<?php

/**
 * HTML class for a file upload field
 *
 * PHP versions 4 and 5
 *
 * LICENSE: This source file is subject to version 3.01 of the PHP license
 * that is available through the world-wide-web at the following URI:
 * http://www.php.net/license/3_01.txt If you did not receive a copy of
 * the PHP License and are unable to obtain it through the web, please
 * send a note to license@php.net so we can mail you a copy immediately.
 *
 * @category    HTML
 * @package     HTML_QuickForm
 * @author      Adam Daniel <adaniel1@eesus.jnj.com>
 * @author      Bertrand Mansion <bmansion@mamasam.com>
 * @author      Alexey Borzov <avb@php.net>
 * @copyright   2001-2009 The PHP Group
 * @license     http://www.php.net/license/3_01.txt PHP License 3.01
 * @version     CVS: $Id: file.php,v 1.25 2009/04/04 21:34:02 avb Exp $
 * @link        http://pear.php.net/package/HTML_QuickForm
 */

/**
 * HTML class for a file upload field
 *
 * @category    HTML
 * @package     HTML_QuickForm
 * @author      Adam Daniel <adaniel1@eesus.jnj.com>
 * @author      Bertrand Mansion <bmansion@mamasam.com>
 * @author      Alexey Borzov <avb@php.net>
 * @version     Release: 3.2.11
 * @since       1.0
 */
class HTML_QuickForm_file extends HTML_QuickForm_input
{
   /**
    * Uploaded file data, from $_FILES
    * @var array
    */
    var $_value = null;

    /**
     * Class constructor
     *
     * @param     string    Input field name attribute
     * @param     string    Input field label
     * @param     mixed     (optional)Either a typical HTML attribute string
     *                      or an associative array
     * @since     1.0
     * @access    public
     */
    public function __construct($elementName=null, $elementLabel=null, $attributes=null)
    {
        parent::__construct($elementName, $elementLabel, $attributes);
        $this->setType('file');
    }

    /**
     * Sets size of file element
     *
     * @param     int    Size of file element
     * @since     1.0
     * @access    public
     */
    function setSize($size)
    {
        $this->updateAttributes(array('size' => $size));
    }

    /**
     * Returns size of file element
     *
     * @since     1.0
     * @access    public
     * @return    int
     */
    function getSize()
    {
        return $this->getAttribute('size');
    }

    /**
     * Freeze the element so that only its value is returned
     *
     * @access    public
     * @return    bool
     */
    function freeze()
    {
        return false;
    }

    /**
     * Sets value for file element.
     *
     * Actually this does nothing. The function is defined here to override
     * HTML_Quickform_input's behaviour of setting the 'value' attribute. As
     * no sane user-agent uses <input type="file">'s value for anything
     * (because of security implications) we implement file's value as a
     * read-only property with a special meaning.
     *
     * @param     mixed    Value for file element
     * @since     3.0
     * @access    public
     */
    function setValue($value)
    {
        return null;
    }

    /**
     * Returns information about the uploaded file
     *
     * @since     3.0
     * @access    public
     * @return    array
     */
    public function getValue()
    {
        return $this->_value;
    } // end func getValue

    // }}}
    // {{{ onQuickFormEvent()

    /**
     * Called by HTML_QuickForm whenever form event is made on this element
     *
     * @param     string    Name of event
     * @param     mixed     event arguments
     * @param     object    calling object
     * @since     1.0
     * @access    public
     * @return    bool
     */
    public function onQuickFormEvent($event, $arg, &$caller)
    {
        switch ($event) {
            case 'updateValue':
                if ($caller->getAttribute('method') == 'get') {
                    throw new \Exception('Cannot add a file upload field to a GET method form');
                }
                $this->_value = $this->_findValue();
                $caller->updateAttributes(array('enctype' => 'multipart/form-data'));
                $caller->setMaxFileSize();
                break;
            case 'addElement':
                $this->onQuickFormEvent('createElement', $arg, $caller);

                return $this->onQuickFormEvent('updateValue', null, $caller);
                break;
            case 'createElement':
                //$className = get_class($this);
                //$this &= new $className($arg[0], $arg[1], $arg[2]);

                break;
        }
        return true;
    }

    /**
     * Moves an uploaded file into the destination
     *
     * @param    string  Destination directory path
     * @param    string  New file name
     * @access   public
     * @return   bool    Whether the file was moved successfully
     */
    public function moveUploadedFile($dest, $fileName = '')
    {
        if ($dest != ''  && substr($dest, -1) != '/') {
            $dest .= '/';
        }
        $fileName = ($fileName != '') ? $fileName : basename($this->_value['name']);
        return move_uploaded_file($this->_value['tmp_name'], $dest . $fileName);
    }

    /**
     * Checks if the element contains an uploaded file
     *
     * @access    public
     * @return    bool      true if file has been uploaded, false otherwise
     */
    public function isUploadedFile()
    {
        return self::_ruleIsUploadedFile($this->_value);
    }

    /**
     * Checks if the given element contains an uploaded file
     *
     * @param     array     Uploaded file info (from $_FILES)
     * @access    private
     * @return    bool      true if file has been uploaded, false otherwise
     */
    public static function _ruleIsUploadedFile($elementValue)
    {
        if ((isset($elementValue['error']) && $elementValue['error'] == 0) ||
            (!empty($elementValue['tmp_name']) && $elementValue['tmp_name'] != 'none')) {
            return is_uploaded_file($elementValue['tmp_name']);
        } else {
            return false;
        }
    }


   /**
    * Tries to find the element value from the values array
    *
    * Needs to be redefined here as $_FILES is populated differently from
    * other arrays when element name is of the form foo[bar]
    *
    * @access    public
    * @return    mixed
    */
    public function _findValue(&$values = null)
    {
        if (empty($_FILES)) {
            return null;
        }
        $elementName = $this->getName();
        if (isset($_FILES[$elementName])) {
            return $_FILES[$elementName];
        } elseif (false !== ($pos = strpos($elementName, '['))) {
            $base  = str_replace(
                        array('\\', '\''), array('\\\\', '\\\''),
                        substr($elementName, 0, $pos)
                    );
            $idx   = "['" . str_replace(
                        array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
                        substr($elementName, $pos + 1, -1)
                     ) . "']";
            $props = array('name', 'type', 'size', 'tmp_name', 'error');
            $code  = "if (!isset(\$_FILES['{$base}']['name']{$idx})) {\n" .
                     "    return null;\n" .
                     "} else {\n" .
                     "    \$value = array();\n";
            foreach ($props as $prop) {
                $code .= "    \$value['{$prop}'] = \$_FILES['{$base}']['{$prop}']{$idx};\n";
            }
            return eval($code . "    return \$value;\n}\n");
        } else {
            return null;
        }
    }

    /**
     * @return string
     */
    public function getElementJS($param)
    {
        $id = $this->getAttribute('id');
        $ratio = 'aspectRatio: 16 / 9';
        if (!empty($param['ratio'])) {
            $ratio = 'aspectRatio: '.$param['ratio'].',';
        }
        $scalable = 'false';
        if (!empty($param['scalable']) && $param['scalable'] != 'false') {
            $ratio = '';
            $scalable = $param['scalable'];
        }

        return '<script>
        $(function() {
            var $inputFile = $(\'#'.$id.'\'),
                $image = $(\'#'.$id.'_preview_image\'),
                $input = $(\'[name="'.$id.'_crop_result"]\'),
                $cropButton = $(\'#'.$id.'_crop_button\'),
                $formGroup = $(\'#'.$id.'-form-group\');

            function isValidType(file) {
                var fileTypes = [\'image/jpg\', \'image/jpeg\', \'image/gif\', \'image/png\'];
        
                for(var i = 0; i < fileTypes.length; i++) {
                    if(file.type === fileTypes[i]) {
                        return true;
                    }
                }

                return false;
            }
            
            function imageCropper() {
                $formGroup.show();
                $cropButton.show();

                $image
                    .cropper(\'destroy\')
                    .cropper({
                        '.$ratio.'
                        responsive : true,
                        center : false,
                        guides : false,
                        movable: false,
                        zoomable: false,
                        rotatable: false,
                        scalable: '.$scalable.',
                        crop: function(e) {
                            // Output the result data for cropping image.
                            $input.val(e.x + \',\' + e.y + \',\' + e.width + \',\' + e.height);
                        }
                    });
            }

            $inputFile.on(\'change\', function () {
                var inputFile = this,
                    file = inputFile.files[0],
                    fileReader = new FileReader();

                if (!isValidType(file)) {
                    $formGroup.hide();
                    $cropButton.hide();

                    if (inputFile.setCustomValidity) {
                        inputFile.setCustomValidity(
                            inputFile.title ? inputFile.title : \''.get_lang('OnlyImagesAllowed').'\'
                        );
                    }

                    return;
                }

                if (inputFile.setCustomValidity) {
                    inputFile.setCustomValidity(\'\');
                }

                fileReader.readAsDataURL(file);
                fileReader.onload = function () {
                    $image
                        .attr(\'src\', this.result)
                        .on(\'load\', imageCropper);
                };
            });

            $cropButton.on(\'click\', function () {
                var canvas = $image.cropper(\'getCroppedCanvas\'),
                    dataUrl = canvas.toDataURL();

                $image.attr(\'src\', dataUrl).cropper(\'destroy\').off(\'load\', imageCropper);
                $(\'[name="'.$id.'_crop_image_base_64"]\').val(dataUrl);
                $cropButton.hide();
            });
        });
        </script>';
    }

    /**
     * @return string
     */
    public function toHtml()
    {
        $js = '';
        if (isset($this->_attributes['crop_image'])) {
            $ratio = '16 / 9';
            if (!empty($this->_attributes['crop_ratio'])) {
                $ratio = $this->_attributes['crop_ratio'];
            }
            $scalable = 'false';
            if (!empty($this->_attributes['crop_scalable'])) {
                $scalable = $this->_attributes['crop_scalable'];
            }
            $js = $this->getElementJS(array('ratio' => $ratio, 'scalable' => $scalable));
        }

        if ($this->isFrozen()) {
            return $this->getFrozenHtml();
        } else {
            $class = '';
            if (isset($this->_attributes['custom']) && $this->_attributes['custom']) {
                $class = 'input-file';
        }

        return $js.$this->_getTabs().
                '<input class="'.$class.'" '.$this->_getAttrString($this->_attributes).' />';
        }
    }

    /**
     * @param string $layout
     *
     * @return string
     */
    public function getTemplate($layout)
    {
        $name = $this->getName();
        $attributes = $this->getAttributes();
        $size = $this->calculateSize();

        switch ($layout) {
            case FormValidator::LAYOUT_INLINE:
                return '
                <div class="form-group {error_class}">
                    <label {label-for} >
                        <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
                        {label}
                    </label>
                    {element}
                </div>';
                break;
            case FormValidator::LAYOUT_HORIZONTAL:
                if (isset($attributes['custom']) && $attributes['custom']) {
                    $template = '
                        <div class="input-file-container">  
                            {element}
                            <label tabindex="0" {label-for} class="input-file-trigger">
                                <i class="fa fa-picture-o fa-lg" aria-hidden="true"></i> {label}
                            </label>
                        </div>
                        <p class="file-return"></p>                        
                        <script>
                            document.querySelector("html").classList.add(\'js\');
                            var fileInput  = document.querySelector( ".input-file" ),  
                                button     = document.querySelector( ".input-file-trigger" ),
                                the_return = document.querySelector(".file-return");
                                  
                            button.addEventListener("keydown", function(event) {  
                                if ( event.keyCode == 13 || event.keyCode == 32 ) {  
                                    fileInput.focus();  
                                }  
                            });
                            button.addEventListener("click", function(event) {
                               fileInput.focus();
                               return false;
                            });  
                            fileInput.addEventListener("change", function(event) {
                                fileName = this.value;
                                if (this.files[0]) {
                                    fileName = this.files[0].name;
                                }
                                the_return.innerHTML = fileName;  
                            });                            
                        </script>
                    ';
                } else {
                    $template = '
                    <div id="file_'.$name.'" class="form-group {error_class}">
                        
                        <label {label-for} class="col-sm-'.$size[0].' control-label" >
                            <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
                            {label}
                        </label>
                         <div class="col-sm-'.$size[1].'">
                            {icon}
                            {element}
                            <!-- BEGIN label_2 -->
                                <p class="help-block">{label_2}</p>
                            <!-- END label_2 -->
                            <!-- BEGIN error -->
                                <span class="help-inline help-block">{error}</span>
                            <!-- END error -->
                        </div>
                        <div class="col-sm-'.$size[2].'">
                            <!-- BEGIN label_3 -->
                                {label_3}
                            <!-- END label_3 -->
                        </div>
                    </div>';
                }
                return $template;
                break;
            case FormValidator::LAYOUT_BOX_NO_LABEL:
                return '
                        <label {label-for}>{label}</label>
                        <div class="input-group">
                            
                            {icon}
                            {element}
                        </div>';
                break;
        }
    }

}