<?php

if (!defined('BASEPATH')) {
    exit('No direct script access allowed');
}

class Rtgc_upload_file extends \Abstract_rtgc_callback
{

    protected $config = [
        'crud'                  => '',
        'field'                 => '',
        'upload_path'           => './assets/uploads/multimedia/files',
        'allowed_types'         => '*',
        'max_size'              => '0',
        // Config js template
        'js_template'           => '$(function(){'
        . '$(".file_box button.choose").click(function(){'
        . 'var el = $(this);'
        . 'var hidden = el.parents(".file_box").find("input[type=hidden]");'
        . 'hidden.val(hidden.val().replace("||Clear_File||",""));'
        . 'el.parents(".file_box").find(".file-upload").click();'
        . '});'
        . '$(".file_box button.delete").click(function(){'
        . 'var el = $(this);'
        . 'el.hide();'
        . 'el.parents(".file_box").find("input[type=file]").val("");'
        . 'el.parents(".file_box").find(".file-name").html("[[text_chosen]]");'
        . 'var hidden = el.parents(".file_box").find("input[type=hidden]");'
        . 'hidden.val(hidden.val()+"||Clear_File||");'
        . '});'
        . '$(".file_box .file-upload").change(function() {'
        . 'var el = $(this),'
        . 'fileName,'
        . '$block = el.next(".block");'
        . 'el.parents(".file_box").find(".delete").show();'
        . 'if (el.val().lastIndexOf("\\\\")) {'
        . ' var i = el.val().lastIndexOf("\\\\") + 1;'
        . '} else {'
        . 'var i = el.val().lastIndexOf("/") + 1;'
        . '}'
        . 'fileName = el.val().slice(i);'
        . 'el.parents(".file_box").find(".file-name").html(fileName);'
        . '});'
        . '});',
        'encrypt_name'          => true,
        'callback_after_upload' => [],
        // Config view template
        'template_field'        =>
        '<div class="file_box">'
        . ' <div class="row">'
        . '   <div class="input-group">'
        . '    <div class="file_controls">'
        . '      <div class="file-name" style="display: inline; margin-left: 20px;">{file_link}</div>'
        . '      <button class="btn btn-default choose" type="button">{text_chosen_btn}</button>'
        . '      <button style="display:{show_clear};" class="btn btn-danger delete" type="button">{text_clear_btn}</button>'
        . '    </div>'
        . '    <div style="margin: 0 20px;">'
        . '    {accept_ext}'
        . '    </div>'
        . '  </div>'
        . '</div>'
        . '<div class="file_upload" style="display:none">'
        . '<input type="file" class="file-upload" name="{name}" accept="{accept_mimes}" /><br />'
        . '<input type="hidden" name="{name}" value="{value}" />'
        . '</div>'
        . '</div>',
    ];
    protected $ci = null;
    protected $value = '';
    protected $errors = '';

    public function __construct($config = [])
    {
        if (!empty($config)) {
            $this->merge_config($config);
        }
        $this->ci = & get_instance();

        // Set max file size
        if (empty($this->config['max_size'])) {
            $this->config['max_size'] = $this->file_upload_max_size();
        }
        if (empty($this->config['crud'])) {
            show_error('Please, set CRUD library');
        }
        if (empty($this->config['field'])) {
            show_error('Please, set `field` key');
        }

        if ($this->config['crud']->is_grid()) {
            $this->config['crud']->before_action('delete', [$this, 'callback_before_delete']);
        } else {
            $this->config['crud']->callback_before_edit([$this, 'callback_before_edit']);
        }
    }

    public function get_config()
    {
        return $this->config;
    }

    public function set_config($config = [])
    {
        $this->config = $config;

        return $this;
    }

    public function get_errors()
    {
        return $this->errors;
    }

    public function merge_config($config = [])
    {
        $this->config = array_merge($this->get_config(), $config);

        return $this;
    }

    public function column($value = '', $data = [])
    {
        return '<a href="' . ltrim(rtrim($this->config['upload_path'], '/'), '.') . '/' . $value . '" target="_blank">' . $value . '</a>';
    }

    public function field($name = 'userfile', $value = '')
    {
        if (!empty($value)) {
            $this->value = $value;
        }

        $accept = '';
        if (!empty($this->config['allowed_types']) && $this->config['allowed_types'] != '*' && is_string($this->config['allowed_types'])) {
            $mimes = & get_mimes();
            foreach (explode('|', $this->config['allowed_types']) as $item) {
                if (isset($mimes[$item])) {
                    $accept .= ', ' . (is_array($mimes[$item]) ? implode(',', $mimes[$item]) : $mimes[$item]);
                }
            }
            $accept = trim($accept, ', ');
        }

        $html = $this->ci->parser->parse_string($this->config['template_field'] . $this->get_errors(), [
            'name'            => $name,
            'show_clear'      => !empty($this->value) ? 'inline' : 'none',
            'value'           => $this->value,
            'accept_mimes'    => $accept ?: '*',
            'text_chosen_btn' => $this->ci->lang->line('Choose file'),
            'text_clear_btn'  => $this->ci->lang->line('Clear'),
            'accept_ext'      => $accept ? '*.' . str_replace('|', ', *.', (string) $this->config['allowed_types']) : '',
            'file_link'       => empty($this->value) ? $this->ci->lang->line('No file chosen') : '<a href="' . ltrim(rtrim($this->config['upload_path'], '/'), '.') . '/' . $value . '" target="_blank">' . $this->value . '</a>'
                ], TRUE);

        $this->ci->js_css->add_js_string(str_replace('[[text_chosen]]', $this->ci->lang->line('No file chosen'), $this->config['js_template']));
        // Clear
        $this->value = '';

        return $html;
    }

    public function do_upload($name = 'userfile')
    {

        if (strpos($this->ci->input->post($name), '||Clear_File||') !== false) {
            $this->remove_file(str_replace('||Clear_File||', '', $this->ci->input->post($name)));
            $_POST[$name] = null;
            $_FILES[$name]['name'] = null;
        }

        if (empty($_FILES[$name]['name'])) {

            return true;
        }

        // Remove old file
        $this->remove_file($this->ci->input->post($name));

        $this->ci->load->library('upload');
        $this->ci->upload->initialize($this->config);

        if (!$this->ci->upload->do_upload($name)) {
            $this->errors = $this->ci->upload->display_errors('<span class="alert-error">', '</span>');

            return false;
        } else {
            $data = $this->ci->upload->data();
            $this->value = $data['file_name'];

            // Callback
            $callback = $this->config['callback_after_upload'];
            if (is_callable($callback)) {
                call_user_func($callback, $this->value);
            }

            $_POST[$name] = $this->value;

            return true;
        }
    }

    public function remove_file($file = '')
    {
        if (!empty($file)) {
            $tmp = explode(DIRECTORY_SEPARATOR, $file);
            $basename = array_pop($tmp);
            $old_file = $this->config['upload_path'] . '/' . $basename;
            if (file_exists($old_file) && !is_dir($old_file)) {
                unlink($old_file);
            }
        }

        return $this;
    }

    public function callback_before_delete($ids = [])
    {
        if (strpos($this->config['field'], 'translate_') !== false) {
            $field = str_replace('translate_', '', $this->config['field']);
            $table = $this->config['crud']->get_table();
            $pkey = 'id_' . $table;
            $table = $table . '_translate';
        } else {
            $field = $this->config['field'];
            $table = $this->config['crud']->get_table();
            $pkey = 'id_' . $table;
        }
        $q = $this->ci->db->
                        select($field)->
                        where_in($pkey, $ids)->
                        get($table)->result_array();
        foreach ($q as $item) {
            $this->remove_file($item[$field]);
        }

        return true;
    }

    public function callback_before_edit($post)
    {
        $field_alias = $this->config['crud']->_field_alias($this->config['field']);
        if (is_array($this->ci->input->post($field_alias))) {
            $old_post = $this->ci->input->post($field_alias);
            $data = [];
            $lang_file = [];
            foreach ($_FILES[$field_alias] as $k => $item) {
                foreach ($item as $kk => $el) {
                    $data[$kk][$field_alias][$k] = $el;
                }
            }
            unset($_FILES[$field_alias]);
            foreach ($data as $k => $file) {
                $_POST[$field_alias] = $old_post[$k];
                $_FILES = $file;
                if ($this->do_upload($field_alias)) {
                    $lang_file[$k] = $this->ci->input->post($field_alias);
                }
            }
            $_POST[$field_alias] = $lang_file;
        } else {
            if ($this->do_upload($field_alias)) {
                $post[$this->config['field']] = $this->ci->input->post($field_alias);
            } else {
                $post[$this->config['field']] = '';
                unset($_POST[$field_alias]);
            }
        }

        return $post;
    }

    protected function file_upload_max_size()
    {
        static $max_size = -1;

        if ($max_size < 0) {
            // Start with post_max_size.
            $max_size = $this->parse_size(ini_get('post_max_size'));

            // If upload_max_size is less, then reduce. Except if upload_max_size is
            // zero, which indicates no limit.
            $upload_max = $this->parse_size(ini_get('upload_max_filesize'));
            if ($upload_max > 0 && $upload_max < $max_size) {
                $max_size = $upload_max;
            }
        }
        return $max_size;
    }

    protected function parse_size($size)
    {
        $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
        $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
        if ($unit) {
            // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
            return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
        } else {
            return round($size);
        }
    }

}
