<?php
/**
 * 2007-2022 ETS-Soft
 *
 * NOTICE OF LICENSE
 *
 * This file is not open source! Each license that you purchased is only available for 1 wesite only.
 * If you want to use this file on more websites (or projects), you need to purchase additional licenses.
 * You are not allowed to redistribute, resell, lease, license, sub-license or offer our resources to any third party.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please contact us for extra customization service at an affordable price
 *
 * @author ETS-Soft <etssoft.jsc@gmail.com>
 * @copyright  2007-2022 ETS-Soft
 * @license    Valid for 1 website (or project) for each purchase of license
 *  International Registered Trademark & Property of ETS-Soft
 */

if (!defined('_PS_VERSION_')) {
    exit;
}
require_once dirname(__FILE__) . '/classes/HDTranslate.php';
require_once dirname(__FILE__) . '/classes/HDHelperList.php';
require_once dirname(__FILE__) . '/classes/HDTools.php';
require_once dirname(__FILE__) . '/classes/HDLink.php';
require_once dirname(__FILE__) . '/classes/HDValidate.php';
require_once dirname(__FILE__) . '/classes/HDDefines.php';
require_once dirname(__FILE__) . '/classes/HDDataProvider.php';
require_once dirname(__FILE__) . '/classes/HDDepartment.php';
require_once dirname(__FILE__) . '/classes/HDTicket.php';
require_once dirname(__FILE__) . '/classes/HDOption.php';
require_once dirname(__FILE__) . '/classes/HDColumn.php';
require_once dirname(__FILE__) . '/classes/HDTicketMessage.php';
require_once dirname(__FILE__) . '/classes/HDStaff.php';
require_once dirname(__FILE__) . '/classes/HDCustomer.php';
require_once dirname(__FILE__) . '/classes/HDPostProcess.php';
require_once dirname(__FILE__) . '/classes/Ets_hd_mailqueue.php';
require_once dirname(__FILE__) . '/classes/Ets_hd_mailtracking.php';
require_once dirname(__FILE__) . '/classes/Ets_hd_maillog.php';
require_once(dirname(__FILE__) . '/classes/Ets_hd_paggination_class.php');
class Ets_helpdesk extends Module
{
    public $ps17;
    const _ADMIN_TAB_PREFIX_ = 'AdminEtsHD';
    public $_warnings = array();
    public function __construct()
    {
        $this->name = 'ets_helpdesk';
        $this->tab = 'front_office_features';
        $this->version = '1.0.1';
        $this->author = 'ETS-Soft';
        $this->need_instance = 0;
        $this->bootstrap = true;

        parent::__construct();
        $this->displayName = $this->l('Help desk');
        $this->description = $this->l('Helpdesk');
        $this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
        $this->ps17 = version_compare(_PS_VERSION_, '1.7.0.0', '>=') ? 1 : 0;
    }

    // Install & Uninstall:
    public function registerHooks($unregister = false)
    {
        $hooks = array(
            'displayHeader',
            'displayBackOfficeHeader',
            'displayMyAccountBlock',
            'displayCustomerAccount',
            'moduleRoutes',
            'displayFooter',
            'actionObjectLanguageAddAfter',
            'displayRightColumnProduct',
            'displayProductAdditionalInfo',
            'displayCustomEtsHelpdesk',
        );
        foreach ($hooks as $hook) {
            if ($unregister && !$this->unregisterHook($hook) || !$unregister && !$this->registerHook($hook))
                return false;
        }
        return true;
    }

    public function install()
    {
        require dirname(__FILE__) . '/sql/install.php';
        HDStaff::initialized();

        return parent::install()
            && $this->registerHooks()
            && $this->installQuickTabs()
            && $this->_installConfigs()
            && $this->_installMail()
            && $this->_installFieldDefault();
    }

    public function uninstall()
    {
        require dirname(__FILE__) . '/sql/uninstall.php';
        /*Clean files in directory:*/
        $dirs = array(
            _PS_IMG_DIR_ . $this->name . '/',
            _PS_DOWNLOAD_DIR_ . $this->name . '/'
        );
        foreach ($dirs as $dir) {
            HDTools::recursiveUnlink($dir);
        }
        return parent::uninstall()
            && $this->registerHooks(true)
            && $this->uninstallQuickTabs()
            && $this->_uninstallConfigs();
    }

    public function installQuickTabs()
    {
        $parent = [
            'origin' => 'Help desk',
            'label' => $this->l('Help desk'),
        ];
        $id_parent = $this->addQuickTab(
            0,
            '',
            $parent['origin']
        );
        if ($id_parent > 0
            && ($quick_tabs = HDDefines::getInstance()->getQuickTabs())
            && is_array($quick_tabs)
            && count($quick_tabs) > 0
        ) {
            foreach ($quick_tabs as $t) {
                // Menus:
                if (isset($t['class']) && isset($t['label']) && !($parent_id = $this->addQuickTab($id_parent, $t['class'], $t['origin'], !isset($t['active']) || $t['active'] ? 1 : 0)))
                    return false;
                // Submenus:
                if (isset($t['sub'])
                    && is_array($t['sub'])
                    && count($t['sub']) > 0
                    && $parent_id > 0
                ) {
                    foreach ($t['sub'] as $st) {
                        if (isset($st['class']) && isset($st['label']) && !$this->addQuickTab($parent_id, $st['class'], $st['origin'], !isset($st['active']) || $st['active'] ? 1 : 0))
                            return false;
                    }
                }
            }
        }

        return true;
    }

    public function uninstallQuickTabs()
    {
        if ($this->removeQuickTab()
            && ($quick_tabs = HDDefines::getInstance()->getQuickTabs())
            && is_array($quick_tabs)
            && count($quick_tabs) > 0
        ) {
            foreach ($quick_tabs as $t) {
                if (isset($t['class']) && !$this->removeQuickTab($t['class']))
                    return false;
                // Remove sub:
                if (isset($t['sub'])
                    && $t['sub']
                    && is_array($t['sub'])
                    && count($t['sub']) > 0
                ) {
                    foreach ($t['sub'] as $st) {
                        if (isset($st['class']) && !$this->removeQuickTab($st['class']))
                            return false;
                    }
                }
            }
        }

        return true;
    }

    private function addQuickTab($id_parent, $class = '', $label = '', $active = 1)
    {
        if ($id_parent && !$class)
            return 0;

        $class_name = trim(self::_ADMIN_TAB_PREFIX_ . $class);
        $id = (int)Tab::getIdFromClassName($class_name);
        if ($id) {
            return 0;
        }
        $t = new Tab((int)$id);
        $t->active = $active;
        $t->class_name = $class_name;
        $t->name = array();
        if ($languages = Language::getLanguages(false)) {
            foreach ($languages as $l) {
                $t->name[$l['id_lang']] = HDTranslate::trans($label, (int)$l['id_lang']) ?: $label;
            }
        }
        $t->id_parent = (int)$id_parent;
        $t->module = $this->name;

        return $t->save() ? $t->id : 0;
    }

    private function removeQuickTab($class_name = '')
    {
        $id = (int)Tab::getIdFromClassName(self::_ADMIN_TAB_PREFIX_ . $class_name);
        if (!$id) {
            return true;
        }
        $tab = new Tab($id);
        return $tab->id ? $tab->delete() : true;
    }

    public function _installConfigs()
    {
        $configs = HDDefines::getInstance()->getAllConfigs();

        if (is_array($configs)
            && count($configs) > 0
        ) {
            $languages = Language::getLanguages(false);
            foreach ($configs as $key => $config) {

                $global = isset($config['global']) && $config['global'] ? 1 : 0;

                if (isset($config['lang']) && $config['lang']) {
                    $values = array();
                    if (is_array($languages)
                        && count($languages) > 0
                    ) {
                        foreach ($languages as $l) {
                            if (isset($config['default']) && is_array($config['default'])) {
                                $values[$l['id_lang']] = isset($config['default']['origin']) ? HDDefines::trans($config['default']['origin'], trim($l['iso_code'])) : '';
                            } else
                                $values[$l['id_lang']] = (isset($config['default']) ? $config['default'] : '');
                        }
                    }
                    $this->configUpdateValue($key, $global, $values, true);
                } else {
                    $this->configUpdateValue($key, $global, isset($config['default']) ? $config['default'] : '', true);
                }
            }
        }

        return true;
    }

    public function configUpdateValue($key, $global, $values, $html = false)
    {
        return $global ? Configuration::updateGlobalValue($key, $values, $html) : Configuration::updateValue($key, $values, $html);
    }

    public function _uninstallConfigs()
    {
        $configs = HDDefines::getInstance()->getAllConfigs();
        if (is_array($configs)
            && count($configs) > 0
        ) {
            foreach (array_keys($configs) as $key) {
                if (!Configuration::deleteByName($key)) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * @param Language $language
     * @return bool
     */
    public function _installMail($language = null)
    {
        if ($language instanceof Language
            && $language->id > 0
        ) {
            HDTools::recurseCopy(dirname(__FILE__) . '/mails/en', dirname(__FILE__) . '/mails/' . $language->iso_code);
        } elseif (
            ($languages = Language::getLanguages(false))
            && count($languages) > 0
        ) {
            foreach ($languages as $l) {
                $local_path_email = dirname(__FILE__) . '/mails/';
                if (isset($l['iso_code'])
                    && trim($l['iso_code']) !== 'en'
                    && (!file_exists($local_path_email . $l['iso_code']) || !glob($local_path_email . $l['iso_code'] . '/*.(txt|html)'))
                ) {
                    HDTools::recurseCopy($local_path_email . 'en', $local_path_email . $l['iso_code']);
                }
            }
        }
        return true;
    }

    // Hooks:
    public function getContent()
    {
        Tools::redirectAdmin($this->context->link->getAdminLink('AdminEtsHDDashboard'));
    }

    public function hookActionObjectLanguageAddAfter($params)
    {
        if (isset($params['object']) && Validate::isLoadedObject($params['object'])) {
            $this->_installMail($params['object']);
        }
    }

    public function hookDisplayBackOfficeHeader()
    {
        if (!$this->ps17) {
            $this->context->controller->addJquery();
        }
        $this->context->controller->addCSS($this->_path . 'views/css/admin_all.css');
        $this->context->controller->addJS($this->_path . 'views/js/helpdesk.all.js');
        $this->smarty->assign(array(
            'ETS_HD_PROCESS_LINK' => $this->context->link->getAdminLink(self::_ADMIN_TAB_PREFIX_ . 'Process'),
        ));

        if ($this->context->controller instanceof AdminEtsHDBaseController) {
            $this->smarty->assign(array(
                'PS_ALLOW_ACCENTED_CHARS_URL' => Configuration::get('PS_ALLOW_ACCENTED_CHARS_URL'),
                'ETS_HD_CURRENT_LINK' => $this->context->link->getAdminLink($this->context->controller->controller_name),
            ));
        }
        return $this->initHeader();
    }

    public function initHeader()
    {
        if ($this->context->controller instanceof AdminEtsHDTicketsController ||
            $this->context->controller instanceof Ets_helpdeskBaseModuleFrontController
        ) {
            $this->context->controller->addJS($this->_path . 'views/js/select2.min.js');
            $configs = $this->getConfigsTicket();

            $captcha_enabled = !$this->isStaff()
            && isset($this->context->customer) && $this->context->customer->id > 0 && $this->context->customer->isLogged()
            && isset($configs['ETS_HD_ALLOW_CAPTCHA']) && $configs['ETS_HD_ALLOW_CAPTCHA'] > 0
            && (!isset($configs['ETS_HD_CUSTOMER_NO_CAPTCHA']) || !$configs['ETS_HD_CUSTOMER_NO_CAPTCHA']) ? 1 : 0;

            if ($captcha_enabled) {
                $this->context->controller->addJS($this->_path . 'views/js/helpdesk.captcha.js');
            }
            $this->smarty->assign(array(
                'language_code' => $this->context->language->iso_code,
                'configs' => HDDefines::getInstance()->getConfigs(),
                'configs_ticket' => $configs,
                'captcha_enabled' => $captcha_enabled,
            ));
        }
        $this->smarty->assign(array(
            'post_max_size' => HDTools::getPostMaxSizeBytes(),
            'allow_ext_files' => self::$ext_files,
            'allow_ext_image_files' => self::$ext_image_files,
            'is_back_office' => $this->isBackOffice(),
        ));
        $controller = Tools::getValue('controller');
        if($controller=='AdminCustomers' || $controller=='AdminOrders' || $controller=='AdminPhMdLicense')
        {   
            $this->context->controller->addJS($this->_path . 'views/js/helpdesk.link_create.js');
            if($controller=='AdminCustomers')
            {
                $request = $this->getRequestContainer();
                $idCustomer = null;
                if($request){
                    $idCustomer = $request->get('customerId');
                }
                else{
                    $idCustomer = (int)Tools::getValue('id_customer');
                }
                if($idCustomer)
                {
                    $this->smarty->assign(
                        array(
                            'ets_hd_link_create_ticket_as_customer'=>$this->context->link->getAdminLink('AdminEtsHDTickets').'&add_ticket=1&id_customer='.$idCustomer,
                        )
                    );
                }
                else
                {
                    
                    $this->smarty->assign(
                        array(
                            'ets_hd_link_create_ticket_as_customer'=>$this->context->link->getAdminLink('AdminEtsHDTickets').'&add_ticket=1',
                        )
                    );
                }
            }
            if($controller=='AdminOrders')
            {
                $request = $this->getRequestContainer();
                $idOrder = null;
                if($request){
                    $idOrder = $request->get('orderId');
                }
                else{
                    $idOrder = (int)Tools::getValue('id_order');
                }
                if($idOrder)
                {
                   $order = new Order($idOrder);
                   $this->smarty->assign(
                        array(
                            'ets_hd_link_create_ticket_as_customer'=>$this->context->link->getAdminLink('AdminEtsHDTickets').'&add_ticket=1&id_customer='.$order->id_customer,
                        )
                    );
                }
            }
        }
        return $this->display(__FILE__, 'bo-fo-head.tpl');
    }
    public function getSfContainer()
    {
        if(!class_exists('\PrestaShop\PrestaShop\Adapter\SymfonyContainer'))
        {
            $kernel = null;
            try{
                $kernel = new AppKernel('prod', false);
                $kernel->boot();
                return $kernel->getContainer();
            }
            catch (Exception $ex){
                return null;
            }
        }
        $sfContainer = call_user_func(array('\PrestaShop\PrestaShop\Adapter\SymfonyContainer', 'getInstance'));
        return $sfContainer;
    }
    public function getRequestContainer()
    {
        if ($this->is17)
        {
            if($sfContainer = $this->getSfContainer())
            {
                return $sfContainer->get('request_stack')->getCurrentRequest();
            }
        }
        return null;
    }
    public function hookDisplayHeader()
    {
        $this->context->controller->addCSS($this->_path . 'views/css/helpdesk_all.css');
        if ($this->context->controller instanceof Ets_helpdeskBaseModuleFrontController) {
            $this->context->controller->addCSS($this->_path . 'views/css/helpdesk.ticket.css');
            $this->context->controller->addJS(array(
                $this->_path . 'views/js/helpdesk.function.js',
                $this->_path . 'views/js/helpdesk.ticket.js'
            ));
        }
        if ($this->context->controller instanceof HistoryController ||
            $this->context->controller instanceof Ets_helpdeskBaseModuleFrontController
        ) {
            $this->context->smarty->assign(array(
                'ETS_HD_PROCESS_LINK' => HDLink::getInstance()->getProcessLink($this->context->language->id),
            ));
        }
        if ($this->context->controller instanceof Ets_helpdeskBaseModuleFrontController ||
            $this->context->controller instanceof IdentityController ||
            $this->context->controller instanceof OrderDetailController ||
            $this->context->controller instanceof HistoryController ||
            $this->context->controller instanceof MyAccountController
        ) {
            $this->context->controller->addJqueryPlugin('growl');
            $this->context->controller->addJS($this->_path . 'views/js/helpdesk.js');
            $this->context->controller->addCSS($this->_path . 'views/css/helpdesk.css');

            return $this->initHeader();
        }
    }

    public function hookDisplayCustomerAccount()
    {
        return $this->hookDisplayMyAccountBlock();
    }

    public function hookDisplayMyAccountBlock()
    {
        if (!$this->context->customer->isLogged())
            return '';
        $this->smarty->assign(array(
            'ETS_HD_TICKET_ENABLED' => Configuration::get('ETS_HD_TICKET_ENABLED'),
            'tickets_link' => HDLink::getInstance()->getTicketsLink($this->context->language->id),
            'nb_customer_ticket' => (int)HDTicket::getTickets(0, true, 0, 0, null, $this->context, false, array(), 0, array(), null), // array('open')
            'ps17' => $this->ps17,
        ));
        if (HDStaff::isGranted($this->context->customer->id)) {
            $this->smarty->assign(array(
                'staffs_link' => HDLink::getInstance()->getStaffsLink($this->context->language->id),
                'nb_staff_ticket' => (int)HDTicket::getTickets(0, true, 0, 0, null, $this->context, true, array(), 0, array(), null),// array('open')
            ));
        }

        return $this->display(__FILE__, 'fo-block-account.tpl');
    }

    public function getMediaLink($path)
    {
        return $this->isBackOffice() ? $path : $this->context->link->getMediaLink($path);
    }

    public function hookDisplayFooter($params)
    {
        if (isset($this->context->customer->id) && $this->context->customer->id > 0 && $this->context->customer->isLogged()) {
            if ($this->context->controller instanceof IdentityController) {
                $this->smarty->assign(array(
                    'PS_ATTACHMENT_MAXIMUM_SIZE' => HDTools::formatBytes(HDTools::getPostMaxSizeBytes()),
                    'avatar' => HDCustomer::getAvatar($this->context->customer->id),
                    'upload_dir' => $this->getMediaLink(_PS_IMG_ . $this->name . '/avatar/'),
                    'upload_url' => $this->context->link->getModuleLink($this->name, 'upload', ['id_customer' => $this->context->customer->id], Configuration::get('PS_SSL_ENABLED') && Configuration::get('PS_SSL_ENABLED_EVERYWHERE')),
                ));
            }
            if ($this->context->controller instanceof OrderDetailController) {
                $this->smarty->assign(array(
                    'contact_support_team' => $this->contactSupportTeam()
                ));
            }
            return $this->display(__FILE__, 'fo-footer.tpl');
        }
    }

    public function contactSupportTeam()
    {
        $id_order = Tools::getValue('id_order');
        if ($id_order !== ''
            && Validate::isUnsignedInt($id_order)
            && ($order = new Order((int)$id_order))
            && $order->id > 0
        ) {
            $this->smarty->assign(array(
                'ticket_add_link' => HDLink::getInstance()->getTicketsLink($this->context->language->id, array('order_ref' => $order->reference, 'add_ticket' => 1)),
            ));

            return $this->display(__FILE__, 'fo-contact-support-team.tpl');
        }
    }

    public function hookDisplayCustomEtsHelpdesk()
    {
        return $this->hookDisplayRightColumnProduct();
    }

    public function hookDisplayRightColumnProduct()
    {
        if ($this->ps17 || trim(Tools::getValue('controller')) == 'product' && !(int)Tools::getValue('content_only')) {
            return $this->hookDisplayProductAdditionalInfo(['product' => (int)Tools::getValue('id_product')]);
        }
    }

    public function hookDisplayProductAdditionalInfo($params)
    {
        if (isset($params['product'])
            && ($product = $params['product'])
        ) {
            if (is_object($product) && $product instanceof PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductLazyArray) {
                $id_product = $product->getId();
            } elseif (is_object($product) && $product instanceof Product) {
                $id_product = $product->id;
            } elseif (is_array($product) && isset($product['id_product']) && $product['id_product'] > 0) {
                $id_product = (int)$params['id_product'];
            } else
                $id_product = Validate::isUnsignedInt($product) && $product > 0 ? $product : 0;

            $this->smarty->assign(array(
                'link' => HDLink::getInstance()->getAddTicketLink($this->context->language->id, array('id_product' => $id_product)),
            ));

            return $this->display(__FILE__, 'fo-product-button.tpl');
        }
    }

    const _REWRITE_PATTERN_ = '[_a-zA-Z0-9\x{0600}-\x{06FF}\pL\pS-]*?';

    public function hookModuleRoutes()
    {
        $suffix = (int)Configuration::get('ETS_HD_TICKET_URL_SUFFIX') > 0 ? '.html' : '';
        return array(
            'module-ets_helpdesk-tickets' => array(
                'controller' => 'tickets',
                'rule' => 'tickets/{rewrite}' . $suffix,
                'keywords' => [
                    'rewrite' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'rewrite'],
                ],
                'params' => array(
                    'fc' => 'module',
                    'module' => $this->name,
                ),
            ),
            'module-ets_helpdesk-add' => array(
                'controller' => 'add',
                'rule' => 'tickets/{rewrite}/add' . $suffix,
                'keywords' => [
                    'rewrite' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'rewrite'],
                ],
                'params' => array(
                    'fc' => 'module',
                    'module' => $this->name,
                ),
            ),
            'module-ets_helpdesk-ticket' => array(
                'controller' => 'ticket',
                'rule' => 'ticket/{rewrite}-{id_ets_hd_ticket}' . $suffix,
                'keywords' => [
                    'id_ets_hd_ticket' => ['regexp' => '[0-9]+', 'param' => 'id_ets_hd_ticket'],
                    'rewrite' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'rewrite'],
                ],
                'params' => array(
                    'fc' => 'module',
                    'module' => $this->name,
                ),
            ),
            'module-ets_helpdesk-staffs' => array(
                'controller' => 'staffs',
                'rule' => 'staffs/{rewrite}' . $suffix,
                'keywords' => [
                    'rewrite' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'rewrite'],
                ],
                'params' => array(
                    'fc' => 'module',
                    'module' => $this->name,
                ),
            ),
            'module-ets_helpdesk-staff' => array(
                'controller' => 'staff',
                'rule' => 'staff/{rewrite}-{id_ets_hd_ticket}' . $suffix,
                'keywords' => [
                    'id_ets_hd_ticket' => ['regexp' => '[0-9]+', 'param' => 'id_ets_hd_ticket'],
                    'rewrite' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'rewrite'],
                ],
                'params' => array(
                    'fc' => 'module',
                    'module' => $this->name,
                ),
            ),
            'module-ets_helpdesk-download' => array(
                'controller' => 'download',
                'rule' => 'download-attachment-file/{type}/{name}/{file}-{id}' . $suffix,
                'keywords' => [
                    'file' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'file'],
                    'type' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'type'],
                    'name' => ['regexp' => self::_REWRITE_PATTERN_, 'param' => 'name'],
                    'id' => ['regexp' => '[0-9]+', 'param' => 'id'],
                ],
                'params' => array(
                    'fc' => 'module',
                    'module' => $this->name,
                ),
            ),
            'module-ets_helpdesk-process' => array(
                'controller' => 'process',
                'rule' => 'process' . $suffix,
                'keywords' => [
                ],
                'params' => array(
                    'fc' => 'module',
                    'module' => $this->name,
                ),
            ),
        );
    }

    // Front & BackOffice:
    public $ajax = 0;
    public $customer_staff = 0;

    public function init()
    {
        $this->ajax = (int)Tools::getValue('ajax') ? 1 : 0;

        if (!$this->isBackOffice()
            && ($this->context->customer->id <= 0 || !$this->context->customer->isLogged())
            && (!$this->isGuest() || !$this->context->controller instanceof Ets_helpdeskAddModuleFrontController)
        ) {
            Tools::redirect($this->context->link->getPageLink('authentication') . '?back=' . HDLink::getInstance()->getTicketsLink($this->context->language->id));
        }
        if (isset($this->context->customer->id) && $this->context->customer->id > 0 && $this->customer_staff && !HDStaff::isGranted($this->context->customer->id)) {
            Tools::redirect(HDLink::getInstance()->getTicketsLink($this->context->language->id));
        }
    }

    static $cache_message_fields = array();

    public function getMessageFields()
    {
        if (!self::$cache_message_fields) {
            $configs = HDDefines::getInstance()->getMessageFields();
            if ($configs) {
                foreach ($configs as $key => &$config) {
                    if ($config['type'] == 'file') {
                        if ($this->isStaff() && !Configuration::get('ETS_HD_STAFF_UPLOAD_FILE') || !$this->isStaff() && !Configuration::get('ETS_HD_CUSTOMER_REPLY_UPLOAD_FILE')) {
                            unset($configs[$key]);
                        } else {
                            $config['save_file'] = $this->isStaff() && Configuration::get('ETS_HD_SAVE_STAFF_FILE') || !$this->isStaff() && Configuration::get('ETS_HD_SAVE_CUSTOMER_FILE');
                        }
                    }
                }
            }
            $configs[] = array(
                'type'=>'hidden',
                'name'=>'last_date',
            );
            self::$cache_message_fields = $configs;
        }

        return self::$cache_message_fields;
    }

    public function postProcess()
    {
        if(Tools::isSubmit('processLoadTicket'))
        {
            $this->ajaxProcessLoadTicket();
        }
        if(Tools::isSubmit('processSearchTicket'))
        {
            $this->ajaxProcessSearchTicket();
        }
        if(Tools::isSubmit('processLoadMessageTicket') && ($id_ticket=(int)Tools::getValue('id_ticket',Tools::getValue('id_ets_hd_ticket'))))
        {
            $this->processLoadMessageTicket($id_ticket);
        }
        if ((int)Tools::getValue('submitAddTicket')) {
            $configs = $this->getTicketFields();
            $this->validateFields($configs, (int)Tools::getValue('id_ets_hd_ticket'), 0, !$this->isStaff());
            if (!count($this->_errors)) {
                $this->postFormTicket($configs);
            }
            if (count($this->_errors)) {
                $this->context->controller->errors = $this->_errors;
            }
        } elseif ((int)Tools::getValue('submitAddMessage')) {
            $id_ets_hd_ticket = (int)Tools::getValue('id_ets_hd_ticket');
            $ticket = new HDTicket($id_ets_hd_ticket);
            if(Validate::isLoadedObject($ticket))
            {
                $configs = $this->getMessageFields();
                $this->validateFields($configs, (int)Tools::getValue('id_ets_hd_ticket_message'));
                if (!count($this->_errors)) {
                    $this->postFormMessage($configs);
                } else {
                    die(json_encode([
                        'errors' => implode(PHP_EOL, $this->_errors),
                    ]));
                }
            }
            {
                $this->_errors[] = $this->l('Ticket not exists');
                die(json_encode([
                        'errors' => implode(PHP_EOL, $this->_errors),
                        'url_redirect' => $this->context->link->getPageLink('my-account'),
                ]));
            }
        } elseif ((int)Tools::getValue('delete_ticket')) {
            $id_ets_hd_ticket = (int)Tools::getValue('id_ets_hd_ticket');
            if (!$id_ets_hd_ticket || !Validate::isUnsignedInt($id_ets_hd_ticket)) {
                $this->_errors[] = $this->l('Ticket not found');
            } elseif (!$this->isGrantedTicket($id_ets_hd_ticket)) {
                $this->_errors[] = $this->l('Ticket access denied');
            } else {
                $ticket = HDTicket::getInstanceById($id_ets_hd_ticket);
                if (!$ticket->delete()) {
                    $this->_errors[] = $this->l('Unknown error. Delete is fail.');
                }
            }
            if (count($this->_errors)) {
                $this->context->controller->errors = $this->_errors;
            } else
                $this->displayConfirm(1);
        } elseif ($action = trim(Tools::getValue('action'))) {
            $method = ($this->ajax ? 'ajaxProcess' : 'process') . Tools::ucfirst($action);
            if (method_exists($this, $method)) {
                $this->{$method}();
            }
        } elseif (Tools::isSubmit('submitBulkdeleteets_hd_ticket')) {
            $id_ets_hd_tickets = Tools::getValue('ets_hd_ticket_groupBox');
            if (is_array($id_ets_hd_tickets)
                && $id_ets_hd_tickets
                && Validate::isArrayWithIds($id_ets_hd_tickets)
            ) {
                if (!HDTicket::deleteByIds($id_ets_hd_tickets)) {
                    $this->_errors[] = $this->l('Cannot delete item selected!');
                } else
                    $this->displayConfirm(1);
            } else
                $this->_errors[] = $this->l('Please choose item need delete');
        } elseif (Tools::isSubmit('submitBulkclosedets_hd_ticket')) {
            $ids_ets_hd_ticket = Tools::getValue('ets_hd_ticket_groupBox');
            if (is_array($ids_ets_hd_ticket)
                && $ids_ets_hd_ticket
                && Validate::isArrayWithIds($ids_ets_hd_ticket)
            ) {
                foreach ($ids_ets_hd_ticket as $id_ets_hd_ticket) {
                    $ticket = new HDTicket($id_ets_hd_ticket);
                    $ticket->status = 'closed';
                    if ($ticket->update(true)) {
                        $this->ticketMailClosed($ticket);
                    } else {
                        $this->_errors[] = $this->l('Cannot closed item selected!');
                    }
                }
                if (!count($this->_errors)) {
                    $this->displayConfirm(2);
                }
            } else
                $this->_errors[] = $this->l('Please choose item need closed');
        }
        if ($this->ajax) {
            die(json_encode(array('errors' => $this->_errors ? implode(PHP_EOL, $this->_errors) : false)));
        } elseif ($this->_errors)
            $this->context->controller->errors = $this->_errors;
    }

    // ajaxProcess
    
    public function ticketMailClosed($ticket)
    {
        if ($ticket instanceof HDTicket
            && $ticket->id > 0
            && $ticket->id_customer > 0
            && trim($ticket->status) === 'closed'
        ) {
            $customer = new Customer($ticket->id_customer);
            $subject = array(
                'origin' => 'Your ticket #%d has been closed',
                'text' => $this->l('Your ticket #%d has been closed'),
            );
            $templateVars = array(
                '{customer_name}' => $customer->firstname . ' ' . $customer->lastname,
                '{ticket_id}' => $ticket->id,
                '{link_ticket}' => HDLink::getInstance()->getTicketLink($customer->id_lang, array('id_ets_hd_ticket' => $ticket->id)),
            );
            $template = 'to_customer_ticket_closed';
            if ($this->templateExits($customer->id_lang, $template))
            {
                if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                {
                    Ets_hd_mailqueue::addMailQueue($customer->id_lang,
                    $customer->id,
                    0,
                    $customer->firstname.' '.$customer->lastname,
                    Configuration::get('ETS_HD_SEND_FROM_EMAIL'),
                    Configuration::get('ETS_HD_SEND_FROM_NAME'),
                    $template,
                    sprintf(HDTranslate::trans($subject['origin'], $customer->id_lang), $ticket->id),
                    $customer->email,
                    $templateVars,
                    null
                    );
                }
                elseif(!Mail::send(
                    $customer->id_lang
                    , $template
                    , sprintf(HDTranslate::trans($subject['origin'], $customer->id_lang), $ticket->id)
                    , $templateVars
                    , $customer->email
                    , $customer->firstname . ' ' . $customer->lastname
                    , Configuration::get('ETS_HD_SEND_FROM_EMAIL')
                    , Configuration::get('ETS_HD_SEND_FROM_NAME')
                    , null
                    , null
                    , dirname(__FILE__) . '/mails/'
                ))
                 $this->_errors[] = sprintf($this->l('Sendmail %s is fail.'), $customer->email);   
            }
        }
    }

    public function ajaxProcessStatusTicket()
    {
        $id_ets_hd_ticket = trim(Tools::getValue('id_ets_hd_ticket')) !== '' && Validate::isUnsignedInt(Tools::getValue('id_ets_hd_ticket')) ? Tools::getValue('id_ets_hd_ticket') : 0;
        $json_array = array();
        if ($id_ets_hd_ticket <= 0 || !($ticket = HDTicket::getInstanceById($id_ets_hd_ticket))) {
            $this->_errors[] = $this->l('Ticket is not found.');
        } elseif ($this->isGrantedTicket($id_ets_hd_ticket)) {
            if (trim(($status = trim(Tools::getValue('status')))) === '' || !Validate::isCleanHtml($status) || !($json_array['status'] = HDDefines::getInstance()->getOptionStatus($status))) {
                $this->_errors[] = $this->l('Status is invalid.');
            }
            if (!count($this->_errors)) {
                $ticket->status = $status;
                if (!$ticket->save(true)) {
                    $this->_errors[] = $this->l('Cannot change status.');
                } else {
                    $this->ticketMailClosed($ticket);
                }
            }
        }
        $has_error = count($this->_errors) ? 1 : 0;
        $json_array['errors'] = $has_error ? implode(PHP_EOL, $this->_errors) : false;
        $json_array['msg'] = !$has_error ? $this->l('Update successfully.') : false;

        die(json_encode($json_array));
    }

    public function ajaxProcessPriorityTicket()
    {
        $id_ets_hd_ticket = trim(Tools::getValue('id_ets_hd_ticket')) !== '' && Validate::isUnsignedInt(Tools::getValue('id_ets_hd_ticket')) ? Tools::getValue('id_ets_hd_ticket') : 0;
        if ($id_ets_hd_ticket <= 0 || !($ticket = HDTicket::getInstanceById($id_ets_hd_ticket))) {
            $this->_errors[] = $this->l('Ticket is not found.');
        } elseif ($this->isGrantedTicket($id_ets_hd_ticket)) {
            if (($priority = trim(Tools::getValue('priority'))) == '' || !Validate::isCleanHtml($priority) || !HDDefines::getInstance()->getOptionPriority($priority)) {
                $this->_errors[] = $this->l('Priority is invalid.');
            }
            if (!$this->_errors) {
                $ticket->priority = $priority;
                if (!$ticket->save(true)) {
                    $this->_errors[] = $this->l('Cannot change priority.');
                }
            }
        }
        $has_error = count($this->_errors) ? 1 : 0;
        die(json_encode([
            'errors' => $has_error ? implode(PHP_EOL, $this->_errors) : false,
            'msg' => !$has_error ? $this->l('Update successfully.') : false,
        ]));
    }

    public function ajaxProcessRatingTicket()
    {
        $id_ets_hd_ticket = trim(Tools::getValue('id_ets_hd_ticket')) !== '' && Validate::isUnsignedInt(Tools::getValue('id_ets_hd_ticket')) ? Tools::getValue('id_ets_hd_ticket') : 0;
        if ($id_ets_hd_ticket <= 0 || !($ticket = HDTicket::getInstanceById($id_ets_hd_ticket))) {
            $this->_errors[] = $this->l('Ticket is not found.');
        } elseif (!isset($this->context->customer->id) || $this->context->customer->id <= 0 || $this->context->customer->id !== (int)$ticket->id_customer) {
            $this->_errors[] = $this->l('Permission denied.');
        } else {
            if (($rating = trim(Tools::getValue('rating'))) == '' || !Validate::isUnsignedInt($rating) || (int)$rating < 1 && (int)$rating > 5) {
                $this->_errors[] = $this->l('Rating is invalid');
            }
            if (!$this->_errors) {
                $ticket->rating = (int)$rating;
                if (!$ticket->save(true)) {
                    $this->_errors[] = $this->l('Rating is fail.');
                }
            }
        }
        $has_error = count($this->_errors) ? 1 : 0;
        die(json_encode([
            'errors' => $has_error ? implode(PHP_EOL, $this->_errors) : false,
            'msg' => !$has_error ? $this->l('Rating successfully.') : false,
        ]));
    }

    // End ajaxProcess


    public function postForm($configs, &$object, &$cache_upload_file)
    {
        if (is_array($configs) && count($configs) > 0) {
            foreach ($configs as $key => $config) {
                if ($config['type'] == 'switch') {
                    $this->setField($object, $key, (int)trim(Tools::getValue($key)) ? 1 : 0);
                } elseif ($config['type'] == 'checkbox' || isset($config['multiple']) && $config['multiple']) {
                    $this->setField($object, $key, implode(PHP_EOL, Tools::getValue($key, array())));
                } elseif ($config['type'] == 'file') {
                    if (isset($_FILES[$key]) && !empty($_FILES[$key]['name'])) {

                        if (isset($config['attachment']) && $config['attachment']) {
                            $this->setField($object, $key . '_file_mail', Tools::fileAttachment($key));
                        }
                        if (!isset($config['save_file']) || $config['save_file']) {
                            $folder = isset($config['folder']) ? $config['folder'] : HDDefines::$default_upload;
                            $file_name = HDTools::getNewFilename($folder);

                            if (!is_uploaded_file($_FILES[$key]['tmp_name']) || !@move_uploaded_file($_FILES[$key]['tmp_name'], $folder . $file_name)) {
                                $this->_errors[] = $this->l('An error occurred while uploading.');
                            } else {
                                $this->setField($object, $key, $file_name . '|' . $_FILES[$key]['name']);
                                $cache_upload_file = $folder . $file_name;
                            }
                        } else
                            $this->setField($object, $key, $_FILES[$key]['name']);
                    } elseif (
                        trim($image_deleted = Tools::getValue($key . '_deleted')) !== ''
                        && Validate::isUnsignedInt($image_deleted)
                        && $image_deleted > 0
                    ) {
                        $folder = isset($config['folder']) ? $config['folder'] : HDDefines::$default_upload;
                        $old_image = $folder . trim(Tools::getValue($key . '_file_dir'));
                        if (!file_exists($old_image) || @unlink($old_image)) {
                            $this->setField($object, $key, '');
                        }
                    }
                } elseif ($config['type'] == 'select') {
                    $this->setField($object, $key, trim(Tools::getValue($key)));
                } else {
                    $this->setField($object, $key, trim(Tools::getValue($key)));
                }
            }
        }
    }

    public function setField(&$object, $key, $value)
    {
        
        if (is_object($object)) {
            $object->$key = $value;
        } else {
            $object[$key] = pSQL($value);
        }
    }

    public function getAdminTokenLite($tab, $id_employee)
    {
        return Tools::getAdminToken($tab . (int)Tab::getIdFromClassName($tab) . (int)$id_employee);
    }

    public function postFormTicket($configs)
    {
        $fields = array();
        $id_ets_hd_ticket = trim(Tools::getValue('id_ets_hd_ticket')) !== '' && Validate::isUnsignedInt(Tools::getValue('id_ets_hd_ticket')) ? Tools::getValue('id_ets_hd_ticket') : 0;
        if ($this->isGrantedTicket($id_ets_hd_ticket)) {
            $cache_upload_file = '';
            $this->postForm($configs, $fields, $cache_upload_file);
            
            if ($id_ets_hd_ticket <= 0) {
                if ($this->isStaff()) {
                    $fields['id_employee'] = isset($this->context->employee) && $this->context->employee->id > 0 && $this->context->employee->isLoggedBack() ? $this->context->employee->id : 0;
                    $fields['staff_read'] = 1;
                } else {
                    $fields['staff_read'] = 0;
                }
                $fields['read'] = $fields['staff_read'] > 0 ? 0 : 1;
                if (!$this->isBackOffice()) {
                    $fields['priority'] = ($priority = trim(Configuration::get('ETS_HD_DEFAULT_PRIORITY'))) !== '' ? $priority : 'medium';
                    $fields['status'] = 'open';
                }
            }
            if ($this->isStaff()) {
                $fields['id_customer'] = trim(($id_customer = Tools::getValue('id_customer'))) !== '' && Validate::isUnsignedInt($id_customer) ? (int)$id_customer : 0;
                $fields['id_guest'] = trim(($id_guest = Tools::getValue('id_guest'))) !== '' && Validate::isUnsignedInt($id_guest) ? (int)$id_guest : 0;
            } else {
                $fields['id_customer'] = isset($this->context->customer) && $this->context->customer->id > 0 && $this->context->customer->isLogged() ? $this->context->customer->id : 0;
                $fields['id_guest'] = isset($this->context->cookie->id_guest) && (int)$this->context->cookie->id_guest > 0 ? (int)$this->context->cookie->id_guest : 0;
            }
            $comfirm = 3;
            $has_add_ticket = !$id_ets_hd_ticket;
            if (count($fields) > 0) {
                if (!HDTicket::saveData($fields, $id_ets_hd_ticket, true, $this->_errors)) {
                    if (file_exists($cache_upload_file)) {
                        @unlink($cache_upload_file);
                    }
                    $this->_errors[] = $this->l('Cannot save data.');
                } elseif (
                    $id_ets_hd_ticket > 0
                    && isset($fields['id_customer'])
                    && $fields['id_customer'] > 0
                    && ($customer = new Customer($fields['id_customer']))
                    && $customer->id > 0
                ) {
                    $fields['id_ets_hd_ticket'] = $id_ets_hd_ticket;
                    $customer_name = $customer->firstname . ' ' . $customer->lastname;
                    $from_email = Configuration::get('ETS_HD_SEND_FROM_EMAIL');
                    $from_name = Configuration::get('ETS_HD_SEND_FROM_NAME');
                    if ($has_add_ticket)
                        Hook::exec('actionAddCustomerActiton', array('action' => 'add_ticket_hd', 'id_ticket' => $id_ets_hd_ticket));
                    // Admin add ticket sendmail to (admin && customer):
                    if ($has_add_ticket && $this->isStaff()) {
                        // To admin:
                        $send_to_groups = array();
                        $employees = Employee::getEmployeesByProfile(_PS_ADMIN_PROFILE_, true);
                        $this->sendToGroups($employees, $send_to_groups, $this->isBackOffice() ? 1 : 0);
                        $staff = $this->isBackOffice() ? $this->context->employee : $this->context->customer;
                        $staff_name = $staff->firstname . ' ' . $staff->lastname;
                        $send_to_groups[] = array(
                            'id_lang' => $staff->id_lang,
                            'name' => $staff->firstname . ' ' . $staff->lastname,
                            'email' => $staff->email,
                            'back_office' => $this->isBackOffice() ? 1 : 0,
                            'id_employee' => $this->isBackOffice() ? $this->context->employee->id : 0,
                        );
                        if (count($send_to_groups) > 0) {
                            $subject = array(
                                'origin' => 'A new ticket has been submitted for %s',
                                'text' => $this->l('A new ticket has been submitted for %s'),
                            );
                            $templateVars = array(
                                '{customer_name}' => $customer_name,
                                '{ticket_content}' => $this->getTicketContent($fields,true),
                            );
                            $template = 'to_admin_add_ticket';
                            foreach ($send_to_groups as $group) {
                                $templateVars['{employee_name}'] = $group['name'];
                                $templateVars['{link_view_ticket}'] = $this->getTicketLinkMailSendStaff($group['id_employee'],$id_ets_hd_ticket,$group['id_lang']);
                                if ($this->templateExits($group['id_lang'], $template))
                                {
                                    if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                                    {
                                        Ets_hd_mailqueue::addMailQueue($group['id_lang'],
                                        0,
                                        $group['id_employee'],
                                        $group['name'],
                                        $from_email,
                                        $from_name,
                                        $template,
                                        sprintf(HDTranslate::trans($subject['origin'], $group['id_lang']), $customer_name),
                                        $group['email'],
                                        $templateVars,
                                        null);
                                    }
                                    elseif(!Mail::send(
                                        $group['id_lang']
                                        , 'to_admin_add_ticket'
                                        , sprintf(HDTranslate::trans($subject['origin'], $group['id_lang']), $customer_name)
                                        , $templateVars
                                        , $group['email']
                                        , $group['name']
                                        , $from_email
                                        , $from_name
                                        , null
                                        , null
                                        , dirname(__FILE__) . '/mails/'
                                    ))
                                    $comfirm = 7;
                                    //$this->_errors[] = sprintf($this->l('Sendmail to admin2 mail: %s is fail.'), $group['email']);
                                }
                            }
                        }
                        // To customer:
                        if ($customer->id > 0) {
                            $subject = array(
                                'origin' => '%s added you a ticket',
                                'text' => $this->l('%s added you a ticket'),
                            );
                            $templateVars = array(
                                '{customer_name}' => $customer_name,
                                '{staff_name}' => $staff_name,
                                '{ticket_content}' => $this->getTicketContent($fields,false),
                                '{ticket_id}' => $id_ets_hd_ticket,
                                '{link_ticket}' => HDLink::getInstance()->getTicketLink($customer->id_lang, array('id_ets_hd_ticket' => $id_ets_hd_ticket)),
                            );
                            $template = 'to_customer_admin_add_ticket';
                            if ($this->templateExits($customer->id_lang, $template))
                            {
                                if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                                {
                                    Ets_hd_mailqueue::addMailQueue($customer->id_lang,
                                    $customer->id,
                                    0,
                                    $customer_name,
                                    $from_email,
                                    $from_name,
                                    $template,
                                    sprintf(HDTranslate::trans($subject['origin'], $customer->id_lang), $staff_name),
                                    $customer->email,
                                    $templateVars
                                    );
                                }
                                elseif(!Mail::send(
                                    $customer->id_lang
                                    , $template
                                    , sprintf(HDTranslate::trans($subject['origin'], $customer->id_lang), $staff_name)
                                    , $templateVars
                                    , $customer->email
                                    , $customer_name
                                    , $from_email
                                    , $from_name
                                    , null
                                    , null
                                    , dirname(__FILE__) . '/mails/'
                                ))
                                $comfirm = 8;    
                                //$this->_errors[] = sprintf($this->l('Sendmail to customer email %s is fail.'), $customer->email); 
                            }
                                
                        }
                    } elseif (isset($this->context->customer->id) && $this->context->customer->id > 0) {
                        
                        $from_email = $this->context->customer->email;
                        $from_name = $this->context->customer->firstname . ' ' . $this->context->customer->lastname;

                        // Who to send email notification when a new ticket arrived or edited ticket?
                        if (($sendmail_to_group = trim(Configuration::get('ETS_HD_MAIL_NEW_TICKET'))) !== ''
                            && ($sendmail_to_groups = explode(',', $sendmail_to_group))
                            && count($sendmail_to_groups) > 0
                        ) {
                            $send_to_groups = array();
                            if (in_array('supper_admins', $sendmail_to_groups)) {
                                $employees = Employee::getEmployeesByProfile(_PS_ADMIN_PROFILE_, true);
                                $this->sendToGroups($employees, $send_to_groups, 1);
                            }
                            if (in_array('all_staff', $sendmail_to_groups)) {
                                $employees = HDStaff::getEmployees();
                                $this->sendToGroups($employees, $send_to_groups, 1);
                                $customers = HDStaff::getCustomers();
                                $this->sendToGroups($customers, $send_to_groups);
                            }
                            if ($has_add_ticket) {
                                $subject = array(
                                    'origin' => 'A new ticket arrived',
                                    'text' => $this->l('A new ticket arrived'),
                                );
                            } else {
                                $subject = array(
                                    'origin' => 'A ticket edited',
                                    'text' => $this->l('A ticket edited'),
                                );
                            }
                            $templateVars = array(
                                '{ticket_content}' => $this->getTicketContent($fields,true),
                                '{customer_name}' => $from_name,
                                '{ticket_id}' => $id_ets_hd_ticket,
                            );

                            $template = $has_add_ticket ? 'to_admin_ticket_arrived' : 'to_admin_edit_ticket';
                            $has_sendmail_to_admin = ($has_add_ticket || (int)Configuration::get('ETS_HD_MAIL_TO_ADMIN_EDIT_TICKET'));

                            if (count($send_to_groups) > 0 && $has_sendmail_to_admin) {
                                foreach ($send_to_groups as $group) {
                                    $templateVars['{employee_name}'] = $group['name'];
                                    $templateVars['{link_view_ticket}'] = $this->getTicketLinkMailSendStaff($group['id_employee'],$id_ets_hd_ticket,$group['id_lang']);
                                    if ($this->templateExits($group['id_lang'], $template))
                                    {
                                        if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                                        {
                                            Ets_hd_mailqueue::addMailQueue($group['id_lang'],
                                            0,
                                            $group['id_employee'],
                                            $group['name'],
                                            $from_email,
                                            $from_name,
                                            $template,
                                            HDTranslate::trans($subject['origin'], $group['id_lang']),
                                            $group['email'],
                                            $templateVars
                                            );
                                        }
                                        elseif(!Mail::send(
                                            $group['id_lang']
                                            , $template
                                            , HDTranslate::trans($subject['origin'], $group['id_lang'])
                                            , $templateVars
                                            , $group['email']
                                            , $group['name']
                                            , $from_email
                                            , $from_name
                                            , null
                                            , null
                                            , dirname(__FILE__) . '/mails/'
                                        ))
                                        $comfirm = 7;  
                                        //$this->_errors[] = sprintf($this->l('Sendmail to admin1 mail: %s is fail.'), $group['email']);
                                    }
                                }
                            }
                            if (in_array('custom_emails', $sendmail_to_groups)
                                && ($custom_emails = trim(Configuration::get('ETS_HD_CUSTOM_EMAILS'))) !== ''
                                && ($emails = explode(',', $custom_emails))
                                && count($emails) > 0
                                && $has_sendmail_to_admin
                            ) {
                                $templateVars['{employee_name}'] = '';
                                $templateVars['{link_view_ticket}'] = HDLink::getInstance()->getTicketLink($this->context->language->id, array('id_ets_hd_ticket' => $id_ets_hd_ticket));
                                foreach ($emails as $email) {
                                    if (trim($email) !== '' && Validate::isEmail($email)) {
                                        if ($this->templateExits($this->context->language->id, $template))
                                        {
                                            if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                                            {
                                                Ets_hd_mailqueue::addMailQueue($this->context->language->id,
                                                0,
                                                0,
                                                '',
                                                $from_email,
                                                $from_name,
                                                $template,
                                                HDTranslate::trans($subject['origin'], $this->context->language->id),
                                                $email,
                                                $templateVars,
                                                null);
                                            }
                                            elseif(!Mail::send(
                                                $this->context->language->id
                                                , $template
                                                , HDTranslate::trans($subject['origin'], $this->context->language->id)
                                                , $templateVars
                                                , trim($email)
                                                , null
                                                , $from_email
                                                , $from_name
                                                , null
                                                , null
                                                , dirname(__FILE__) . '/mails/'
                                            ))
                                            $comfirm=8;
                                            //$this->_errors[] = sprintf($this->l('Sendmail to customer %s is fail.'), $email);    
                                        }
                                        
                                    }
                                }
                            }
                        }
                        // Send a confirmation email to customer when ticket is submitted?
                        if ($has_add_ticket && Configuration::get('ETS_HD_MAIL_TO_CUSTOMER')) {
                            // to customer:
                            $subject = array(
                                'origin' => 'Your ticket has been successfully submitted',
                                'text' => $this->l('Your ticket has been successfully submitted'),
                            );
                            $templateVars = array(
                                '{customer_name}' => $customer->firstname . ' ' . $customer->lastname,
                                '{ticket_content}' => $this->getTicketContent($fields,false),
                                '{ticket_id}' => $id_ets_hd_ticket,
                                '{link_ticket}' => HDLink::getInstance()->getTicketLink($customer->id_lang, array('id_ets_hd_ticket' => $id_ets_hd_ticket)),
                            );
                            $template = 'to_customer_ticket_submitted';
                            if ($this->templateExits($customer->id_lang, $template))
                            {
                                if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                                {
                                    Ets_hd_mailqueue::addMailQueue($customer->id_lang,
                                    $customer->id,
                                    0,
                                    $customer->firstname.' '.$customer->lastname,
                                    $from_email,
                                    $from_name,
                                    $template,
                                    HDTranslate::trans($subject['origin'], $customer->id_lang),
                                    $customer->email,
                                    $templateVars
                                    );
                                }
                                elseif(!Mail::send(
                                    $customer->id_lang
                                    , $template
                                    , HDTranslate::trans($subject['origin'], $customer->id_lang)
                                    , $templateVars
                                    , $customer->email
                                    , $customer->firstname . ' ' . $customer->lastname
                                    , $from_email
                                    , $from_name
                                    , null
                                    , null
                                    , dirname(__FILE__) . '/mails/'
                                ))
                                  $comfirm=8;  
                                  //$this->_errors[] = sprintf($this->l('Sendmail to customer %s is fail.'), $customer->email);
                            }
                        }
                    }
                }
            }
            if (!count($this->_errors)) {
                if (!$has_add_ticket) {
                    $this->displayConfirm($comfirm);
                } elseif ($id_ets_hd_ticket > 0) {
                    if ($this->isBackOffice()) {
                        Tools::redirectAdmin($this->context->link->getAdminLink('AdminEtsHDTickets'));
                    }
                    elseif($this->isStaff()){
                        Tools::redirect(HDLink::getInstance()->getStaffsLink($this->context->language->id,array('confirm'=>$comfirm)));
                    } elseif ($this->context->controller instanceof Ets_helpdeskAddModuleFrontController) {
                        Tools::redirect(HDLink::getInstance()->getAddTicketLink($this->context->language->id, ['ets_hd_ticket_id' => $id_ets_hd_ticket]));
                    } else {
                        Tools::redirect(HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams(['add_ticket' => 1, 'ets_hd_ticket_id' => $id_ets_hd_ticket])));
                    }
                }
            } else {
                $this->context->controller->errors = $this->_errors;
            }
        }
    }

    public function templateExits($id_lang, $template)
    {
        $language = new Language($id_lang);
        $ps_mail_type = Configuration::get('PS_MAIL_TYPE');
        $templatePath = dirname(__FILE__) . '/mails/';
        $isoTemplate = $language->iso_code . '/' . $template;
        if (!file_exists($templatePath . $isoTemplate . '.txt') &&
            (
                $ps_mail_type == Mail::TYPE_BOTH ||
                $ps_mail_type == Mail::TYPE_TEXT
            )
        ) {
            $this->_errors[] = sprintf($this->l('Error - The following e-mail template is missing: %s'), $templatePath . $isoTemplate . '.txt');
        } elseif (!file_exists($templatePath . $isoTemplate . '.html') &&
            (
                $ps_mail_type == Mail::TYPE_BOTH ||
                $ps_mail_type == Mail::TYPE_HTML
            )
        ) {
            $this->_errors[] = sprintf($this->l('Error - The following e-mail template is missing: %s'), $templatePath . $isoTemplate . '.html');
        }

        return !count($this->_errors);
    }

    static $cache_ticket;

    public function getTicketContent($ticket = array(),$is_staff=null)
    {
        if (!is_array($ticket) && Validate::isUnsignedInt($ticket)) {
            $ticket = HDTicket::getTickets($ticket);
        }
        
        $cache_id = isset($ticket['id_ets_hd_ticket']) ? $ticket['id_ets_hd_ticket'] : 0;
        if (!isset(self::$cache_ticket[$cache_id])) {
            $content = '';
            if (is_array($ticket)) {
                $fields_display = HDColumn::getColumnFields($this->context, false, $this->isStaff());
                $this->getTicketProperties($ticket, $fields_display,$is_staff);
                $this->smarty->assign(array(
                    'fields' => $fields_display,
                    'ticket' => $ticket,
                ));
                $content = $this->display(__FILE__, 'mail-ticket-content.tpl');
            }
            self::$cache_ticket[$cache_id] = $content;
        }

        return self::$cache_ticket[$cache_id];
    }

    public function sendToGroups($groups, &$send_to_groups, $back_office = 0)
    {
        if (is_array($groups) && count($groups) > 0) {
            foreach ($groups as $group) {
                if (isset($group['email']) && trim($group['email']) !== '') {
                    $send_to_groups[] = array(
                        'id_lang' => isset($group['id_lang']) && $group['id_lang'] > 0 ? (int)$group['id_lang'] : (int)Configuration::get('PS_LANG_DEFAULT'),
                        'name' => (isset($group['firstname']) ? trim($group['firstname']) : '') . (isset($group['lastname']) ? ' ' . trim($group['lastname']) : ''),
                        'email' => trim($group['email']),
                        'back_office' => $back_office,
                        'id_employee' => isset($group['id_employee']) && (int)$group['id_employee'] > 0 ? (int)$group['id_employee'] : 0
                    );
                }
            }
        }

    }

    public function displayConfirm($confirm, $params = array())
    {
        if ($this->ajax <= 0) {
            if ($this->isGuest()) {
                $confirm = array('conf_msg' => $confirm);
            } else {
                $confirm = array('confirm' => $confirm);
            }
            if (is_array($params) && count($params) > 0) {
                $confirm = array_merge($params, $confirm);
            }
            if(Tools::isSubmit('viewNext'))
            {
                $tickets = HDTicket::getTickets(0, 0, 0, 1, 'last_date_message desc', $this->context, $this->isStaff());
                if($tickets)
                {
                    if($this->isBackOffice()) 
                        Tools::redirectAdmin($this->context->link->getAdminLink('AdminEtsHDTickets') . '&id_ets_hd_ticket='.(int)$tickets[0]['id_ets_hd_ticket'].'&' . http_build_query($confirm));
                    else
                        Tools::redirect(HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams(array_merge($confirm,array('id_ets_hd_ticket'=>$tickets[0]['id_ets_hd_ticket'])))));
                }
            }
            if($this->isBackOffice()) 
                Tools::redirectAdmin($this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query($confirm));
            else
               Tools::redirect(HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams($confirm))); 
           
        }
    }
    public function processLoadMessageTicket($id_ticket)
    {
        die(Tools::jsonEncode(
            array(
                'last_date' => Date('Y-m-d H:i:s'),
                'new_messages' => $this->reloadNewMessage($id_ticket),
                'tickets' => $this->isStaff() ? $this->reloadNewTicket($id_ticket):'',
            )
        ));
    }
    public function postFormMessage($configs)
    {
        $message = new HDTicketMessage();
        $id_ets_hd_ticket = Tools::getValue('id_ets_hd_ticket');
        $message->id_ets_hd_ticket = trim($id_ets_hd_ticket) !== '' && Validate::isUnsignedInt($id_ets_hd_ticket) ? (int)$id_ets_hd_ticket : 0;
        $json_array = array();
        if ($message->id_ets_hd_ticket <= 0 || !($ticket = HDTicket::getInstanceById($id_ets_hd_ticket))) {
            $this->_errors[] = $this->l('Ticket is not found.');
        } elseif ($this->isGrantedTicket($message->id_ets_hd_ticket)) {

            $cache_upload_file = '';
            $this->postForm($configs, $message, $cache_upload_file);

            $message->id_employee = $this->isBackOffice() ? $this->context->employee->id : 0;
            if (!$this->isBackOffice()) {
                $message->id_customer = isset($this->context->customer) && $this->context->customer->id > 0 && $this->context->customer->isLogged() ? $this->context->customer->id : 0;
            }
            $message->is_staff = $this->isStaff() && !$this->isBackOffice() ? 1 : 0;
            // Calc response time:
            if ($this->isStaff()) {
                $last_message = HDTicketMessage::getLastMessageByTicket($ticket->id);
                if ($last_message instanceof HDTicketMessage
                    && $last_message->id > 0
                ) {
                    if (
                        $last_message->id_employee <= 0
                        && $last_message->id_customer > 0
                        && $last_message->is_staff <= 0
                    ) {
                        $message->response_time = time() - strtotime($last_message->date_add);
                    }
                } elseif (
                    $ticket->id_employee <= 0
                    && $ticket->id_customer > 0
                ) {
                    $message->response_time = time() - strtotime($ticket->date_add);
                }
            }
            // End calc response time:
            if (!$message->save()) {
                if (file_exists($cache_upload_file)) {
                    @unlink($cache_upload_file);
                }
                $this->_errors[] = $this->l('Cannot post message!');
            } else {
                if ($this->isStaff()) {
                    HDDepartment::saveData($id_ets_hd_ticket, $this->isBackOffice() ? $this->context->employee->id : $this->context->customer->id);
                    HDTicketMessage::makeTicketOfStaff($id_ets_hd_ticket);
                }
                else
                    $ticket->status='open';
                $ticket->staff_replied = $message->id_employee > 0 || $message->is_staff;
                $ticket->replied = $ticket->staff_replied > 0 ? 0 : 1;

                $ticket->staff_read = $ticket->staff_replied;
                $ticket->read = $ticket->staff_read > 0 ? 0 : 1;

                if (!$ticket->update(true)) {
                    $this->_errors[] = $this->l('Update sate error.');
                }
                $message_array = HDTicketMessage::getMessages($message->id, $message->id_ets_hd_ticket);
                $this->getMessageProperties($message_array);
                $json_array['message'] = $this->displayTicketMessage($message_array);
                $json_array['message_content'] = $this->displayTicketMessage($message_array, true);
                $json_array['unique'] = isset($message_array['unique']) ? $message_array['unique'] : uniqid();
                $from_email = Configuration::get('ETS_HD_SEND_FROM_EMAIL');
                $from_name = Configuration::get('ETS_HD_SEND_FROM_NAME');
                $json_array['last_date'] = Date('Y-m-d H:i:s');
                $json_array['new_messages'] = $this->reloadNewMessage($message->id_ets_hd_ticket);
                
                $json_array['tickets'] =  $this->isStaff() ? $this->reloadNewTicket($message->id_ets_hd_ticket):'';
                if ($this->isStaff()) {

                    $staff = $this->isBackOffice() ? $this->context->employee : $this->context->customer;
                    $staff_name = $staff->firstname . ' ' . $staff->lastname;
                    $fileAttachment = Configuration::get('ETS_HD_STAFF_UPLOAD_FILE') ? $message->attachment_file_mail : null;

                    //Send email to admin when they successfully replied?
                    if (Configuration::get('ETS_HD_MAIL_TO_ADMIN_REPLIED')) {
                        $subject = array(
                            'origin' => 'You have been successful replied ticket',
                            'text' => $this->l('You have been successful replied ticket'),
                        );
                        $templateVars = array(
                            '{employee_name}' => $staff_name,
                            '{ticket_id}' => $message->id_ets_hd_ticket,
                            '{message}' => $json_array['message_content'],
                            '{link_view_ticket}' => $this->getTicketLinkMailSendStaff($this->isBackOffice() ? $this->context->employee->id:0,$message->id_ets_hd_ticket,$staff->id_lang)
                        );
                        $template = 'to_admin_replied_ticket';
                        if ($this->templateExits($staff->id_lang, $template))
                        {
                            if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                            {
                                Ets_hd_mailqueue::addMailQueue($staff->id_lang,
                                0,
                                $staff->id,
                                $staff_name,
                                $from_email,
                                $from_name,
                                $template,
                                HDTranslate::trans($subject['origin'], $staff->id_lang),
                                $staff->email,
                                $templateVars,
                                $fileAttachment
                                );
                            }
                            elseif(!Mail::send(
                                $staff->id_lang
                                , $template
                                , HDTranslate::trans($subject['origin'], $staff->id_lang)
                                , $templateVars
                                , $staff->email
                                , $staff_name
                                , $from_email
                                , $from_name
                                , $fileAttachment
                                , null
                                , dirname(__FILE__) . '/mails/'
                            ))
                                $this->_warnings[] = sprintf($this->l(' Send email to %s is fail.'), $staff->email);
                        }
                    }

                    // Send email to customer when admin reply to their ticket?
                    if (Configuration::get('ETS_HD_MAIL_REPLY_CUSTOMER')) {
                        $ticket = HDTicket::getInstanceById($message->id_ets_hd_ticket);
                        $customer = new Customer($ticket->id_customer);
                        $customer_name = $customer->firstname . ' ' . $customer->lastname;
                        if ($customer->id > 0) {
                            $subject = array(
                                'origin' => '%s just replied to your ticket',
                                'text' => $this->l('%s just replied to your ticket'),
                            );
                            $templateVars = array(
                                '{customer_name}' => $customer_name,
                                '{employee_name}' => $staff_name,
                                '{ticket_id}' => $message->id_ets_hd_ticket,
                                '{message}' => $json_array['message_content'],
                                '{link_ticket}' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query(array('id_ets_hd_ticket' => $id_ets_hd_ticket)) : HDLink::getInstance()->getStaffLink($staff->id_lang, array('id_ets_hd_ticket' => $id_ets_hd_ticket))
                            );
                            $template = 'to_customer_admin_reply_ticket';
                            if ($this->templateExits($customer->id_lang, $template))
                            {
                                if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                                {
                                    Ets_hd_mailqueue::addMailQueue($customer->id_lang,
                                    $customer->id,
                                    0,
                                    $customer_name,
                                    $staff_name,
                                    $staff->email,
                                    $template,
                                    sprintf(HDTranslate::trans($subject['origin'], $customer->id_lang), $staff_name),
                                    $customer->email,$templateVars,$fileAttachment
                                    );
                                }
                                elseif(!Mail::send(
                                    $customer->id_lang
                                    , $template
                                    , sprintf(HDTranslate::trans($subject['origin'], $customer->id_lang), $staff_name)
                                    , $templateVars
                                    , $customer->email
                                    , $customer_name
                                    , $staff->email
                                    , $staff_name
                                    , $fileAttachment
                                    , null
                                    , dirname(__FILE__) . '/mails/'
                                ))
                                $this->_warnings[] = sprintf($this->l('Send email to %s is fail.'), $customer->email);
                            }
                                
                        }
                    }
                } else {
                    $customer_name = $this->context->customer->firstname . ' ' . $this->context->customer->lastname;
                    $fileAttachment = Configuration::get('ETS_HD_CUSTOMER_REPLY_UPLOAD_FILE') ? $message->attachment_file_mail : null;
                    //Send email to admin when customer reply to a ticket?
                    if (Configuration::get('ETS_HD_MAIL_REPLY_ADMIN')) {
                        $send_to_groups = array();
                        $employees = Employee::getEmployeesByProfile(_PS_ADMIN_PROFILE_, true);
                        $this->sendToGroups($employees, $send_to_groups, 1);
                        $employees = HDStaff::getEmployees();
                        $this->sendToGroups($employees, $send_to_groups, 1);
                        $customers = HDStaff::getCustomers();
                        $this->sendToGroups($customers, $send_to_groups);
                        $subject = array(
                            'origin' => 'Customer replied to a ticket',
                            'text' => $this->l('Customer replied to a ticket'),
                        );
                        $templateVars = array(
                            '{customer_name}' => $customer_name,
                            '{ticket_id}' => $message->id_ets_hd_ticket,
                            '{message}' => $json_array['message_content'],
                        );
                        $template = 'to_admin_customer_reply_ticket';
                        if (count($send_to_groups) > 0) {
                            foreach ($send_to_groups as $group) {
                                $templateVars['{employee_name}'] = $group['name'];
                                $templateVars['{link_view_ticket}'] = $this->getTicketLinkMailSendStaff($group['id_employee'],$id_ets_hd_ticket,$group['id_lang']);
                                if ($this->templateExits($group['id_lang'], $template))
                                {
                                    if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                                    {
                                        Ets_hd_mailqueue::addMailQueue($group['id_lang'],
                                        0,
                                        $group['id_employee'],
                                        $group['name'],
                                        $this->context->customer->email,
                                        $customer_name,
                                        $template,
                                        HDTranslate::trans($subject['origin'], $group['id_lang']),
                                        $group['email'],
                                        $templateVars,
                                        $fileAttachment
                                        );
                                    }
                                    elseif(!Mail::send(
                                        $group['id_lang']
                                        , $template
                                        , HDTranslate::trans($subject['origin'], $group['id_lang'])
                                        , $templateVars
                                        , $group['email']
                                        , $group['name']
                                        , $this->context->customer->email
                                        , $customer_name
                                        , $fileAttachment
                                        , null
                                        , dirname(__FILE__) . '/mails/'
                                    ))
                                    $this->_warnings[] = sprintf($this->l('Sendmail to mail: %s is fail.'), $group['email']);   
                                }
                            }
                        }
                    }
                    // Send email to customer when they successfully replied? :
                    if (Configuration::get('ETS_HD_MAIL_TO_CUSTOMER_REPLIED')) {
                        $subject = array(
                            'origin' => 'You have been successful replied ticket',
                            'text' => $this->l('You have been successful replied ticket'),
                        );
                        $templateVars = array(
                            '{customer_name}' => $customer_name,
                            '{ticket_id}' => $message->id_ets_hd_ticket,
                            '{message}' => $json_array['message_content'],
                            '{link_ticket}' => HDLink::getInstance()->getTicketLink($this->context->customer->id_lang, array('id_ets_hd_ticket' => $id_ets_hd_ticket))
                        );
                        $template = 'to_customer_replied_ticket';
                        if ($this->templateExits($this->context->customer->id_lang, $template))
                        {
                            if(Configuration::get('ETS_HD_WHEN_SEND_MAIL')=='by_queue')
                            {
                                Ets_hd_mailqueue::addMailQueue($this->context->customer->id_lang,
                                $this->context->customer->id,
                                0,
                                $customer_name,
                                $from_email,
                                $from_name,
                                $template,
                                HDTranslate::trans($subject['origin'], $this->context->customer->id_lang),
                                $this->context->customer->email,
                                $templateVars,$fileAttachment);
                            }
                            elseif(!Mail::send(
                                $this->context->customer->id_lang
                                , $template
                                , HDTranslate::trans($subject['origin'], $this->context->customer->id_lang)
                                , $templateVars
                                , $this->context->customer->email
                                , $customer_name
                                , $from_email
                                , $from_name
                                , $fileAttachment
                                , null
                                , dirname(__FILE__) . '/mails/'
                            ))
                            $this->_warnings[] = sprintf($this->l('Sendmail to mail: %s is fail.'), $this->context->customer->email);
                        }
                    }
                }
            }
        }

        $has_error = count($this->_errors) ? 1 : 0;
        $json_array['errors'] = $has_error ? implode(PHP_EOL, $this->_errors) : false;
        $json_array['warnings'] = $this->_warnings ? Tools::nl2br(implode("\n",$this->_warnings)):false;
        $json_array['success'] = !$has_error ? $this->l('Send message sucessfull'):'';
        die(json_encode($json_array));
    }
    public function reloadNewMessage($id_ticket)
    {
        $ticket = new HDTicket($id_ticket);
        if($this->isStaff())
            $ticket->staff_read=1;
        else
            $ticket->read =1;
        $ticket->update();
        if(($late_date = Tools::getValue('last_date')) && HDTicket::getTickets($id_ticket, true, 0, 0, null, $this->context, $this->isStaff()))
        {
            $new_messages = HDTicketMessage::getMessages(0,$id_ticket,0,0,0,null,null,false,'a.date_add > "'.pSQL($late_date).'"');
            if($new_messages)
            {
                $messages = array();
                foreach($new_messages as $new_message)
                {
                    $this->getMessageProperties($new_message,true);
                    $messages[] = array(
                        'message' => $this->displayTicketMessage($new_message),
                        'id_ets_hd_ticket_message' => $new_message['id_ets_hd_ticket_message'],
                        'unique'=> isset($new_message['unique']) ? $new_message['unique'] : uniqid(),
                    );
                }
                return $messages;
            }
        }
    }
    public function displayTicketMessage($message, $sendmail = false)
    {
        $this->smarty->assign(array(
            'currentIndex' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams()),
            'message' => $message,
            'sendmail' => $sendmail,
            'is_staff' => $this->isStaff(),
        ));

        return $this->display(__FILE__, 'bo-fo-ticket-message.tpl');
    }

    static $cached_message_unique = null;

    public function getMessageProperties(&$row,$show_profile=false)
    {
        if (isset($row['attachment']) && trim($row['attachment']) !== '') {
            $attachment = explode('|', $row['attachment']);
            if (count($attachment) > 1) {
                if(!file_exists(_PS_DOWNLOAD_DIR_ . $this->name . '/'.$attachment[0]))
                {
                    $row['file_deleted'] = true;
                }
                $params = array(
                    'file' => trim($attachment[0]),
                    'type' => 'message',
                    'name' => 'attachment',
                    'id' => $row['id_ets_hd_ticket_message']
                );
                $row['attachment'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDDownload') . '&' . http_build_query($params) : HDLink::getInstance()->getDownloadLink($this->context->language->id, $params);
                $fileZise = @filesize(_PS_DOWNLOAD_DIR_ . $this->name . '/'.$attachment[0]);
                $row['attachment_name'] = trim($attachment[1]);
                $row['file_size'] ='('.($fileZise >=1024 ? Tools::ps_round($fileZise/1024,2):$fileZise).' '.($fileZise >= 1024 ? 'MB':'KB').')';
            }
        }
        if ($show_profile || self::$cached_message_unique == null || isset($row['unique']) && self::$cached_message_unique !== trim($row['unique'])) {
            self::$cached_message_unique = trim($row['unique']);
            /*Get avatar*/
            $message_of_staff = (int)$row['id_employee'] > 0 || (int)$row['is_staff'] > 0;
            $row['show_profile'] = true;
            if (trim($row['avatar']) == '' || !file_exists(HDDefines::$avatar_upload . trim($row['avatar']))) {
                $avatar = $message_of_staff ? Configuration::get('ETS_HD_EMPLOYEE_AVATAR_DEFAULT') : Configuration::get('ETS_HD_CUSTOMER_AVATAR_DEFAULT');
                $row['avatar'] = $avatar && file_exists(HDDefines::$avatar_upload . $avatar) ? $avatar : '';
            }
            if (trim($row['avatar']) !== '') {
                $row['avatar'] = $this->getMediaLink(HDDefines::$avatar_base_uri . $row['avatar']);
            } else {
                $avatar = $message_of_staff ? HDDefines::$employee_avatar_default : HDDefines::$customer_avatar_default;
                $row['avatar'] = $avatar && file_exists($this->local_path . 'views/img/' . $avatar) ? $this->getMediaLink($this->_path . 'views/img/' . $avatar) : '';
            }
        }
        if (isset($row['yourself']) && $row['yourself'] > 0) {
            $row['yourself'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDStaffs') . '&' . http_build_query(array('id_ets_hd_staff' => (int)HDStaff::getIdStaffByIdEmployee($row['id_employee']) . '-' . $row['id_employee'], 'updateets_hd_staff' => '')) : $this->context->link->getPageLink('identity');
        }
        if (isset($row['message']) && trim($row['message']) !== '') {
            $row['message'] = preg_replace('/\b(?:http(?:|s):\/\/[\#\/\._a-zA-Z0-9\x{0600}-\x{06FF}\pL\pS-]+)\b/u', '<a href="$0">$0</a>', $row['message']);
        }
        $time_date_add = strtotime($row['date_add']);
        if (time() - $time_date_add < 86400) {
            $row['display_date'] = $this->l('Today') . ' ' . date('h:i A', $time_date_add);
        } elseif (time() - $time_date_add < 172800) {
            $row['display_date'] = $this->l('Yesterday') . ' ' . date('h:i A', $time_date_add);
        } else
            $row['display_date'] = Tools::dateFormat(array('date' => $row['date_add']), $this->smarty);

        return $row;
    }

    public function ajaxProcessPaginationMessage()
    {
        $id_ets_hd_ticket = Tools::getValue('id_ets_hd_ticket');
        if (!$id_ets_hd_ticket ||
            !Validate::isUnsignedInt($id_ets_hd_ticket)
        ) {
            $this->_errors[] = $this->l('Ticket does\'t exist.');
        } elseif ($this->isGrantedTicket($id_ets_hd_ticket)) {
            $p = Tools::getValue('p');
            if (!$p || !Validate::isUnsignedInt($p)) {
                $p = 1;
            }
            $n = Tools::getValue('n');
            if (!$n || !Validate::isUnsignedInt($n)) {
                $n = (int)Configuration::get('ETS_HD_NUMBER_TICKET_MESSAGES') ?: 10;
            }
            $params = array(
                'id_ets_hd_ticket' => $id_ets_hd_ticket,
                'p' => $p + 1,
                'n' => $n,
            );
            $messages = HDTicketMessage::getMessages(0, $id_ets_hd_ticket, 0, $p, $n, 'id_ets_hd_ticket_message.desc', $this->context);
            $messages = HDTools::quickSort($messages, 'id_ets_hd_ticket_message');
            $count = count($messages);
            if ($count > 0) {
                self::$cached_message_unique = null;
                foreach ($messages as &$message) {
                    $this->getMessageProperties($message);
                }
                
            }
            if ($n > $count) {
                $n -= $count;
            }
            $this->context->smarty->assign(array(
                'messages' => $messages,
            ));
            die(json_encode(array(
                'messages' => $this->display(__FILE__, 'bo-fo-ticket-message-partial.tpl'),
                'next_url' => $n <= $count ? $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query($params) : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams($params)) : '',
            )));
        }
    }

    public function ajaxProcessMarkAsReplied()
    {
        if (!$this->isStaff()) {
            $this->_errors[] = $this->l('Permission denied.');
        } else {
            $id_ets_hd_ticket = Tools::getValue('id_ets_hd_ticket');
            $id_ets_hd_ticket = trim($id_ets_hd_ticket) !== '' && Validate::isUnsignedInt($id_ets_hd_ticket) ? (int)$id_ets_hd_ticket : 0;

            if ($id_ets_hd_ticket <= 0 || !($ticket = HDTicket::getInstanceById($id_ets_hd_ticket))) {
                $this->_errors[] = $this->l('Ticket is not found.');
            } elseif ($this->isGrantedTicket($id_ets_hd_ticket)) {
                $id_ets_hd_ticket_message = Tools::getValue('id_ets_hd_ticket_message');
                $id_ets_hd_ticket_message = trim($id_ets_hd_ticket_message) !== '' && Validate::isUnsignedInt($id_ets_hd_ticket_message) ? (int)$id_ets_hd_ticket_message : 0;
                if ($id_ets_hd_ticket_message <= 0 || !($message = HDTicketMessage::getInstanceById($id_ets_hd_ticket_message))) {
                    $this->_errors[] = $this->l('Message is does\'t exist.');
                } else {
                    $ticket->staff_replied = 1;
                    $ticket->staff_read=1;
                    $message->mark_as_replied = $this->isBackOffice() ? HDStaff::getIdStaffByIdEmployee($this->context->employee->id) : HDStaff::getIdStaffByIdCustomer($this->context->customer->id);
                    if (!$ticket->save(true) || !$message->save(true)) {
                        $this->_errors[] = $this->l('Mark as replied error.');
                    } else {
                        HDTicketMessage::makeTicketOfStaff($id_ets_hd_ticket);
                    }
                }
            }
        }
        $has_error = count($this->_errors) ? 1 : 0;
        die(json_encode([
            'errors' => $has_error ? implode(PHP_EOL, $this->_errors) : false,
            'msg' => !$has_error ? $this->l('Mark as replied successfully.') : false,
        ]));
    }
    public function reloadNewTicket($id_ticket)
    {
        if(($last_reload_ticket=Tools::getValue('last_date')) && Validate::isDate($last_reload_ticket))
        {
            $filter = array();
            $filter['last_date_message'] = array(
                            'rule' =>  'tm.date_add > "' . pSQL($last_reload_ticket) . '" OR a.date_add > "' . pSQL($last_reload_ticket) . '" ',
                            'value' => $last_reload_ticket
                        );
            $tickets = HDTicket::getTickets(0, 0, 0, 0, 'last_date_message DESC', $this->context, $this->isStaff(), $filter);
            if($tickets)
            {
                foreach($tickets as &$item)
                {
                    $this->getTicketProperties($item,array(),$this->isStaff());
                    $item['last_date_message'] = $this->displayTimeByDate($item['last_date_message'],false);
                    $this->smarty->assign(
                        array(
                            'item_ticket' => $item,
                            'id_ets_hd_ticket' =>$id_ticket,
                            'is_staff' => $this->isStaff(),
                            
                        )
                    );
                    $item['row_content'] = $this->display(__FILE__,'bo-ticket-left-row.tpl');                        
                }
            }
            return $tickets;
        }
    }
    public function viewTicket($id_ets_hd_ticket)
    {
        if ($confirm = trim(Tools::getValue('confirm')) && !$this->ajax) {
            switch ($confirm) {
                case 1:
                    $this->context->controller->success[] = $this->l('Successful deletion.');
                    break;
                case 2:
                    $this->context->controller->success[] = $this->l('Successful ticket closed.');
                    break;
                case 3:
                    $this->context->controller->success[] = $this->l('Successful creation.');
                    break;
                case 4:
                    $this->context->controller->success[] = $this->l('Successful update.');
                    break;
                case 5:
                    $this->context->controller->errors[] = $this->l('Ticket not found.');
                    break;
                case 6:
                    $this->context->controller->errors[] = $this->l('Permission denied ticket.');
                    break;
                case 7:
                    $this->context->controller->success[] = $this->l('Submit ticket successfull. Send email to admin fail');
                    break;
                case 8:
                    $this->context->controller->success[] = $this->l('Submit ticket successfull. Send email to customer fail');
                    break;
            }
            if ($this->isBackOffice()) {
                $this->context->controller->confirmations = $this->context->controller->success;
            }
        }
        if (trim($id_ets_hd_ticket) == '' ||
            !Validate::isUnsignedInt($id_ets_hd_ticket) ||
            !($ticket = HDTicket::getTickets($id_ets_hd_ticket, 0, 0, 0, null, $this->context, $this->isStaff()))
        ) {
            $this->displayConfirm(5);
        } elseif ($this->isGrantedTicket($id_ets_hd_ticket)) {

            if (!HDTicket::read($id_ets_hd_ticket, $this->isStaff())) {
                $this->_errors[] = $this->l('Cannot read ticket');
            }

            // Ticket:
            $fields = array_merge(array('product' => array(
                        'name' => 'product',
                        'label' => $this->l('Product'),
                        'type' => 'text',
                        'filter' => 'IF(p.reference != "", CONCAT(pl.name, " (", p.reference, ")"), pl.name)',
                        'class' => 'ticket_product',
                        'product_display' => true,
                        'validate' => 'isCleanHtml',
                    )),HDColumn::getColumnFields($this->context)) ;
            $this->getTicketProperties($ticket, $fields);
            if (HDDataProvider::getOrders((int)$ticket['id_customer'], trim($ticket['order_ref']), true, 0, 0, null, $this->context)) {
                $paramUrls = array(
                    'id_customer' => (int)$ticket['id_customer'],
                    'order_ref' => trim($ticket['order_ref'])
                );
                $ticket['order_link'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDProcess') . '&' . http_build_query($paramUrls) : HDLink::getInstance()->getProcessLink($this->context->language->id, $paramUrls);
            }

            // Messages:
            $number_of_message = HDTicketMessage::getMessages(0, $id_ets_hd_ticket, 1, 0, 0, null, $this->context);
            $n = (int)Configuration::get('ETS_HD_NUMBER_TICKET_MESSAGES') ?: 10;
            $messages = HDTicketMessage::getMessages(0, $id_ets_hd_ticket, 0, 1, $n, 'id_ets_hd_ticket_message.desc', $this->context);
            if($messages && $this->isStaff())
            {
                $mark_as_replied = false;
                foreach($messages as &$message)
                {
                    if($ticket['staff_replied'])
                        $message['mark_as_replied'] =1;
                    else
                    {
                        if($mark_as_replied==true)
                            $message['mark_as_replied'] =1;
                        if(!$message['mark_as_replied'])
                           $mark_as_replied = true; 
                        
                    }
                }
            }
            $messages = HDTools::quickSort($messages, 'id_ets_hd_ticket_message');
            if ($messages) {
                self::$cached_message_unique = null;
                foreach ($messages as &$message) {
                    $this->getMessageProperties($message);
                }
                //$messages = HDTools::quickSort($messages, 'id_ets_hd_ticket_message');
            }
            $params = array(
                'id_ets_hd_ticket' => $id_ets_hd_ticket,
                'p' => 2,
                'n' => $n
            );
            $title_tickets = array(
                '1' => $this->l('Terrible'),
                '2' => $this->l('Acceptable'),
                '3' => $this->l('Fairly Good'),
                '4' => $this->l('Good'),
                '5' => $this->l('Excellent'),
            );
            // View:
            if($this->isStaff() && !$this->ajax)
            {
                $tickets = HDTicket::getTickets(0, 0, 0, 20, 'last_date_message desc', $this->context, $this->isStaff());
                if($tickets)
                {
                    foreach($tickets as &$item)
                    {
                        $this->getTicketProperties($item,array(),$this->isStaff());
                        $item['last_date_message'] = $this->displayTimeByDate($item['last_date_message'],false);              
                    }
                }
            }
            $this->context->smarty->assign(array(
                'ETS_HD_TICKET_DESCRIPTION' => $this->isStaff() ? Configuration::get('ETS_HD_TICKET_DESCRIPTION', $this->context->language->id) : Configuration::get('ETS_HD_STAFF_DESCRIPTION', $this->context->language->id),
                'fields' => $fields,
                'ticket' => $ticket,
                'title_tickets' => $title_tickets,
                'messages' => $messages,
                'currentIndex' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams(array('list'=>1))),
                'form' => $this->formMessage($id_ets_hd_ticket),
                'is_staff' => $this->isStaff(),
                'priority' => HDDefines::getInstance()->getOptionPriority(),
                'status' => HDDefines::getInstance()->getOptionStatus(),
                'supper_admin' => $this->isBackOffice(true),
                'admin_delete_link' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query(array('id_ets_hd_ticket' => $id_ets_hd_ticket, 'delete_ticket' => 1)) : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams(array('id_ets_hd_ticket' => $id_ets_hd_ticket, 'delete_ticket' => 1))),
                'back_office' => $this->isBackOffice(),
                'filter_unique' => self::$filter_unique,
                'has_product_expried' => $this->isStaff()? Hook::exec('actionCheckLicenseExpried',array('id_customer'=>$ticket['id_customer'])):false,
                'list_tickets' => $this->isStaff() && !$this->ajax ? $tickets: array(),
                'isAjax' => $this->ajax,
                'id_ets_hd_ticket' => $id_ets_hd_ticket,
                'has_load_more' => ($number_of_message - count($messages)) > 0,
                'ETS_HD_TIME_RELOAD_LIST_MESSAGE' => $this->isBackOffice() ? ( (float)Tools::ps_round(Configuration::get('ETS_HD_TIME_RELOAD_LIST_MESSAGE'),2) ? :false) : ( (float)Tools::ps_round(Configuration::get('ETS_HD_TIME_RELOAD_LIST_MESSAGE_FRONT'),2) ? :false),
                'next_url' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query($params) : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams($params)),
                'products_licenseBeforeExpried' => !$this->isStaff() ? Hook::exec('actionCheckLicenseBeforeExpried',array('id_customer'=>$this->context->customer->id,'list'=>true)):'',
                'products_licenseExpried' =>!$this->isStaff() ? Hook::exec('actionCheckLicenseExpried',array('id_customer'=>$this->context->customer->id,'list'=>true)):'',
            ));

            return $this->display(__FILE__, 'bo-fo-ticket.tpl');
        }
    }

    public function isStaff()
    {
        return $this->isBackOffice() && ($this->context->employee->id_profile == _PS_ADMIN_PROFILE_ || HDStaff::isGranted(0, $this->context->employee->id)) || $this->customer_staff && isset($this->context->customer->id) && $this->context->customer->id > 0 && HDStaff::isGranted($this->context->customer->id) ? 1 : 0;
    }

    public function isGuest()
    {
        return !$this->isBackOffice() && (!isset($this->context->customer->id) || !$this->context->customer->id || !$this->context->customer->isLogged()) && (int)Configuration::get('ETS_HD_ALLOW_USER_SUBMIT');
    }

    public $content;

    public function initContent($ret = false)
    {
        if ((int)Tools::getValue('add_ticket') ||
            (int)Tools::getValue('edit_ticket') ||
            $this->context->controller instanceof Ets_helpdeskAddModuleFrontController
        ) {
            $this->content = $this->formTicket();
        } elseif ($id_ets_hd_ticket = (int)Tools::getValue('id_ets_hd_ticket')) {
            $this->content = $this->viewTicket($id_ets_hd_ticket);
        } else {
            $this->content = $this->listTicket();
        }
        if ($ret) {
            return $this->content;
        }
        $this->context->smarty->assign(array(
            'content' => $this->content,
        ));
    }

    static $cache_field_ticket = array();

    public function getTicketFields()
    {
        if (!self::$cache_field_ticket) {
            $column_fields = HDColumn::getColumnFields($this->context);
            self::$cache_field_ticket = array_merge(
                $this->isStaff() ? array(
                    'id_customer' => array(
                        'name' => 'id_customer',
                        'type' => 'hidden',
                        'label' => $this->l('Customer'),
                        'default' => 0,
                        'placeholder' => $this->l('Search customer by id, firstname, lastname, email'),
                        'required' => true,
                        'col' => 9,
                        'search' => true,
                        'class' => 'ets',
                    )
                ) : array()
                , !$this->isStaff()
                ? array(
                    'customer_name' => array(
                        'name' => 'customer_name',
                        'type' => 'text',
                        'label' => $this->l('Name'),
                        'required' => true,
                        'validate' => 'isCatalogName',
                        'readonly' =>  $this->isGuest() ? false : true,
                        'disabled' =>  $this->isGuest() ? false : true,
                    ),
                    'customer_email' => array(
                        'name' => 'customer_email',
                        'type' => 'text',
                        'label' => $this->l('Email'),
                        'required' => true,
                        'validate' => 'isEmail',
                        'readonly' =>  $this->isGuest() ? false : true,
                        'disabled' =>  $this->isGuest() ? false : true,
                    )
                ) : array()
                , HDDefines::getInstance()->getTicketFields()
                , $column_fields
                , $this->isBackOffice(true)
                ? array(
                    'priority' => array(
                        'name' => 'priority',
                        'label' => $this->l('Priority'),
                        'type' => 'select',
                        'options' => array(
                            'query' => HDDefines::getInstance()->getOptionPriority(),
                            'id' => 'id',
                            'name' => 'name'
                        ),
                        'validate' => 'isCleanHtml',
                    ),
                    'status' => array(
                        'name' => 'status',
                        'label' => $this->l('Status'),
                        'type' => 'select',
                        'options' => array(
                            'query' => HDDefines::getInstance()->getOptionStatus(),
                            'id' => 'id',
                            'name' => 'name'
                        ),
                        'validate' => 'isCleanHtml',
                    )
                ) : array()
            );
        }

        return self::$cache_field_ticket;
    }

    const DEFAULT_MAX_SIZE = 104857600;

    public function validateFields($configs, $id_object = 0, $id_lang_default = 0, $reCAPTCHA = false)
    {
        if (is_array($configs)
            && count($configs) > 0
        ) {
            if ($id_lang_default <= 0) {
                $id_lang_default = (int)Configuration::get('PS_LANG_DEFAULT');
            }
            foreach ($configs as $key => $config) {
                
                if (isset($config['lang']) && $config['lang']) {
                    $val_default = trim(Tools::getValue($key . '_' . $id_lang_default));
                    if (isset($config['required']) && $config['required'] && $config['type'] != 'switch' &&  $val_default== '') {
                        $this->_errors[] = $config['label'] . ' ' . $this->l('is required');
                    }
                    if($val_default!='')
                    {
                        if (isset($config['size']) && $config['size'] && Tools::strlen($val_default) > (int)$config['size']) {
                            $this->_errors[] = sprintf($this->l('%s maximum %d characters'),$config['label'], (int)$config['size']);
                        }
                    }
                } elseif (isset($config['type']) && $config['type'] != 'file') {
                    if (isset($config['required'])
                        && $config['required']
                        && (!isset($config['disabled']) || !$config['disabled'])
                        && $config['type'] != 'switch'
                        && ((!isset($config['multiple']) || !$config['multiple']) && trim(Tools::getValue($key)) == '' || isset($config['multiple']) && $config['multiple'] > 0 && (!is_array(Tools::getValue($key)) || !count(Tools::getValue($key))))
                    ) {
                        $required = true;
                        if (isset($config['condition'])
                            && is_array($config['condition'])
                            && count($config['condition']) > 0
                        ) {
                            foreach ($config['condition'] as $id => $condition) {
                                $value = Tools::getValue($id);
                                if (!is_array($condition)) {
                                    $required &= (trim($value) == trim($condition));
                                } elseif (count($condition) > 0) {
                                    foreach ($condition as $cond) {
                                        if (isset($cond['operator']) && trim($cond['operator']) !== '') {
                                            switch (trim($cond['operator'])) {
                                                case 'in_array':
                                                    $required &= is_array($value) && count($value) > 0 && in_array($cond['value'], $value);
                                                    break;
                                                case '>=':
                                                    $required &= $value >= $cond['value'];
                                                    break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if ($required)
                            $this->_errors[] = $config['label'] . ' ' . $this->l('is required');
                    } elseif (isset($config['regex'])
                        && $config['regex']
                        && (!isset($config['multiple']) || !$config['multiple'])
                        && ($field_value = Tools::getValue($key))
                        && !is_array($field_value)
                        && trim($field_value) !== ''
                    ) {
                        foreach ($config['regex'] as $regex) {
                            if (isset($regex['bool'])
                                && isset($regex['pattern'])
                                && trim($regex['pattern']) !== ''
                            ) {
                                if ($regex['bool'] && !preg_match($regex['pattern'], trim($field_value)) || !$regex['bool'] && preg_match($regex['pattern'], trim($field_value))) {
                                    $this->_errors[] = $config['label'] . ' ' . (isset($regex['error']) ? $regex['error'] : $this->l('invalid'));
                                }
                            }
                        }
                    }
                    
                    elseif (isset($config['validate'])
                        && method_exists('HDValidate', $config['validate'])
                        && ($field_value = Tools::getValue($key))!==''
                        && (is_array($field_value) || trim($field_value) !== '')
                    ) {
                        $validate = trim($config['validate']);
                        $multiple = isset($config['multiple']) && $config['multiple'] > 0 ? 1 : 0;
                        
                        if (!$multiple && !is_array($field_value) && method_exists('HDValidate', $validate) && !HDValidate::$validate(trim($field_value))) {
                            $this->_errors[] = $config['label'] . ' ' . $this->l('is invalid');
                        } elseif ($multiple && is_array($field_value)) {
                            foreach ($field_value as $item) {
                                if (method_exists('HDValidate', $validate) && !HDValidate::$validate(trim($item))) {
                                    $this->_errors[] = $config['label'] . ' ' . $this->l('is invalid');
                                    break;
                                }
                            }
                        }
                        unset($validate);
                    } elseif (isset($config['multiple']) && $config['multiple'] > 0 || $config['type'] == 'checkbox') {
                        $field_value = Tools::getValue($key);
                        $options = isset($config['options']) && isset($config['options']['query']) && is_array($config['options']['query']) ? $config['options']['query'] : array();
                        $array_values = array();
                        if (count($options) > 0) {
                            foreach ($options as $option) {
                                $array_values[] = trim($option['title']);
                            }
                        }
                        if ($array_values
                            && is_array($field_value)
                            && count($field_value) > 0
                        ) {
                            foreach ($field_value as $val) {
                                if (!in_array(trim($val), $array_values)) {
                                    $this->_errors[] = $config['label'] . ' ' . $this->l('is invalid');
                                    break;
                                }
                            }
                        }
                    } elseif ($config['type'] !== 'checkboxes' && !Validate::isCleanHtml(trim(Tools::getValue($key)))) {
                        $this->_errors[] = $config['label'] . ' ' . $this->l('is invalid');
                    }
                    if (!$this->_errors && isset($config['size']) && $config['size'] && isset($config['field_type']) && trim($config['field_type']) !== '') {
                        $field_value = Tools::getValue($key);
                        switch (trim($config['field_type'])) {
                            case 'tinyint':
                            case 'int':
                                if ((int)$field_value > (int)$config['size']) {
                                    $this->_errors[] = sprintf($this->l('%s number is maximum is %d'),$config['label'], (int)$config['size']);
                                }
                                break;
                            case 'decimal':
                                if (is_array($config['size'])) {
                                    $number_split = explode('.', $field_value);
                                    if ($number_split[0] > (int)$config['size'][0]) {
                                        $this->_errors[] = sprintf($this->l('%s maximum partial int of number is is %d'),$config['label'], (int)$config['size'][0]);
                                    }
                                    if (isset($number_split[1]) && $number_split[1] > (int)$config['size'][1]) {
                                        $this->_errors[] = sprintf($this->l('%s maximum partial real of number is %d'), $config['label'],(int)$config['size'][1]);
                                    }
                                }
                                break;
                            default:
                                if (Tools::strlen($field_value) > (int)$config['size']) {
                                    $this->_errors[] =  sprintf($this->l('%s maximum %d characters'),$config['label'], (int)$config['size']);
                                }
                                break;
                        }
                    }
                } else {
                    $this->validateUploadFile($key, $config, $id_object, self::$ext_files, $this->_errors);
                }
            }
        }
        if ($reCAPTCHA) {
            $this->verifyReCAPTCHA();
        }
        if (count($this->_errors)) {
            $this->context->controller->errors = $this->_errors;
        }
    }

    static $ext_files = array('jpg', 'gif', 'jpeg', 'png', 'docx', 'doc', 'pdf', 'zip', 'xls', 'xlsx', 'mp4', 'zar');
    static $ext_image_files = array('jpg', 'gif', 'jpeg', 'png');

    public function validateUploadFile($key, $config, $id_object, $ext_files, &$_errors)
    {
        $upload_folder = isset($config['folder']) && trim($config['folder']) !== '' ? $config['folder'] : HDDefines::$default_upload;
        if (!is_dir($upload_folder)) {
            mkdir($upload_folder, 0755, true);
        }
        $post_content_size = HDTools::getServerVars('CONTENT_LENGTH');
        if (($post_max_size = HDTools::getPostMaxSizeBytes())
            && ($post_content_size > $post_max_size)
        ) {
            $_errors[] = sprintf($this->l('The uploaded file(s) exceeds the post_max_size directive in php.ini (%s > %s)'), $post_content_size, $post_max_size);
        } elseif (isset($config['required'])
            && $config['required']
            && (!isset($_FILES[$key]) || empty($_FILES[$key]['name']))
            && $id_object <= 0
        ) {
            $_errors[] = $config['label'] . ' ' . $this->l('is required');
        } elseif (!@is_writable($upload_folder) && !empty($_FILES[$key]['name'])) {
            $_errors[] = sprintf($this->l('The directory "%s" is not writable.', 'upload'), $upload_folder);
        } elseif (isset($_FILES[$key])
            && !empty($_FILES[$key]['name'])
        ) {
            if ($uploadError = $this->checkUploadError($_FILES[$key]['error'], $_FILES[$key]['name'])) {
                $_errors[] = $uploadError;
            } elseif ($_FILES[$key]['size'] > self::DEFAULT_MAX_SIZE) {
                $_errors[] = sprintf($this->l('File is too large. Current size is %1s, maximum size is %2s.'), $_FILES[$key]['size'], self::DEFAULT_MAX_SIZE);
            } elseif (isset($_FILES[$key]['name']) && $_FILES[$key]['name']) {
                if (!Validate::isFileName(HDTools::formatFileName($_FILES[$key]['name']))) {
                    $_errors[] = sprintf($this->l('File name "%s" is invalid'), $_FILES[$key]['name']);
                } else {
                    $type = Tools::strtolower(Tools::substr(strrchr($_FILES[$key]['name'], '.'), 1));
                    if (!in_array($type, $ext_files)) {
                        $_errors[] = sprintf($this->l('File "%s" type not allowed'), $_FILES[$key]['name']);
                    }
                }
            }
        }
    }

    public function verifyReCAPTCHA()
    {
        if (!(int)Configuration::get('ETS_HD_ALLOW_CAPTCHA') || (int)Configuration::get('ETS_HD_CUSTOMER_NO_CAPTCHA')) {
            return true;
        }
        if (Tools::getIsset('g-recaptcha-response')) {
            $reCAPTCHA = Tools::getValue('g-recaptcha-response');
            if (!$reCAPTCHA || !Validate::isCleanHtml($reCAPTCHA)) {
                $this->_errors[] = $this->l('reCAPTCHA is error');
            } else {
                $secret = Configuration::get('ETS_HD_RECAPTCHA_V' . (Configuration::get('ETS_HD_CAPTCHA_TYPE') != 'recaptcha_v3' ? '2' : '3') . '_SECRET_KEY');
                $http_build_query = http_build_query(array(
                    'secret' => $secret,
                    'response' => $reCAPTCHA
                ));
                $response = Tools::file_get_contents('https://www.google.com/recaptcha/api/siteverify?' . $http_build_query);
                $response = json_decode($response);
                if (!$response || (property_exists($response, 'success') && $response->success == false) || (property_exists($response, 'score') && $response->score < 0.5)) {
                    $this->_errors[] = $this->l('reCAPTCHA is invalid.');
                }
            }
        } else
            $this->_errors[] = $this->l('404 not found!');

        return !(count($this->_errors) > 0);
    }

    public function checkUploadError($error_code, $file_name)
    {
        $error = 0;
        switch ($error_code) {
            case 1:
                $error = sprintf($this->l('File "%1s" uploaded file exceeds %2s'), $file_name, ini_get('upload_max_filesize'));
                break;
            case 2:
                $error = sprintf($this->l('The uploaded file exceeds %s'), ini_get('post_max_size'));
                break;
            case 3:
                $error = sprintf($this->l('Uploaded file "%s" was only partially uploaded'), $file_name);
                break;
            case 6:
                $error = $this->l('Missing temporary folder');
                break;
            case 7:
                $error = sprintf($this->l('Failed to write file "%s" to disk'), $file_name);
                break;
            case 8:
                $error = sprintf($this->l('A PHP extension stopped the file "%s" to upload'), $file_name);
                break;
            default:
                break;
        }
        return $error;
    }

    public function isBackOffice($supper_admin = false)
    {
        return defined('_PS_ADMIN_DIR_') && isset($this->context->employee) && $this->context->employee->id > 0 && (!$supper_admin || $this->context->employee->id_profile = _PS_ADMIN_PROFILE_) ? 1 : 0;
    }

    public function isGrantedTicket($id_ets_hd_ticket, $return_bool = false)
    {
        if ($id_ets_hd_ticket > 0 &&
            Validate::isUnsignedInt($id_ets_hd_ticket) &&
            !HDTicket::isGranted($id_ets_hd_ticket, $this->context)
        ) {
            if ($return_bool)
                return false;
            if ($this->ajax) {
                $this->_errors[] = $this->l('Permission denied.');
                return false;
            } else
                $this->displayConfirm(6);
        }

        return true;
    }

    public function formTicket()
    {
        $configs = $this->getTicketFields();
        $ticket = array();
        $id_ets_hd_ticket = Tools::getValue('id_ets_hd_ticket');

        if (trim($id_ets_hd_ticket) !== ''
            && Validate::isUnsignedInt($id_ets_hd_ticket)
            && $id_ets_hd_ticket > 0
            && $this->isGrantedTicket($id_ets_hd_ticket)
        ) {
            $configs['id_ets_hd_ticket']['default'] = $id_ets_hd_ticket;
            $ticket = HDTicket::getTickets($id_ets_hd_ticket, 0, 0, 0, null, $this->context, $this->isStaff());
        }

        return $this->generalForm(
            'ets_hd_ticket',
            Configuration::get('ETS_HD_TICKET_TITLE', $this->context->language->id),
            array(
                'name' => 'submitAddTicket',
                'title' => $this->l('Submit'),
                'icon' => 'process-icon-save'
            ),
            $this->isBackOffice() ? array(
                'back_to_list' => array(
                    'name' => 'ets_hd_btn_back',
                    'title' => $this->l('Back to list'),
                    'href' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams()),
                    'icon' => 'svg_back',
                    'class' => 'btn btn-default'
                )
            ) : array()
            , $configs
            , $ticket
            , 'id_ets_hd_ticket'
            , $id_ets_hd_ticket
            , null
            , true
            , !$this->isStaff()
        );
    }

    public function generalForm($table, $form_title, $submit, $buttons, $configs, $object, $identity = null, $id_object = 0, $action = null, $has_config_form = false, $reCAPTCHA = false)
    {
        if (empty($configs) || !is_array($configs)) {
            return '';
        }
        $id_product = trim(Tools::getValue('id_product'));
        if (is_array($configs) && count($configs) > 0) {
            $date = true;
            $datetime = true;
            $autocomplete = true;
            foreach ($configs as $key => &$config) {
                if (trim($key) === 'id_product' && is_array($object)) {
                    $config['placeholder'] = $this->l('Search product by id, name, reference.');
                    $config['search'] = true;
                    $config['col'] = 9;
                    if (isset($object['id_product']) && $object['id_product'] > 0 || $id_product !== '' && Validate::isUnsignedInt($id_product) && (int)$id_product > 0) {
                        $product = new Product(isset($object['id_product']) && $object['id_product'] > 0 ? $object['id_product'] : (int)$id_product, true, $this->context->language->id);
                        $image_cover = Product::getCover($product->id);
                        $config['product'] = array(
                            'id' => $product->id,
                            'name' => $product->name . ($product->reference ? ' (' . $product->reference . ')' : ''),
                            'cover' => !empty($image_cover['id_image']) ? $this->context->link->getImageLink($product->link_rewrite, $image_cover['id_image'], HDTools::getImageType('cart')) : HDPostProcess::getNoImageDefault(HDTools::getImageType('cart')),
                        );
                        $config['default'] = $product->id;
                    }
                } elseif (trim($key) === 'id_customer'
                    && $this->isStaff()
                    && is_array($object)
                    && (isset($object['id_customer']) && $object['id_customer'] > 0 || ($id_customer = trim(Tools::getValue('id_customer'))) !== '' && Validate::isUnsignedInt($id_customer) && (int)$id_customer > 0)
                ) {
                    $customer = new Customer(isset($id_customer) ? (int)$id_customer : $object['id_customer']);
                    $config['customer'] = array(
                        'id' => $customer->id,
                        'name' => $customer->firstname . ' ' . $customer->lastname,
                        'email' => $customer->email
                    );
                } elseif (trim($key) === 'order_ref'
                    && is_array($object)
                    && !$this->isStaff()
                    && ($order_ref = trim(Tools::getValue('order_ref'))) !== ''
                    && Validate::isReference($order_ref)
                    && HDTicket::orderReferenceAndEmail($order_ref, $this->context->customer->email)->id > 0
                ) {
                    $config['default'] = $order_ref;
                }
                elseif($key=='priority')
                {
                    $config['default'] = Configuration::get('ETS_HD_DEFAULT_PRIORITY');
                }
                elseif (trim($config['type']) == 'date') {
                    $config['class'] = 'datepicker';
                    if ($date) {
                        $this->context->controller->addJqueryUI(array('ui.slider', 'ui.datepicker'));
                        $date = false;
                    }
                } elseif (trim($config['type']) == 'datetime') {
                    $config['class'] = 'datetimepicker';
                    if ($datetime) {
                        if (!$this->isBackOffice()) {
                            $relativePath = 'jquery/plugins/timepicker/';
                            if (method_exists($this->context->controller, 'registerJavascript')) {
                                $relativePath = 'js' . DIRECTORY_SEPARATOR . $relativePath;
                                $this->context->controller->registerStylesheet('ets-js-jquery-plugins-timepicker', $relativePath . 'jquery-ui-timepicker-addon.css', array('media' => 'all', 'priority' => 100));
                                $this->context->controller->registerJavascript('ets-js-jquery-plugins-timepicker', $relativePath . 'jquery-ui-timepicker-addon.js', array('position' => 'bottom', 'priority' => 100));
                            } else {
                                $this->context->controller->addCSS(_PS_JS_DIR_ . $relativePath . 'jquery-ui-timepicker-addon.css');
                                $this->context->controller->addJS(_PS_JS_DIR_ . $relativePath . 'jquery-ui-timepicker-addon.js');
                            }
                        }
                        $datetime = false;
                    }
                } elseif (trim($config['type']) == 'file'
                    && $id_object > 0
                    && isset($object[$key])
                    && trim($object[$key]) !== ''
                ) {
                    $file_name = explode('|', $object[$key]);
                    $params = array(
                        'file' => $file_name[0],
                        'type' => 'ticket',
                        'name' => $key,
                        'id' => $id_object,
                    );
                    $config['file'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDDownload') . '&' . http_build_query($params) : HDLink::getInstance()->getDownloadLink($this->context->language->id, $params);
                    $config['file_name'] = isset($file_name[1]) ? $file_name[1] : '';
                    $config['file_dir'] = $file_name[0];
                }
                elseif(trim($config['type'])=='text')
                {
                    if( isset($config['is_contact_name']) &&  $config['is_contact_name'] &&  (isset($object['id_customer']) && $object['id_customer'] > 0 || ($id_customer = trim(Tools::getValue('id_customer'))) !== '' && Validate::isUnsignedInt($id_customer) && (int)$id_customer > 0))
                    {
                        $customer = new Customer(isset($id_customer) ? (int)$id_customer : $object['id_customer']);
                        $config['default'] = $customer->firstname.' '.$customer->lastname;
                    }
                    
                }
                if (isset($config['search']) && $config['search']) {
                    $config['class'] = 'autocomplete';
                    if ($autocomplete) {
                        $this->context->controller->addJqueryPlugin('autocomplete');
                        $autocomplete = false;
                    }
                }
            }
        }

        $fieldset = array(
            'form' => array(
                'legend' => array(
                    'title' => $form_title,
                    'icon' => 'icon-cogs',
                ),
                'input' => $configs,
                'submit' => $submit,
                'buttons' => $buttons,
            )
        );

        $tpl_vars = array(
            $identity => $id_object,
            'fieldset' => $fieldset,
            'fields_value' => $this->getFieldsValue($configs, isset($submit['name']) ? $submit['name'] : 'submitForm', $object, $id_object),
            'action' => $action,
            'PS_ATTACHMENT_MAXIMUM_SIZE' => HDTools::formatBytes(HDTools::getPostMaxSizeBytes()),
            'table' => $table,
            'reCAPTCHA' => $reCAPTCHA ? 1 : 0,
            'is_staff' => $this->isStaff(),
            'product_ref' => (int)$id_product,
        );

        $ets_hd_ticket_id = (int)Tools::getValue('ets_hd_ticket_id');
        if ($ets_hd_ticket_id > 0 && !count($this->_errors)) {
            $tpl_vars['list_ticket_link'] = HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams());
        }
        if ($has_config_form) {
            $tpl_vars['configs'] = $this->getConfigsTicket(false);
        }

        $this->smarty->assign($tpl_vars);

        return $this->display(__FILE__, 'bo-fo-form.tpl');
    }

    public function formMessage($id_ets_ticket = 0)
    {
        $configs = $this->getMessageFields();
        $object = new HDTicketMessage();

        return $this->generalForm(
            'ets_hd_ticket_message'
            , ''
            , array(
                'title' => $this->l('Post message'),
                'name' => 'submitAddMessage',
                'icon' => 'svg_envelop',
            )
            ,$this->isBackOffice() ? array(
                'back_to_list' => array(
                    'name' => 'ets_hd_btn_back',
                    'title' => $this->l('Back to list'),
                    'href' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams()),
                    'icon' => 'svg_back',
                    'class' => 'btn btn-default pull-left'
                )
            ):false
            , $configs
            , $object
            , 'id_ets_hd_ticket_message'
            , 0
            , $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query(array('id_ets_hd_ticket' => $id_ets_ticket)) : HDLink::getInstance()->getTicketLink($this->context->language->id, $this->extraParams(array('id_ets_hd_ticket' => $id_ets_ticket)))
            , true
        );
    }

    public function extraParams($params = array())
    {
        return $this->customer_staff > 0 ? array_merge($params, array('staff' => $this->customer_staff)) : $params;
    }

    public function getFieldsValue($configs, $submit_action, $object = null, $id_object = 0)
    {
        $fields_value = array();
        if (Tools::isSubmit($submit_action)) {
            if ($configs) {
                foreach ($configs as $key => $config) {
                    if($config['name']=='last_date')
                        $fields_value['last_date'] = date('Y-m-d H:i:s');
                    elseif($config['name']=='customer_name' && !$this->isStaff() && $this->context->customer->logged)
                        $fields_value['customer_name']   = $this->context->customer->firstname.' '.$this->context->customer->lastname;
                    elseif($config['name']=='customer_email' && !$this->isStaff() && $this->context->customer->logged)
                        $fields_value['customer_email']   = $this->context->customer->email;
                    else
                    {
                        if ($config['type'] == 'switch') {
                            $fields_value[$key] = trim(Tools::getValue($key)) !== '' ? 1 : 0;
                        } elseif (isset($config['type']) && $config['type'] == 'checkbox' || isset($config['multiple']) && $config['multiple']) {
                            $fields_value[$key] = Tools::getValue($key, array());
                        } else {
                            $fields_value[$key] = Tools::getValue($key);
                        }
                    }
                    
                }
            }
        } else {
            if ($configs) {
                foreach ($configs as $key => $config) {
                    if($config['name']=='last_date')
                        $fields_value['last_date'] = date('Y-m-d H:i:s');
                    elseif($config['name']=='customer_name' && !$this->isStaff() && $this->context->customer->logged)
                        $fields_value['customer_name']   = $this->context->customer->firstname.' '.$this->context->customer->lastname;
                    elseif($config['name']=='customer_email' && !$this->isStaff() && $this->context->customer->logged)
                        $fields_value['customer_email']   = $this->context->customer->email;
                    else
                    {
                        if (isset($config['type']) && $config['type'] == 'checkbox' || isset($config['multiple']) && $config['multiple']) {
                            $fields_value[$key] = $id_object > 0 ? (is_object($object) ? (isset($object->$key) && trim($object->$key) !== '' ? explode(PHP_EOL, $object->$key) : '') : (isset($object[$key]) && trim($object[$key]) !== '' ? explode(PHP_EOL, $object[$key]) : '')) : (isset($config['default']) && trim($config['default']) !== '' ? explode(PHP_EOL, $config['default']) : array());
                        } else {
                            $fields_value[$key] = $id_object > 0 ? (is_object($object) ? (property_exists($object, $key) && trim($object->$key) !== '' && $object->$key!='0000-00-00' && $object->$key!='0000-00-00 00:00:00' ? trim($object->$key) : '') : (isset($object[$key]) && trim($object[$key]) !== '' && $object[$key]!='0000-00-00' && $object[$key]!='0000-00-00 00:00:00' ? trim($object[$key]) : '')) : (isset($config['default']) && trim($config['default']) !== '' ? $config['default'] : '');
                        }
                    }
                }
            }
        }

        return $fields_value;
    }

    static $per_pages = array(
        5 => '',
        20 => '',
        50 => '',
        100 => '',
        300 => '',
        1000 => ''
    );

    static $min_per_page = 20;

    static $cache_fields_list_ticket;

    public function getFieldsListTicket()
    {
        if (!self::$cache_fields_list_ticket) {
            self::$cache_fields_list_ticket = array_merge(
                array(
                    'id_ets_hd_ticket' => array(
                        'name' => 'id_ets_hd_ticket',
                        'label' => $this->l('ID'),
                        'type' => 'text',
                        'filter' => 'a.id_ets_hd_ticket',
                        'class' => 'fixed-width-xs center hd_ticket_id',
                        'validate' => 'isUnsignedInt',
                    )
                ),
                array(
                    'last_message' => array(
                        'name' => 'last_message',
                        'label' => $this->l('Last message'),
                        'type' => 'text',
                        'class' => 'left',
                        'filter' => 'tm.message',
                        'class'=>'last_message',
                        'search' => false,
                        'orderby' => false,
                        'truncate' => 100,
                        'validate' => 'isCleanHtml',
                    )
                ),
                $this->isStaff() ? array(
                    'customer' => array(
                        'name' => 'customer',
                        'label' => $this->l('Customer'),
                        'type' => 'text',
                        'filter' => 'CONCAT(c.firstname, \' \', c.lastname, \' \', c.email)',
                        'class' => 'left hd_customer',
                        'customer_display' => true,
                        'havingFilter' => true,
                        //'validate' => 'isCleanHtml',
                    )
                ) : array(),
                $this->isBackOffice() ? array(
                    'order_ref' => array(
                        'name' => 'order_ref',
                        'label' => $this->l('Order ref'),
                        'type' => 'text',
                        'filter' => 'a.order_ref',
                        'class' => '',
                        'validate' => 'isCleanHtml',
                    )
                ) : array(),
                (int)Configuration::get('ETS_HD_PRODUCTS_IN_LIST_TICKET') ? array(
                    'product' => array(
                        'name' => 'product',
                        'label' => $this->l('Product'),
                        'type' => 'text',
                        'filter' => 'IF(p.reference != "", CONCAT(pl.name, " (", p.reference, ")"), pl.name)',
                        'class' => 'ticket_product',
                        'product_display' => true,
                        'validate' => 'isCleanHtml',
                    )
                ) : array(),
                HDColumn::getColumnFields($this->context, true, $this->isStaff()),
                $this->isStaff() ? array(
                    'staff_replied' => array(
                        'name' => 'staff_replied',
                        'label' => $this->l('Replied'),
                        'type' => 'select',
                        'list' => HDDefines::getInstance()->getStatusReply(),
                        'filter' => 'a.staff_replied',
                        'class' => 'center staff_replied',
                        'validate' => 'isUnsignedInt',
                    ),
                    'last_date_message' => array(
                        'name' => 'last_date_message',
                        'label' => $this->l('Last date message'),
                        'type' => 'datetime',
                        'filter' => 'tm.date_add',
                        'class' => 'last_date_message',
                        'havingFilter' => true,
                        'validate' => 'isDate',
                    ),
                ) : array(
                    'last_date_message' => array(
                        'name' => 'last_date_message',
                        'label' => $this->l('Last date message'),
                        'type' => 'datetime',
                        'filter' => 'tm.date_add',
                        'class' => 'last_date_message',
                        'havingFilter' => true,
                        'validate' => 'isDate',
                    ),
                ),
                array(
                    'priority' => array(
                        'name' => 'priority',
                        'label' => $this->l('Priority'),
                        'type' => 'select',
                        'list' => HDDefines::getInstance()->getOptionPriority(),
                        'filter' => 'a.priority',
                        'class' => 'priority center',
                        'validate' => 'isCleanHtml',
                    ),
                ),
                array(
                    'status' => array(
                        'name' => 'status',
                        'label' => $this->l('Status'),
                        'type' => 'select',
                        'list' => HDDefines::getInstance()->getOptionStatus(),
                        'filter' => 'a.status',
                        'class' => 'status center',
                        'validate' => 'isCleanHtml',
                    )
                )
            );
        }

        return self::$cache_fields_list_ticket;
    }

    static $filter_unique = 'ets_hd_ticket';

    public function cookieFilter($method = 'set', $value = null)
    {
        $cookie = self::$filter_unique . ($this->isBackOffice() ? '_employee_' . $this->context->employee->id : '_customer_' . $this->context->customer->id);
        switch ($method) {
            case 'set':
                $this->context->cookie->$cookie = $value;
                break;
            case 'get':
                return $this->context->cookie->$cookie;
            case 'unset':
                unset($this->context->cookie->$cookie);
                break;
            default:
                return false;
        }
        return true;
    }

    public function postFilter($fields_list)
    {
        $filter = array();
        if (Tools::isSubmit('submitFilter' . self::$filter_unique)) {
            if ($fields_list) {
                foreach ($fields_list as $key => $field) {
                    if (isset($field['search']) &&
                        !$field['search'] ||
                        !isset($field['filter']) ||
                        !$field['filter']
                    ) {
                        continue;
                    }
                    $validate = isset($field['validate']) && trim($field['validate']) !== '' && method_exists('Validate', trim($field['validate'])) ? trim($field['validate']) : 'isCleanHtml';
                    if (($field['type'] == 'select' || $field['type'] == 'radio')
                        && isset($field['list'])
                        && is_array($field['list'])
                    ) {
                        $value = trim(Tools::getValue(self::$filter_unique . '_' . $key));
                        if ($value !== '' && $validate !== '' && Validate::$validate($value) && HDTools::valueOfList($field['list'], 'id', $value)) {
                            $filter[$key] = array(
                                'rule' => $field['filter'] . '=\'' . pSQL($value) . '\'',
                                'value' => $value
                            );
                        } elseif ($value !== '')
                            $this->_errors[] = $field['name'] . ' ' . $this->l('is invalid');
                    } elseif (
                        $field['type'] == 'date' ||
                        $field['type'] == 'datetime'
                    ) {
                        $date = Tools::getValue(self::$filter_unique . '_' . $key);
                        if (is_array($date) && count($date) > 1) {
                            $array_values = array();
                            $rules = array();
                            if (trim($date[0]) !== '' && $validate !== '' && Validate::$validate($date[0])) {
                                $rules[] = $field['filter_key'] . '>=\'' . pSQL($date[0]) . '\'';
                                $array_values['from'] = $date[0];
                            } elseif (trim($date[0]) !== '')
                                $this->_errors[] = $field['name'] . ' ' . $this->l('is invalid');
                            if (trim($date[1]) !== '' && $validate !== '' && Validate::$validate($date[1]) && strtotime($date[1]) > strtotime($date[0])) {
                                $rules[] = $field['filter'] . '<=\'' . pSQL($date[1]) . '\'';
                                $array_values['to'] = $date[1];
                            } elseif (trim($date[1]) !== '')
                                $this->_errors[] = $field['name'] . ' ' . $this->l('is invalid');
                            if ($array_values) {
                                $filter[$key] = array(
                                    'rules' => $rules,
                                    'values' => $array_values
                                );
                            }
                        }
                    } else {
                        $value = trim(Tools::getValue(self::$filter_unique . '_' . $key));
                        if ($value !== '' && $validate !== '' && Validate::$validate($value)) {
                            $filter[$key] = array(
                                'rule' => $field['filter'] . ' LIKE \'%' . pSQL($value) . '%\'',
                                'value' => $value
                            );
                        } elseif ($value !== '')
                            $this->_errors[] = $field['name'] . ' ' . $this->l('is invalid');
                    }
                }
            }

            if ($this->_errors) {
                $this->context->controller->errors = $this->_errors;
            } elseif ($filter) {
                $this->cookieFilter('set', json_encode($filter));
            }
        } elseif (Tools::isSubmit('submitReset' . self::$filter_unique)) {
            $this->cookieFilter('unset');
        } elseif ($filter = $this->cookieFilter('get')) {
            $filter = @json_decode($filter, true);
        }
        return $filter;
    }

    static $cache_product;
    static $cache_customer;

    public function getTicketProperties(&$row, $fields = array(),$is_staff = null)
    {
        if ($fields) {
            foreach ($fields as $key => $field) {
                if (isset($row[$key]) && $row[$key]) {
                    if (isset($field['type']) && $field['type'] == 'file') {
                        if (($files = explode('|', $row[$key])) && count($files) > 1) {
                            $params = array(
                                'file' => trim($files[0]),
                                'type' => 'ticket',
                                'name' => $key,
                                'id' => $row['id_ets_hd_ticket']
                            );
                            if(!file_exists(_PS_DOWNLOAD_DIR_ . $this->name . '/'.$files[0]))
                            {
                                $row[$key . '_file_deleted'] = true;
                            }
                            else
                            {
                                if($is_staff===null)
                                    $row[$key . '_link_download'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDDownload') . '&' . http_build_query($params) : HDLink::getInstance()->getDownloadLink($this->context->language->id, $params);
                                elseif($is_staff)
                                {
                                    $row[$key . '_link_download'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDDownload') . '&' . http_build_query($params) : Tools::getShopDomainSsl(true) . Context::getContext()->shop->getBaseURI() . Configuration::get('ETS_HD_DIRECTORY_ADMIN_URL').'/index.php?'. http_build_query($params);
                                }
                                else
                                    $row[$key . '_link_download'] = HDLink::getInstance()->getDownloadLink($this->context->language->id, $params);
                            }
                            
                            $row[$key] = $files[1];
                        }
                    } elseif (isset($field['product_display']) && $field['product_display'] && isset($row['link_rewrite']) && trim($row['link_rewrite']) !== '') {
                        if (!isset(self::$cache_product[(int)$row['id_product']])) {
                            $product = new Product((int)$row['id_product']);
                            if ($product->id) {
                                $category = new Category($product->id_category_default, $this->context->language->id);
                                $link = $this->context->link->getProductLink($product, $row['link_rewrite'], $category->link_rewrite, $product->ean13, $this->context->language->id);
                                $cover = Product::getCover($product->id, $this->context);
                                $image = isset($cover['id_image']) && (int)$cover['id_image'] > 0 ? $this->context->link->getImageLink($row['link_rewrite'], (int)$cover['id_image'], HDTools::getImageType('home')) : '';
                                if($logo = HDTicket::getLogoProduct($row['id_product']))
                                    $image = $this->context->shop->getBaseURI() . $logo;
                                self::$cache_product[(int)$row['id_product']] = array($link, $image);
                            }
                        }
                        list($row['product_link'], $row['product_image']) = self::$cache_product[(int)$row['id_product']];
                    } elseif (isset($field['customer_display']) && $field['customer_display'] && isset($row['id_customer']) && $row['id_customer'] > 0 && $this->isBackOffice()) {
                        $row['customer_link'] = $this->ps17 ? $this->context->link->getAdminLink('AdminCustomers', true, array('route' => 'admin_customers_view', 'customerId' => (int)$row['id_customer'])) : $this->context->link->getAdminLink('AdminCustomers') . '&' . http_build_query(array('viewcustomer' => '', 'id_customer' => (int)$row['id_customer']));
                    }
                }
            }
        }
        $last_message = HDTicketMessage::getMessages(0, (int)$row['id_ets_hd_ticket'], 0, 0, 0, 'date_add.desc', $this->context, true);
        $row['last_date_message'] = isset($last_message['date_add']) ? $last_message['date_add'] : (isset($row['last_date_message']) ? $row['last_date_message'] :'');
        if($last_message && isset($last_message['attachment']) && $last_message['attachment'])
        {
            $this->getMessageProperties($last_message);
            if(isset($last_message['attachment_name']) && $last_message['attachment_name'])
            {
                $row['last_message_attachment_name'] = $last_message['attachment_name'];
                $row['last_message_attachment'] = $last_message['attachment'];
                $row['file_size'] = $last_message['file_size'];
                $row['file_deleted'] = isset($last_message['file_deleted']) ? $last_message['file_deleted']:false;
            }
            else
                $row['attachment'] = $last_message['attachment'];
        }
        if (isset($row['id_customer']) && $row['id_customer'] > 0) {
            $id_address = Address::getFirstCustomerAddressId($row['id_customer']);
            $country_and_state = Address::getCountryAndState($id_address);
            if (isset($country_and_state['id_country']) && (int)$country_and_state['id_country'] > 0) {
                $country = new Country((int)$country_and_state['id_country'], $this->context->language->id);
                $row['customer_country'] = $country->name;
            }
            $row['customer_verified'] = HDDataProvider::customerVerified($row['id_customer']);
            if ($this->isBackOffice()) {
                $row['customer_link'] = $this->ps17 ? $this->context->link->getAdminLink('AdminCustomers', true, array('route' => 'admin_customers_view', 'customerId' => (int)$row['id_customer'])) : $this->context->link->getAdminLink('AdminCustomers') . '&' . http_build_query(array('viewcustomer' => '', 'id_customer' => (int)$row['id_customer']));
            }
        }

        if (isset($row['customer'])) {
            $row['customer_name'] = $row['customer'];
        }

        return $row;
    }

    public function listTicket()
    {
        $this->context->controller->addCSS($this->_path . 'views/css/helpdesk.ticket.css');
        if ($confirm = trim(Tools::getValue('confirm'))) {
            switch ($confirm) {
                case 1:
                    $this->context->controller->success[] = $this->l('Successful deletion.');
                    break;
                case 2:
                    $this->context->controller->success[] = $this->l('Successful ticket closed.');
                    break;
                case 3:
                    $this->context->controller->success[] = $this->l('Successful creation.');
                    break;
                case 4:
                    $this->context->controller->success[] = $this->l('Successful update.');
                    break;
                case 5:
                    $this->context->controller->errors[] = $this->l('Ticket not found.');
                    break;
                case 6:
                    $this->context->controller->errors[] = $this->l('Permission denied ticket.');
                    break;
                case 7:
                    $this->context->controller->success[] = $this->l('Submit ticket successfull. Send email to admin fail');
                    break;
                case 8:
                    $this->context->controller->success[] = $this->l('Submit ticket successfull. Send email to customer fail');
                    break;
            }
            if ($this->isBackOffice() && isset($this->context->controller->success) && $this->context->controller->success) {
                $this->context->controller->confirmations = $this->context->controller->success;
            }
        }
        $p = Tools::getValue('p');
        if ($p <= 0 || !Validate::isUnsignedInt($p)) {
            $p = 1;
        }
        $n = Tools::getValue('n');
        if ($n <= 0 || !Validate::isUnsignedInt($n)) {
            $n = self::$min_per_page;
        }

        $fields_list = $this->getFieldsListTicket();
        if ($fields_list) {
            $date = true;
            foreach ($fields_list as $field) {
                if (trim($field['type']) == 'date') {
                    $field['class'] = 'datepicker';
                    if ($date) {
                        $this->context->controller->addJqueryUI('ui.datepicker');
                        $date = false;
                    }
                }
            }
        }
        $filter = $this->postFilter($fields_list);

        // Sort by validate:
        $sort_by = Tools::getValue('sort_by','last_date_message.desc');
        if (trim($sort_by) == '' || !Validate::isCleanHtml($sort_by) || !($sort_by_items = explode('.', $sort_by)) || !is_array($sort_by_items) || count($sort_by_items) < 1) {
            $order_by = 'a.date_add DESC';
        } else {
            if (!isset($sort_by_items[1]) || trim($sort_by_items[1]) == '' || !Validate::isSortDirection(Tools::strtoupper(trim($sort_by_items[1])))) {
                $sort_by_items[1] = 'ASC';
            } else
                $sort_by_items[1] = Tools::strtoupper(trim($sort_by_items[1]));
            if (!isset($sort_by_items[0]) || empty($fields_list) || !isset($fields_list[trim($sort_by_items[0])]) || !$fields_list[trim($sort_by_items[0])]) {
                $sort_by_items[0] = 'a.date_add';
            } else {
                $field = $fields_list[trim($sort_by_items[0])];
                if(trim($sort_by_items[0])=='product')
                {
                    $sort_by_items[0] ='pl.name';
                }
                else
                {
                    $alias = '';
                    if (isset($field['alias']) && trim($field['alias']) !== '') {
                        $alias = $field['alias'];
                    } elseif (!isset($field['havingFilter']) || !$field['havingFilter']) {
                        $alias = 'a';
                    }
                    $sort_by_items[0] = (trim($alias) !== '' ? $alias . '.' : '') . trim($sort_by_items[0]);
                }
                
            }
            $order_by = implode(' ', $sort_by_items);
        }

        $tickets = HDTicket::getTickets(0, 0, $p, $n, $order_by, $this->context, $this->isStaff(), $filter);
        
        $params = array(
            'rewrite' => Configuration::get('ETS_HD_' . ($this->customer_staff ? 'STAFF' : 'TICKET') . '_URL_ALIAS', $this->context->language->id)
        );
        if (trim($sort_by) !== '')
            $params['sort_by'] = $sort_by;
        if ($tickets) {
            foreach ($tickets as &$ticket) {
                $this->getTicketProperties($ticket, $fields_list);
                $paramUrls = array('id_ets_hd_ticket' => (int)$ticket['id_ets_hd_ticket']);
                $ticket['link'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query($paramUrls) : HDLink::getInstance()->getTicketLink($this->context->language->id, $this->extraParams($paramUrls));
                $ticket['is_granted'] = $this->isGrantedTicket($ticket['id_ets_hd_ticket'], $this->context);
                if ($this->isStaff() && HDDataProvider::getOrders((int)$ticket['id_customer'], trim($ticket['order_ref']), true, 0, 0, null, $this->context)) {
                    $paramUrls = array(
                        'id_customer' => (int)$ticket['id_customer'],
                        'order_ref' => trim($ticket['order_ref'])
                    );
                    $ticket['order_link'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDProcess') . '&' . http_build_query($paramUrls) : HDLink::getInstance()->getProcessLink($this->context->language->id, $paramUrls);
                    $ticket['has_product_expried'] = $this->isStaff()? Hook::exec('actionCheckLicenseExpried',array('id_customer'=>$ticket['id_customer'])):false;
                }
            }
        }
        $router_id = 'module-ets_helpdesk-' . ($this->customer_staff ? 'staff' : 'ticket') . 's';
        $total_records = HDTicket::getTickets(0, 1, 0, 0, null, $this->context, $this->isStaff(), $filter);
        $paginates = HDLink::getInstance()->getPagination($router_id, $total_records, $p, $n, !$this->isBackOffice() ? $params : array(), 1, $this->isBackOffice() ? 'AdminEtsHDTickets' : null);
        if (self::$per_pages) {
            foreach (array_keys(self::$per_pages) as $per_page) {
                $paramUrls = array('n' => $per_page, 'p' => 1);
                self::$per_pages[$per_page] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query($paramUrls) : HDLink::getInstance()->getPaginationLink($router_id, array_merge($params, $paramUrls), $this->context->language->id);
            }
        }
        $this->smarty->assign(array(
            'title' => $total_records > 1 ? $this->l('Ticket') : $this->l('Tickets'),
            'fields_list' => $fields_list,
            'tickets' => $tickets,
            'ticket_link' => $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') : HDLink::getInstance()->getTicketsLink($this->context->language->id, $this->extraParams()),
            'last_reload' => date('Y-m-d H:i:s'),
            'total_records' => $total_records,
            'show_footer_btn' => self::$min_per_page > 0 && ceil($total_records / self::$min_per_page) > 1,
            'paginates' => $paginates,
            'current_per_page' => $n,
            'list_per_pages' => self::$per_pages,
            'back_office' => $this->isBackOffice() ? 1 : 0,
            'is_staff' => $this->isStaff() ? 1 : 0,
            'table' => 'ets_hd_ticket',
            'current_sort_by' => $sort_by,
            'filter' => $filter,
            'ETS_HD_TIME_RELOAD_LIST_TICKET' => $this->isBackOffice() ? ((float)Tools::ps_round(Configuration::get('ETS_HD_TIME_RELOAD_LIST_TICKET'),2) ? :false) : ((float)Tools::ps_round(Configuration::get('ETS_HD_TIME_RELOAD_LIST_TICKET_FRONT'),2) ? :false),
            'has_bulk_actions' => true,
            'products_licenseBeforeExpried' => !$this->isStaff() ? Hook::exec('actionCheckLicenseBeforeExpried',array('id_customer'=>$this->context->customer->id,'list'=>true)):'',
            'products_licenseExpried' =>!$this->isStaff() ? Hook::exec('actionCheckLicenseExpried',array('id_customer'=>$this->context->customer->id,'list'=>true)):'',
            'bulk_actions' => array(
                'closed' => array(
                    'icon' => 'svg_check',
                    'text' => $this->l('Closed selected'),
                ),
                'delete' => array(
                    'icon' => 'svg_trash',
                    'text' => $this->l('Delete selected'),
                    'confirm' => $this->l('Do you want delete item selected?')
                )
            ),
        ));

        return $this->display(__FILE__, 'bo-fo-list.tpl');
    }
    public function ajaxProcessViewTickets()
    {
        if($id_ticket = (int)Tools::getValue('id_ticket'))
        {
            die(
                Tools::jsonEncode(
                    array(
                        'ticket_content' => $this->viewTicket($id_ticket),
                    )
                )
            );
        }
    }
    public function ajaxProcessLoadTicket()
    {
        $last_reload_ticket = Tools::getValue('last_reload_ticket');
        $current_date  = date('Y-m-d H:i:s');
        if($last_reload_ticket && Validate::isDate($last_reload_ticket))
        {
            $filter = array();
            $filter['last_date_message'] = array(
                            'rule' =>  'tm.date_add > "' . pSQL($last_reload_ticket) . '" OR a.date_add > "' . pSQL($last_reload_ticket) . '" ',
                            'value' => $last_reload_ticket
                        );
            $tickets = HDTicket::getTickets(0, 0, 0, 0, null, $this->context, $this->isStaff(), $filter);
            if($tickets)
            {
                $fields_list = $this->getFieldsListTicket();
                foreach($tickets as &$ticket)
                {
                    $this->getTicketProperties($ticket, $fields_list);
                    $paramUrls = array('id_ets_hd_ticket' => (int)$ticket['id_ets_hd_ticket']);
                    $ticket['link'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDTickets') . '&' . http_build_query($paramUrls) : HDLink::getInstance()->getTicketLink($this->context->language->id, $this->extraParams($paramUrls));
                    $ticket['is_granted'] = $this->isGrantedTicket($ticket['id_ets_hd_ticket'], $this->context);
                    if (HDDataProvider::getOrders((int)$ticket['id_customer'], trim($ticket['order_ref']), true, 0, 0, null, $this->context)) {
                        $paramUrls = array(
                            'id_customer' => (int)$ticket['id_customer'],
                            'order_ref' => trim($ticket['order_ref'])
                        );
                        $ticket['order_link'] = $this->isBackOffice() ? $this->context->link->getAdminLink('AdminEtsHDProcess') . '&' . http_build_query($paramUrls) : HDLink::getInstance()->getProcessLink($this->context->language->id, $paramUrls);
                        $ticket['has_product_expried'] = $this->isBackOffice() ? Hook::exec('actionCheckLicenseExpried',array('id_customer'=>$ticket['id_customer'])):false;
                    }
                    $this->smarty->assign(
                        array(
                            'ticket' => $ticket,
                            'fields_list' =>$fields_list,
                            'back_office' => $this->isBackOffice() ? 1 : 0,
                            'is_staff' => $this->isStaff() ? 1 : 0,
                            'has_bulk_actions' =>true,
                            'table' => 'ets_hd_ticket',
                        )
                    );
                    $status = HDDefines::getInstance()->getOptionStatus();
                    if(isset($status[$ticket['status']]))
                    {
                        $ticket['display_status'] = $status[$ticket['status']];
                    }
                    else
                        $ticket['display_status'] = false;
                    $ticket['row_content'] = $this->display(__FILE__,'bo-ticket-row.tpl');
                }
                die(Tools::jsonEncode(
                    array(
                        'tickets' => $tickets,
                        'current_date'=> $current_date,
                        'msg' => $this->l('Refresh successful'),
                    )
                ));
            }
            die(Tools::jsonEncode(
                array(
                    'tickets' => false,
                    'current_date'=> $current_date,
                    'msg' => $this->l('Refresh successful'),
                )
            ));
        }
    }
    public function ajaxProcessSearchTicket(){
        $filter = array();
        $search = Tools::getValue('search');
        $id_customer = (int)Tools::getValue('id_customer');
        if($search && Validate::isCleanHtml($search))
        {
           $filter['customer_name'] = array(
                'rule' =>  ' a.customer_name like "%' .pSQL($search). '%" OR a.customer_email like "%' . pSQL($search) .'%" OR CONCAT(c.firstname, \' \', c.lastname) like "%' . pSQL($search) .'%" OR a.id_ets_hd_ticket="'.(int)$search.'" OR c.email LIKE "%'.pSQL($search).'%"',
                'value' => $search
           ); 
        }
        if($id_customer)
        {
            $filter['customer_name'] = array(
                'rule' => 'a.id_customer='.(int)$id_customer,
                'value'=>$id_customer,
            );
        }
        $tickets = HDTicket::getTickets(0, 0, 0, 20, 'last_date_message desc', $this->context, $this->isStaff(), $filter);
        if($tickets)
        {
            foreach($tickets as &$ticket)
            {
                $this->getTicketProperties($ticket, array(),$this->isStaff());
                $ticket['last_date_message'] = $this->displayTimeByDate($ticket['last_date_message'],false);           
            } 
        }
        $this->smarty->assign(
            array(
                'list_tickets' => $tickets,
                'id_ets_hd_ticket' => (int)Tools::getValue('id_ticket'),
                'is_staff'=> $this->isStaff(),
            )
        );
        die(Tools::jsonEncode(
            array(
                'list_tickets' => $this->display(__FILE__,'left-list-tickets.tpl'),
            )
        ));
    }
    private function getConfigsTicket($js = true)
    {
        $fields = array();
        if ($configs = HDDefines::getInstance()->getConfigs()) {
            foreach ($configs as $key => $config) {
                if ($js && (!isset($config['js']) || !$config['js'])) {
                    continue;
                }
                if (isset($config['lang']) && $config['lang']) {
                    $fields[$key] = isset($config['global']) && $config['global'] ? Configuration::getGlobalValue($key, $this->context->language->id) : Configuration::get($key, $this->context->language->id);
                } elseif (isset($config['type']) && $config['type'] == 'checkbox' || isset($config['multiple']) && $config['multiple']) {
                    $value = isset($config['global']) && $config['global'] ? Configuration::getGlobalValue($key) : Configuration::get($key);
                    $fields[$key] = trim($value) !== '' ? implode(',', array_map('trim', explode(',', $value))) : '';
                } else {
                    $fields[$key] = isset($config['global']) && $config['global'] ? Configuration::getGlobalValue($key) : Configuration::get($key);
                }
            }
        }
        return $fields;
    }

    static $allow_download_type = array(
        'message',
        'ticket'
    );

    public function downloadFile()
    {
        list($filename, $type, $id, $key) = array(Tools::getValue('file'), Tools::getValue('type'), Tools::getValue('id'), Tools::getValue('name'));
        $params = array(
            'file' => $filename,
            'type' => $type,
            'id' => $id,
            'name' => $key,
        );
        if (!defined('_PS_ADMIN_DIR_') && ($this->context->customer->id <= 0 || !$this->context->customer->isLogged())) {
            Tools::redirect($this->context->link->getPageLink('authentication') . '?back=' . HDLink::getInstance()->getDownloadLink($this->context->language->id, $params));
        } elseif (defined('_PS_ADMIN_DIR_') && ($this->context->employee->id <= 0 || !$this->context->employee->isLoggedBack())) {
            Tools::redirectAdmin($this->context->link->getAdminLink('AdminLogin') . '&redirect=' . $this->context->link->getAdminLink('AdminEtsHDDownload') . '&' . http_build_query($params));
        }
        if (!isset($this->context->controller) || !($this->context->controller instanceof Ets_helpdeskDownloadModuleFrontController || $this->context->controller instanceof AdminEtsHDDownloadController)) {
            echo $this->l('Access file denied.');
            exit;
        }
        if (trim($filename) == '' ||
            !Validate::isFileName(HDTools::formatFileName($filename)) ||
            trim($id) == '' ||
            !Validate::isUnsignedInt($id) ||
            trim($type) == '' ||
            !Validate::isCleanHtml($type) ||
            !in_array($type, self::$allow_download_type)
        ) {
            echo $this->l('File name is not valid');
            exit;
        }
        $file_info = array();
        switch ($type) {
            case 'message':
                $file_info = HDTicketMessage::getMessages($id);
                break;
            case 'ticket':
                $file_info = HDTicket::getTickets($id,0,0,0,null,null,$this->isStaff());
                break;
        }

        $file = HDDefines::$default_upload . preg_replace('/\.{2,}/', '.', $filename);
        if (!is_file($file) || !$file_info || !isset($file_info[$key]) || $file_info[$key] == '') {
            echo $this->l('File does not exist2');
            exit;
        }

        if (!isset($file_info['id_ets_hd_ticket']) || !$file_info['id_ets_hd_ticket'] || !$this->isGrantedTicket((int)$file_info['id_ets_hd_ticket'])) {
            echo $this->l('Permission file denied.');
            exit;
        }

        $files = explode('|', $file_info[$key]);
        if (count($files) < 2 || trim($files[0]) !== trim($filename)) {
            echo $this->l('File is invalid');
            exit;
        }


        $filename = $files[1];
        /* Detect mime content type */
        $mimeType = false;
        if (function_exists('finfo_open')) {
            $finfo = @finfo_open(FILEINFO_MIME);
            $mimeType = @finfo_file($finfo, $file);
            @finfo_close($finfo);
        } elseif (function_exists('mime_content_type')) {
            $mimeType = @mime_content_type($file);
        } elseif (function_exists('exec')) {
            $mimeType = trim(call_user_func('exec', 'file -b --mime-type ' . call_user_func('escapeshellarg', $file)));
            if (!$mimeType) {
                $mimeType = trim(call_user_func('exec', 'file --mime ' . call_user_func('escapeshellarg', $file)));
            }
            if (!$mimeType) {
                $mimeType = trim(@call_user_func('exec', 'file -bi ' . call_user_func('escapeshellarg', $file)));
            }
        }

        if (empty($mimeType)) {
            $bName = basename($filename);
            $bName = explode('.', $bName);
            $bName = Tools::strtolower($bName[count($bName) - 1]);

            $mimeTypes = array(
                'ez' => 'application/andrew-inset',
                'hqx' => 'application/mac-binhex40',
                'cpt' => 'application/mac-compactpro',
                'doc' => 'application/msword',
                'oda' => 'application/oda',
                'pdf' => 'application/pdf',
                'ai' => 'application/postscript',
                'eps' => 'application/postscript',
                'ps' => 'application/postscript',
                'smi' => 'application/smil',
                'smil' => 'application/smil',
                'wbxml' => 'application/vnd.wap.wbxml',
                'wmlc' => 'application/vnd.wap.wmlc',
                'wmlsc' => 'application/vnd.wap.wmlscriptc',
                'bcpio' => 'application/x-bcpio',
                'vcd' => 'application/x-cdlink',
                'pgn' => 'application/x-chess-pgn',
                'cpio' => 'application/x-cpio',
                'csh' => 'application/x-csh',
                'dcr' => 'application/x-director',
                'dir' => 'application/x-director',
                'dxr' => 'application/x-director',
                'dvi' => 'application/x-dvi',
                'spl' => 'application/x-futuresplash',
                'gtar' => 'application/x-gtar',
                'hdf' => 'application/x-hdf',
                'js' => 'application/x-javascript',
                'skp' => 'application/x-koan',
                'skd' => 'application/x-koan',
                'skt' => 'application/x-koan',
                'skm' => 'application/x-koan',
                'latex' => 'application/x-latex',
                'nc' => 'application/x-netcdf',
                'cdf' => 'application/x-netcdf',
                'sh' => 'application/x-sh',
                'shar' => 'application/x-shar',
                'swf' => 'application/x-shockwave-flash',
                'sit' => 'application/x-stuffit',
                'sv4cpio' => 'application/x-sv4cpio',
                'sv4crc' => 'application/x-sv4crc',
                'tar' => 'application/x-tar',
                'tcl' => 'application/x-tcl',
                'tex' => 'application/x-tex',
                'texinfo' => 'application/x-texinfo',
                'texi' => 'application/x-texinfo',
                't' => 'application/x-troff',
                'tr' => 'application/x-troff',
                'roff' => 'application/x-troff',
                'man' => 'application/x-troff-man',
                'me' => 'application/x-troff-me',
                'ms' => 'application/x-troff-ms',
                'ustar' => 'application/x-ustar',
                'src' => 'application/x-wais-source',
                'xhtml' => 'application/xhtml+xml',
                'xht' => 'application/xhtml+xml',
                'zip' => 'application/zip',
                'au' => 'audio/basic',
                'snd' => 'audio/basic',
                'mid' => 'audio/midi',
                'midi' => 'audio/midi',
                'kar' => 'audio/midi',
                'mpga' => 'audio/mpeg',
                'mp2' => 'audio/mpeg',
                'mp3' => 'audio/mpeg',
                'aif' => 'audio/x-aiff',
                'aiff' => 'audio/x-aiff',
                'aifc' => 'audio/x-aiff',
                'm3u' => 'audio/x-mpegurl',
                'ram' => 'audio/x-pn-realaudio',
                'rm' => 'audio/x-pn-realaudio',
                'rpm' => 'audio/x-pn-realaudio-plugin',
                'ra' => 'audio/x-realaudio',
                'wav' => 'audio/x-wav',
                'pdb' => 'chemical/x-pdb',
                'xyz' => 'chemical/x-xyz',
                'bmp' => 'image/bmp',
                'gif' => 'image/gif',
                'ief' => 'image/ief',
                'jpeg' => 'image/jpeg',
                'jpg' => 'image/jpeg',
                'jpe' => 'image/jpeg',
                'png' => 'image/png',
                'tiff' => 'image/tiff',
                'tif' => 'image/tif',
                'djvu' => 'image/vnd.djvu',
                'djv' => 'image/vnd.djvu',
                'wbmp' => 'image/vnd.wap.wbmp',
                'ras' => 'image/x-cmu-raster',
                'pnm' => 'image/x-portable-anymap',
                'pbm' => 'image/x-portable-bitmap',
                'pgm' => 'image/x-portable-graymap',
                'ppm' => 'image/x-portable-pixmap',
                'rgb' => 'image/x-rgb',
                'xbm' => 'image/x-xbitmap',
                'xpm' => 'image/x-xpixmap',
                'xwd' => 'image/x-windowdump',
                'igs' => 'model/iges',
                'iges' => 'model/iges',
                'msh' => 'model/mesh',
                'mesh' => 'model/mesh',
                'silo' => 'model/mesh',
                'wrl' => 'model/vrml',
                'vrml' => 'model/vrml',
                'css' => 'text/css',
                'html' => 'text/html',
                'htm' => 'text/html',
                'asc' => 'text/plain',
                'txt' => 'text/plain',
                'rtx' => 'text/richtext',
                'rtf' => 'text/rtf',
                'sgml' => 'text/sgml',
                'sgm' => 'text/sgml',
                'tsv' => 'text/tab-seperated-values',
                'wml' => 'text/vnd.wap.wml',
                'wmls' => 'text/vnd.wap.wmlscript',
                'etx' => 'text/x-setext',
                'xml' => 'text/xml',
                'xsl' => 'text/xml',
                'mpeg' => 'video/mpeg',
                'mpg' => 'video/mpeg',
                'mpe' => 'video/mpeg',
                'qt' => 'video/quicktime',
                'mov' => 'video/quicktime',
                'mxu' => 'video/vnd.mpegurl',
                'avi' => 'video/x-msvideo',
                'movie' => 'video/x-sgi-movie',
                'ice' => 'x-conference-xcooltalk',
            );

            if (isset($mimeTypes[$bName])) {
                $mimeType = $mimeTypes[$bName];
            } else {
                $mimeType = 'application/octet-stream';
            }
        }

        if (ob_get_level() && ob_get_length() > 0) {
            ob_end_clean();
        }

        /* Set headers for download */
        header('Content-Transfer-Encoding: binary');
        header('Content-Type: ' . $mimeType);
        header('Content-Length: ' . filesize($file));
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        //prevents max execution timeout, when reading large files
        @set_time_limit(0);
        $fp = fopen($file, 'rb');

        if ($fp && is_resource($fp)) {
            while (!feof($fp)) {
                echo fgets($fp, 16384);
            }
        }

        exit;
    }
    public function renderList($listData)
    { 
        if(isset($listData['fields_list']) && $listData['fields_list'])
        {
            foreach($listData['fields_list'] as $key => &$val)
            {
                $value_key = (string)Tools::getValue($key);
                $value_key_max = (string)Tools::getValue($key.'_max');
                $value_key_min = (string)Tools::getValue($key.'_min');
                if(isset($val['filter']) && $val['filter'] && ($val['type']=='int' || $val['type']=='date'))
                {
                    if(Tools::isSubmit('ets_hd_submit_'.$listData['name']))
                    {
                        $val['active']['max'] =  trim($value_key_max);   
                        $val['active']['min'] =  trim($value_key_min); 
                    }
                    else
                    {
                        $val['active']['max']='';
                        $val['active']['min']='';
                    }  
                }  
                elseif(!Tools::isSubmit('del') && Tools::isSubmit('ets_hd_submit_'.$listData['name']))               
                    $val['active'] = trim($value_key);
                else
                    $val['active']='';
            }
        }  
        if(!isset($listData['class']))
            $listData['class']='';  
        $this->smarty->assign($listData);
        return $this->display(__FILE__, 'list_helper.tpl');
    }
    public function getFilterParams($field_list,$table='')
    {
        $params = '';        
        if($field_list)
        {
            if(Tools::isSubmit('ets_hd_submit_'.$table))
                $params .='&ets_hd_submit_'.$table.='=1';
            foreach($field_list as $key => $val)
            {
                $value_key = (string)Tools::getValue($key);
                $value_key_max = (string)Tools::getValue($key.'_max');
                $value_key_min = (string)Tools::getValue($key.'_min');
                if($value_key!='')
                {
                    $params .= '&'.$key.'='.urlencode($value_key);
                }
                if($value_key_max!='')
                {
                    $params .= '&'.$key.'_max='.urlencode($value_key_max);
                }
                if($value_key_min!='')
                {
                    $params .= '&'.$key.'_min='.urlencode($value_key_min);
                } 
            }
            unset($val);
        }
        return $params;
    }
    public function displayText($content=null,$tag,$class=null,$id=null,$href=null,$blank=false,$src = null,$name = null,$value = null,$type = null,$data_id_product = null,$rel = null,$attr_datas=null)
    {
        $this->smarty->assign(
            array(
                'content' =>$content,
                'tag' => $tag,
                'tag_class'=> $class,
                'tag_id' => $id,
                'href' => $href,
                'blank' => $blank,
                'src' => $src,
                'attr_name' => $name,
                'value' => $value,
                'type' => $type,
                'data_id_product' => $data_id_product,
                'attr_datas' => $attr_datas,
                'rel' => $rel,
            )
        );
        return $this->display(__FILE__,'html.tpl');
    }
    public function displayPaggination($limit,$name)
    {
        $this->context->smarty->assign(
            array(
                'limit' => $limit,
                'pageName' => $name,
            )
        );
        return $this->display(__FILE__,'limit.tpl');
    }
    public function _installFieldDefault()
    {
        $default_fields = array(
            array(
                'name' => 'subject',
                'required' => 1,
                'type'=> 'text',
                'field_type' => 'varchar',
                'display_field'=> 0,
                'display_field_admin'=> 0,
                'active' => 1,
                'field_length' => '255',
                'title' => $this->l('Subject'),
                'title_lang' => 'Subject',
            ),
            array(
                'name' => 'message',
                'required' => 1,
                'type'=> 'textarea',
                'field_type' => 'text',
                'display_field'=> 0,
                'display_field_admin'=> 0,
                'active' => 1,
                'title' => $this->l('Message'),
                'title_lang' => 'Message',
            ),  
            array(
                'name' => 'file',
                'required' => 0,
                'type'=> 'file',
                'field_type' => 'varchar',
                'display_field'=> 0,
                'display_field_admin'=> 0,
                'active' => 1,
                'title' => $this->l('File'),
                'title_lang' => 'File',
                'field_length' => '200',
            ),  
        );
        $languages = Language::getLanguages(false);
        foreach($default_fields as $filed)
        {
            $column = new HDColumn();
            $column->name = $filed['name'];
            $column->required = $filed['required'];
            $column->type = $filed['type'];
            $column->field_type = $filed['field_type'];
            $column->display_field = $filed['display_field'];
            $column->display_field_admin = $filed['display_field_admin'];
            $column->active = $filed['active'];
            foreach($languages as $lang)
            {
                $column->title[$lang['id_lang']] = HDDefines::trans($filed['title_lang'],$lang,'ets_helpdesk') ?: $filed['title'] ;
            }
            if($column->add())
                HDTicket::addColumn($column->name, $column->field_type.(isset($filed['field_length']) && $filed['field_length'] ? ' (' . $filed['field_length'] . ')' : ''));
        }
        return true;
    }
    public function displayTimeByDate($date,$time = true)
    {
        if($time)
        {
            $time_text ='';
            $last_time = strtotime($date);
            $time = strtotime(date('Y-m-d H:i:s'))-$last_time;
            if($time > 86400)
                $time_text = Tools::displayDate($date,null,true);
            elseif($time)
            {
                if($hours =floor($time/3600))
                {
                    $time_text .= $hours.' '.$this->l('hours').' ';
                    $time = $time%3600;
                }
                elseif($minutes = floor($time/60))
                {
                    $time_text .= $minutes.' '.$this->l('minutes').' ';
                    $time = $time%60;
                }
                elseif($time)
                    $time_text .= $time.' '.$this->l('seconds').' ';
                $time_text .= $this->l('ago');
            }
            return $time_text;
        }
        else
        {
            $last_time = strtotime($date);
            $time = strtotime(date('Y-m-d H:i:s'))-$last_time;
            if ($time< 86400) {
                return  $this->l('Today') . ' ' . date('h:i A', $last_time); // h:i A
            } elseif ($time < 172800) {
                return $this->l('Yesterday') . ' ' . date('h:i A', $last_time);
            }
            else
                return Tools::displayDate($date,null,true);
        }        
        
    }
    public function getTicketLinkMailSendStaff($id_employee,$id_ticket,$id_lang=null)
    {
        if($id_employee)
        {
            if($this->isBackOffice())
                return $this->context->link->getAdminLink('AdminEtsHDTickets', true).'&id_ets_hd_ticket='.$id_ticket;
            else
                return Context::getContext()->shop->getBaseURI() . Configuration::get('ETS_HD_DIRECTORY_ADMIN_URL').'/index.php';
        }
        else
            return HDLink::getInstance()->getStaffLink($id_lang, array('id_ets_hd_ticket' => $id_ticket));
    }
    
}
