<?php

/**
 * 2007-2017 PrestaShop
 *
 * NOTICE OF LICENSE
 *
 * @author    Innovadeluxe SL
 * @copyright 2017 Innovadeluxe SL

 * @license   INNOVADELUXE
 */
if (!defined('_PS_VERSION_')) {
    return false;
}

if (!class_exists('InnovaTools_2_0_0')) {
    require_once(_PS_ROOT_DIR_ . '/modules/idxrcustomproduct/libraries/innovatools_2_0_0.php');
}

require_once(_PS_ROOT_DIR_ . '/modules/idxrcustomproduct/classes/IdxComponent.php');
require_once(_PS_ROOT_DIR_ . '/modules/idxrcustomproduct/classes/IdxConfiguration.php');
require_once(_PS_ROOT_DIR_ . '/modules/idxrcustomproduct/classes/IdxCustomizedProduct.php');

class IdxrCustomProduct extends Module
{

    public function __construct()
    {
        $this->name = 'idxrcustomproduct';
        $this->tab = 'checkout';
        $this->version = '1.4.2';
        $this->author_address = '0x899FC2b81CbbB0326d695248838e80102D2B4c53';
        $this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
        $this->author = 'Innovadeluxe';
        $this->innovatabs = "";
        $this->doclink = $this->name . "/doc/readme_en.pdf";
        $this->bootstrap = true;
        $this->es17 = version_compare(_PS_VERSION_, '1.7.0.0', '>');
        $this->module_key = 'ae42eb29e5226fd19f5ddfb42738599b';
        $this->new_id_configuration = false;
        $this->new_id_component = false;

        parent::__construct();

        if (!HookCore::getIdByName('actionAdminProductsListingResultsModifier')) {
            $hook_action = new Hook();
            $hook_action->name = 'actionAdminProductsListingResultsModifier';
            $hook_action->title = 'actionAdminProductsListingResultsModifier';
            $hook_action->description = 'actionAdminProductsListingResultsModifier';
            $hook_action->add();
        }

        $this->displayName = $this->l('Custom product');
        $this->description = $this->l('Create customization options for customizable products');
        $this->confirmUninstall = $this->l('If you uninstall this module will lose all the configuration already done, are you sure to uninstall? ');
    }

    public function install()
    {

        if (!HookCore::getIdByName('actionAdminMetaAfterWriteRobotsFile')) {
            $hook_action = new Hook();
            $hook_action->name = 'actionAdminMetaAfterWriteRobotsFile';
            $hook_action->title = 'actionAdminMetaAfterWriteRobotsFile';
            $hook_action->description = 'actionAdminMetaAfterWriteRobotsFile';
            $hook_action->add();
        }

        if (!HookCore::getIdByName('actionAdminProductsListingResultsModifier')) {
            $hook_action = new Hook();
            $hook_action->name = 'actionAdminProductsListingResultsModifier';
            $hook_action->title = 'actionAdminProductsListingResultsModifier';
            $hook_action->description = 'actionAdminProductsListingResultsModifier';
            $hook_action->add();
        }

        include(dirname(__FILE__) . '/sql/install.php');

        $default_img_type = ImageType::typeAlreadyExists('home_default');
        if ($default_img_type) {
            Configuration::updateValue(Tools::strtoupper($this->name) . '_PCIMGTYPE', (int) $default_img_type);
            Configuration::updateValue(Tools::strtoupper($this->name) . '_PCIMGTYPE', (int) $default_img_type);
            Configuration::updateValue(Tools::strtoupper($this->name) . '_PCIMGTYPE', (int) $default_img_type);
            Configuration::updateValue(Tools::strtoupper($this->name) . '_COVERID', '.js-qv-product-cover');
        }

        if ($this->es17) {
            $this->registerHook('displayOverrideTemplate');
        }

        return parent::install()
                && $this->registerHook('displayBackOfficeTop')
                && $this->registerHook('displayRightColumnProduct')
                && $this->registerHook('displayProductTab')
                && $this->registerHook('displayProductTabContent')
                && $this->registerHook('displayProductButtons')
                && $this->registerHook('displayFooterProduct')
                && $this->registerHook('displayShoppingCartFooter')
                && $this->registerHook('displayOrderDetail')
                && $this->registerHook('actionCartSave')
                && $this->registerHook('actionValidateOrder')
                && $this->registerHook('actionOrderReturn')
                && $this->registerHook('actionAdminMetaAfterWriteRobotsFile')
                && $this->registerHook('displayAdminOrder')
                && $this->registerHook('displayCustomerAccount')
                && $this->registerHook('displayHeader')
                && $this->registerHook('displayPDFInvoice')
                && $this->registerHook('actionAdminProductsListingResultsModifier')
                && $this->createAjaxController();
    }

    public function createAjaxController()
    {
        $exist = Db::getInstance()->getValue('Select id_tab from ' . _DB_PREFIX_ . 'tab where module = "' . pSQL($this->name) . '" and class_name = "AdminIdxrcustomproduct"');
        if ($exist) {
            return true;
        }
        $tab = new Tab();
        $tab->active = 1;
        $languages = Language::getLanguages(false);
        if (is_array($languages)) {
            foreach ($languages as $language) {
                $tab->name[$language['id_lang']] = $this->name;
            }
        }
        $tab->class_name = 'AdminIdxrcustomproduct';
        $tab->module = $this->name;
        $tab->id_parent = - 1;
        return (bool) $tab->add();
    }

    public function uninstall()
    {
        //include(dirname(__FILE__) . '/sql/uninstall.php');
        $this->removeAjaxController();
        Configuration::deleteByName(Tools::strtoupper($this->name) . '_CATEGORY');
        Configuration::deleteByName(Tools::strtoupper($this->name) . '_PCIMGTYPE');
        Configuration::deleteByName(Tools::strtoupper($this->name) . '_MIMGTYPE');
        Configuration::deleteByName(Tools::strtoupper($this->name) . '_TIMGTYPE');
        Configuration::deleteByName(Tools::strtoupper($this->name) . '_COVERID');
        return parent::uninstall();
    }

    public function removeAjaxController()
    {
        $tab_id = Tab::getIdFromClassName('AdminIdxrcustomproduct');
        $tab = new Tab($tab_id);
        $tab->delete();
    }

    public function getContent()
    {
        //$this->fixCategoryProductPosition();
        $output = $this->innovaTitle();
        $output .= $this->postProcess() . $this->renderForm();
        return $output;
    }

    public function postProcess()
    {
        $this->checkTables();
        $default_cat = (Configuration::get(Tools::strtoupper($this->name . '_CATEGORY')) || Tools::getValue('customizable_category'));
        $locked = true;
        if ($default_cat) {
            $locked = false;
        }
        Media::addJsDef(array('delete_option_query' => $this->l('Are you sure to delete this option?')));
        $url_ajax = '';
        if ($this->es17) {
            $url_ajax =  $this->context->link->getAdminLink('AdminIdxrcustomproduct', true, array(), array('ajax' => true));
        } else {
            $url_ajax =  $this->context->link->getAdminLink('AdminIdxrcustomproduct').'&ajax=true';
        }
        Media::addJsDef(
            array(
                'url_ajax' => $url_ajax,
                'confirm_text' => addslashes(htmlspecialchars($this->l('Are you sure to delete?'))),
                'empty_icon_text' => addslashes(htmlspecialchars($this->l('There are not any image uploaded for this component'))),
                'saved_text' => json_encode($this->l('Succesfully updated')),
                'alert_text' => $locked ? $this->l('Category not already selected') : false,
                'fu_success' =>  addslashes(htmlspecialchars($this->l('The file was uploaded successfully!'))),
                'fu_error' =>  addslashes(htmlspecialchars($this->l('There was an error during file upload!'))),
                'mod_back_url' => AdminController::$currentIndex . '&configure=' . $this->name,
                'token' => Tools::getAdminTokenLite('AdminModules')
            )
        );
        $this->context->controller->addjqueryPlugin('sortable');
        $this->context->controller->addJS(
            $this->_path . 'views/js/sortable.js',
            false
        );
        $this->context->controller->addjqueryPlugin('validate');
        $this->context->controller->addJS(
            $this->_path . 'views/js/back.js',
            false
        );
        if (Tools::isSubmit('submitModConfiguration')) {
            $id_category = Tools::getValue('customizable_category');
            Configuration::updateValue(Tools::strtoupper($this->name) . '_CATEGORY', (int) $id_category);
            $this->updateRobotsFile();
            $pc_image_type = Tools::getValue('pc_image_type');
            Configuration::updateValue(Tools::strtoupper($this->name) . '_PCIMGTYPE', (int) $pc_image_type);
            $mobile_image_type = Tools::getValue('mobile_image_type');
            Configuration::updateValue(Tools::strtoupper($this->name) . '_MIMGTYPE', (int) $mobile_image_type);
            $tablet_image_type = Tools::getValue('tablet_image_type');
            Configuration::updateValue(Tools::strtoupper($this->name) . '_TIMGTYPE', (int) $tablet_image_type);
            $coverimageid = Tools::getValue('coverimageid');
            Configuration::updateValue(Tools::strtoupper($this->name) . '_COVERID', $coverimageid);

            return $this->displayConfirmation($this->l('Configuration saved'));
        }
        if (Tools::isSubmit('submitConfiguration') || Tools::isSubmit('submitConfigurationStay')) {
            $name = Tools::getValue('addconftitle');
            $id_configuration = Tools::getValue('id_configuration');
            $this->new_id_configuration = $this->addConfiguration($name, $id_configuration);
            return $this->displayConfirmation($this->l('Configuration saved'));
        }
        if (Tools::isSubmit('submitUpdateFileConfiguration') || Tools::isSubmit('submitUpdateFileConfigurationStay')) {
            $id_component = (int) Tools::getValue('id_component');
            $file_size = (int) Tools::getValue('max_size');
            $post = Tools::getAllValues();
            $extensions = array();
            foreach ($post as $key => $value) {
                if (Tools::substr($key, 0, 4) === "ext_") {
                    $extensions[] = str_replace('ext_', '', $key);
                }
            }
            $this->updateOptionFile($id_component, $file_size, $extensions);
            return $this->displayConfirmation($this->l('Configuration saved'));
        }
        if (Tools::isSubmit('activeidxrcustomproduct_configurations')) {
            $id = Tools::getValue('id_configuration');
            $this->activeConfiguration($id);
            return $this->displayConfirmation($this->l('Configuration saved'));
        }
        if (Tools::isSubmit('submitComponent') || Tools::isSubmit('submitComponentStay')) {
            $languages = Language::getLanguages(false);
            $title = array();
            $description = array();
            foreach ($languages as $lang) {
                $title[$lang['id_lang']] = Tools::getValue('title_' . (int) $lang['id_lang']);
                $description[$lang['id_lang']] = Tools::getValue('description_' . (int) $lang['id_lang']);
            }
            $name = Tools::getValue('name');
            $type = Tools::getValue('type');
            $columns = Tools::getValue('columns');
            $id_component = $this->addComponent($name, $title, $description, $type, $columns);
            if ($id_component && isset($_FILES['icon']) && isset($_FILES['icon']['tmp_name']) && !empty($_FILES['icon']['tmp_name'])) {
                $this->saveComponentIcon($id_component);
            }
            return $this->displayConfirmation($this->l('Configuration saved'));
        }
        if (Tools::isSubmit('editComponent') || Tools::isSubmit('editComponentStay')) {
            $id_component = Tools::getValue('id_component');
            $component = new IdxComponent($id_component);
            $component->fillObject();
            $languages = Language::getLanguages(false);
            foreach ($languages as $lang) {
                $component->title_lang[$lang['id_lang']] = Tools::getValue('title_' . (int) $lang['id_lang']);
                $component->description_lang[$lang['id_lang']] = Tools::getValue('description_' . (int) $lang['id_lang']);
            }
            $component->name = Tools::getValue('name');
            $component->type = Tools::getValue('type');
            $component->optional = Tools::getValue('optional');
            $component->columns = Tools::getValue('columns');
            $component->zoom = Tools::getValue('zoom_icon');
            $component->color = Tools::getValue('component_color');
            $component->update();

//            $name = Tools::getValue('name');
//            $type = Tools::getValue('type');
//            $columns = Tools::getValue('columns');
//            $zoom_icon = Tools::getValue('zoom_icon');
//            $color = Tools::getValue('component_color');
//            $this->addComponent($name, $title, $description, $type, $columns, $id_component, $zoom_icon, $color);
//            if ($id_component && isset($_FILES['icon']) && isset($_FILES['icon']['tmp_name']) && !empty($_FILES['icon']['tmp_name'])) {
//                $this->saveComponentIcon($id_component);
//            }
            return $this->displayConfirmation($this->l('Configuration saved'));
        }
        if (Tools::isSubmit('deleteidxrcustomproduct_configurations')) {
            $id_configuration = Tools::getValue('id_configuration');
            $this->deleteConfiguration($id_configuration);
            return $this->displayConfirmation($this->l('Configuration deleted'));
        }
        if (Tools::isSubmit('deleteidxrcustomproduct_components') || Tools::isSubmit('deletecomponent')) {
            $id_component = Tools::getValue('id_component');
            $this->deleteComponent($id_component);
            return $this->displayConfirmation($this->l('Component deleted'));
        }
        if (Tools::isSubmit('submitCloneComponent')) {
            $id_component = Tools::getValue('component_source');
            $component = new IdxComponent($id_component);
            $this->new_id_component = $component->clone();
        }
        if (Tools::isSubmit('submitGenerateComponent')) {
            $id_product = Tools::getValue('product_source');
            $this->new_id_component = IdxComponent::generateFromProduct($id_product);
        }
    }

    public function checkTables()
    {
        $exist_addbasecol = Db::getInstance()->getValue('SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = "'._DB_PREFIX_.'idxrcustomproduct_configurations" AND column_name = "add_base";');
        if (!$exist_addbasecol) {
            Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'idxrcustomproduct_configurations ADD add_base tinyint(1) NOT NULL DEFAULT 1;');
        }
        $exist_discount = Db::getInstance()->getValue('SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = "'._DB_PREFIX_.'idxrcustomproduct_configurations" AND column_name = "discount";');
        if (!$exist_discount) {
            Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'idxrcustomproduct_configurations ADD discount tinyint(1) NOT NULL DEFAULT 0;');
            Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'idxrcustomproduct_configurations ADD discount_type varchar(255);');
            Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'idxrcustomproduct_configurations ADD discount_amount decimal(17,2);');
        }
        $exist_discount_createdas = Db::getInstance()->getValue('SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = "'._DB_PREFIX_.'idxrcustomproduct_configurations" AND column_name = "discount_createdas";');
        if (!$exist_discount_createdas) {
            Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'idxrcustomproduct_configurations ADD discount_createdas varchar(255);');
        }
        $exist_impact = Db::getInstance()->getValue('SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = "'._DB_PREFIX_.'idxrcustomproduct_components_opt_impact" AND column_name = "price_impact_type";');
        if (!$exist_impact) {
            Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'idxrcustomproduct_components_opt_impact ADD price_impact_type varchar(255) DEFAULT "fixed";');
            Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'idxrcustomproduct_components_opt_impact ADD price_impact_calc varchar(255);');
        }
    }

    public function hookDisplayRightColumnProduct($params)
    {
        return $this->display_customization($params, 'hookDisplayRightColumnProduct');
    }

    public function hookDisplayProductButtons($params)
    {
        return $this->display_customization($params, 'hookDisplayProductButtons');
    }

    public function hookdisplayProductTab($params)
    {
        return $this->display_customization($params, 'hookdisplayProductTab');
    }

    public function hookdisplayProductTabContent($params)
    {
        return $this->display_customization($params, 'hookdisplayProductTabContent');
    }

    public function hookDisplayFooterProduct($params)
    {
        return $this->display_customization($params, 'hookDisplayFooterProduct');
    }

    public function hookdisplayHeader($params)
    {
        if ($this->es17) {
            if ($this->context->controller->php_self == 'product') {
                $id_product = (int) Tools::getValue('id_product');
                $id_configuration = $this->getConfigurationByProduct($id_product);
                if ($id_configuration) {
                    $steps = $this->getConfigurationFront($id_configuration);
                    $block = preg_replace('/[ ]{2,}|[\t]|\r|\n/', ' ', $this->getToppriceBlock($id_product));
                    $top_price_block = Tools::jsonEncode($block);
                    Media::addJsDef(
                        array(
                            'idxcp_id_configuration' => $id_configuration,
                            'url_ajax' => $this->context->link->getModuleLink($this->name, 'ajax', array('ajax' => true)),
                            'send_text' => $this->l('Send to cart'),
                            'save_text' => $this->l('Save in my wishlist'),
                            'not_finish' => $this->l('You must fill all the customization options before to make the order'),
                            'next_text' => $this->l('Next'),
                            'finish_text' => $this->l('Finish'),
                            'show_topprice' => $steps['show_topprice'],
                            'toppriceblock' => $top_price_block,
                            'first_open' => $steps['first_open'],
                            'resume_open' => $steps['resume_open'],
                            'step_active' => $steps['step_active'],
                            'image_editor' => Tools::getValue('idxcpeditimages'),
                            'cover_image_id' => Configuration::get(Tools::strtoupper($this->name . '_COVERID'))
                        )
                    );

                    $favorite = Tools::getValue('icp');
                    if ($favorite) {
                        $this->applyfavorite(str_replace('_', '-', $favorite));
                    }
                    $this->context->controller->registerStylesheet('modules-idxcpfrontcss', 'modules/' . $this->name . '/views/css/17/front.css', ['media' => 'all', 'priority' => 150]);
                    $this->context->controller->registerJavascript('modules-idxcpfrontjs', 'modules/' . $this->name . '/views/js/front.js', ['position' => 'bottom', 'priority' => 150]);
                    $this->context->controller->registerStylesheet('modules-idxcpfront' . $steps['visualization'] . 'css', 'modules/' . $this->name . '/views/css/17/front_' . $steps['visualization'] . '.css', array('media' => 'all', 'priority' => 150));
                    $this->context->controller->registerJavascript('modules-idxcpfront' . $steps['visualization'] . 'js', 'modules/' . $this->name . '/views/js/front_' . $steps['visualization'] . '.js', array('position' => 'bottom', 'priority' => 150));

                    if ($steps['visualization'] == 'minified') {
                        $this->context->controller->registerStylesheet('modules-idxcpfront-bootstrap-select.min.css', 'modules/' . $this->name . '/views/css/bootstrap-select.min.css', array('media' => 'all', 'priority' => 150));
                        $this->context->controller->registerJavascript('modules-idxcpfront-bootstrap-select.min.js', 'modules/' . $this->name . '/views/js/bootstrap-select.min.js', array('position' => 'bottom', 'priority' => 150));
                    }

                    if (Tools::getValue('idxcpeditimages')) {
                        $this->context->controller->registerStylesheet('modules-idxcpslickcss', 'modules/' . $this->name . '/libraries/slick/slick.css', ['media' => 'all', 'priority' => 150]);
                        $this->context->controller->registerStylesheet('modules-idxcpslickcsstheme', 'modules/' . $this->name . '/libraries/slick/slick-theme.css', ['media' => 'all', 'priority' => 150]);
                        $this->context->controller->registerJavascript('modules-idxcpslickjs', 'modules/' . $this->name . '/libraries/slick/slick.min.js', ['position' => 'bottom', 'priority' => 150]);
                    }
                }
            } else if ($this->context->controller->php_self == 'cart') {
                $extra_info = $this->getExtraByContext();
                if (count($extra_info)) {
                    $json_extra_info = json_encode($extra_info, JSON_UNESCAPED_UNICODE);
                    Media::addJsDef(array('icp_extrainfo' => $json_extra_info));
                    $this->context->controller->registerStylesheet('modules-idxcpfront-cart.css', 'modules/' . $this->name . '/views/css/17/front_cart.css', array('media' => 'all', 'priority' => 150));
                    $this->context->controller->registerJavascript('modules-idxcpcartjs', 'modules/' . $this->name . '/views/js/icp_order17.js', array('position' => 'bottom', 'priority' => 150));
                }
            } else {
                $this->context->controller->addCSS($this->_path . 'views/css/16/front_header.css', 'all');
                Media::addJsDef(
                    array(
                        'url_ajax' => $this->context->link->getModuleLink($this->name, 'ajax', array('ajax' => true)),
                        'add_text' => $this->l('Customize'),
                        'show_conf_text' => $this->l('Show customization'),
                    )
                );
                $this->context->controller->registerStylesheet('modules-idxcpfront-idxopc.css', 'modules/' . $this->name . '/views/css/17/idxopc.css', array('media' => 'all', 'priority' => 150));
                $this->context->controller->registerJavascript('modules-idxcpajaxcartjs', 'modules/' . $this->name . '/views/js/icp_cart17.js', array('position' => 'bottom', 'priority' => 150));
            }
        } else {
            $custom_products = Db::getInstance()->executeS('Select products from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations;');
            foreach ($custom_products as &$prod) {
                if (isset($prod['products']) && $prod['products']) {
                    $prod['link'] = $this->context->link->getProductLink($prod['products']);
                }
            }
            Media::addJsDef(
                array(
                    'custom_products' => $custom_products,
                    'configure_text' => $this->l('Configure')
                )
            );
            $this->context->controller->addJS($this->_path . 'views/js/icp_cart16.js', false);
            if ($this->context->controller->php_self == 'order-opc' && isset($this->context->controller->name_module) && $this->context->controller->name_module == 'onepagecheckoutps') {
                $this->hookdisplayShoppingCartFooter($params);
            }
        }
    }

    public function display_customization($params, $hook = '')
    {
        $id_product = (int) Tools::getValue('id_product');
        $id_configuration = $this->getConfigurationByProduct($id_product, $hook);
        if ($id_configuration) {
            $steps = $this->getConfigurationFront($id_configuration);
            if (!$this->es17) {
                Media::addJsDef(
                    array(
                        'idxcp_id_configuration' => $id_configuration,
                        'url_ajax' => $this->context->link->getModuleLink($this->name, 'ajax', array('ajax' => true)),
                        'send_text' => $this->l('Send to cart'),
                        'save_text' => $this->l('Save in my wishlist'),
                        'not_finish' => $this->l('You must fill all the customization options before to make the order'),
                        'show_topprice' => $steps['show_topprice'],
                        'first_open' => $steps['first_open'],
                        'step_active' => $steps['step_active'],
                        'image_editor' => Tools::getValue('idxcpeditimages'),
                        'cover_image_id' => Configuration::get(Tools::strtoupper($this->name . '_COVERID'))
                    )
                );
                if ($steps['show_topprice']) {
                    $block = str_replace('"', '\"', preg_replace('/[ ]{2,}|[\t]|\r|\n/', ' ', $this->getToppriceBlock($id_product)));
                    $top_price_block = Tools::jsonEncode($block);
                    Media::addJsDef(array('toppriceblock' => $top_price_block));
                } else {
                    Media::addJsDef(array('toppriceblock' => ''));
                }
                $favorite = Tools::getValue('icp');
                if ($favorite) {
                    $this->applyfavorite(str_replace('_', '-', $favorite));
                }
                if (Tools::getValue('idxcpeditimages')) {
                    $this->context->controller->addCSS($this->_path . 'libraries/slick/slick.css', 'all');
                    $this->context->controller->addCSS($this->_path . 'libraries/slick/slick-theme.css', 'all');
                    $this->context->controller->addJS($this->_path . 'libraries/slick/slick.min.js',false);
                }
                $this->context->controller->addJS($this->_path . 'views/js/front.js', false);
                $this->context->controller->addJS($this->_path . 'views/js/front_' . $steps['visualization'] . '.js', false);
                $this->context->controller->addCSS($this->_path . 'views/css/16/front.css', 'all');
                $this->context->controller->addCSS($this->_path . 'views/css/16/front_' . $steps['visualization'] . '.css', 'all');
            }

            if ($steps['add_base']) {
                $base_price = Product::getPriceStatic($id_product, true, false);
                $base_price_wot = Product::getPriceStatic($id_product, false, false);
            } else {
                $base_price = 0;
                $base_price_wot = 0;
            }
            $product_name = ProductCore::getProductName($id_product);
            $favorite = Tools::getValue('icp');
            if ($favorite) {
                $steps['default_configuration'] = array();
                $favorite_default = explode(',', $favorite);
                $fav_array = array();
                foreach($favorite_default as  $fav) {                    
                    $fav_parts = explode('_',$fav);
                    $fav_array[$fav_parts[0]] = $fav_parts[1];                    
                }
                $steps['default_configuration'] = json_encode($fav_array);
            }
            if ($steps['default_configuration']) {
                $default = json_decode($steps['default_configuration'], true);
                foreach ($steps['components'] as &$component) {
                    if (array_key_exists($component['id_component'], $default)) {
                        switch ($default[$component['id_component']]) {
                            case -2:
                                break;
                            case -1:
                                unset($component['default_opt']);
                            default:
                                $component['default_opt'] = $default[$component['id_component']];
                                break;
                        }
                    }
                }
            }
            
            $this->smarty->assign(array(
                'steps' => $steps,
                'icp_price' => number_format($base_price, 2),
                'icp_price_formated'=> self::formatPrice($base_price),
                'icp_price_wo' => number_format($base_price_wot, 2),
                'icp_price_wo_formated' => self::formatPrice($base_price_wot),
                'product_name' => $product_name,
                'modules_dir' => _MODULE_DIR_,
                'opcion_img_dir' => _PS_IMG_ . $this->name . DIRECTORY_SEPARATOR . 'options' . DIRECTORY_SEPARATOR
            ));
            if ($steps['visualization'] == 'minified') {
                $this->context->controller->addCSS($this->_path . 'views/css/bootstrap-select.min.css', 'all');
                $this->context->controller->addJS($this->_path . 'views/js/bootstrap-select.min.js', false);
            }
            $imageeditor_modal = '';
            if (Tools::getValue('idxcpeditimages')) {
                $images = IdxConfiguration::getAllImages($id_configuration);
                $this->smarty->assign(array("conf_images" => $images));
                $imageeditor_modal = $this->display(__FILE__, 'views/templates/front/image_editor.tpl');
            }

            return $imageeditor_modal.$this->display(__FILE__, 'views/templates/front/' . ($this->es17 ? '17' : '16') . '/' . $steps['visualization'] . '/front_' . $steps['visualization'] . '.tpl');
        } else {
            return '';
        }
    }

    public function applyfavorite($favorite)
    {
        $fav_q = 'Select id_fav from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_fav '
            . 'where id_product = ' . (int) Tools::getValue('id_product')
            . ' and id_customer = ' . (int) $this->context->customer->id
            . ' and icp_code = "' . $favorite . '"';

        $fav_id = Db::getInstance()->getValue($fav_q);
        if ($fav_id !== false) {
            $extra_q = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra where id_fav = ' . (int) $fav_id . ';';
            $extra_values = Db::getInstance()->executeS($extra_q);
            if ($extra_values) {
                $extra = array();
                foreach ($extra_values as $value) {
                    $extra[$value['id_component']] = $value['extra'];
                }
                Media::addJsDef(array('extra_values' => $extra));
            }
        }
    }

    public function hookdisplayShoppingCartFooter($params)
    {
        if (!$this->es17) {
            $extra_info = $this->getExtraByContext();
            if (count($extra_info)) {
                $json_extra_info = json_encode($extra_info, JSON_UNESCAPED_UNICODE);
                Media::addJsDef(array('icp_extrainfo' => $json_extra_info));
                $this->context->controller->addCSS($this->_path . 'views/css/16/front_cart.css', 'all');
                $this->context->controller->addJS($this->_path . 'views/js/icp_order.js', false);
            }
        }
    }

    public function hookDisplayOverrideTemplate($param)
    {
        if (isset($this->context->controller->php_self) && !$this->context->controller->ajax && ($this->context->controller->php_self == 'cart')) {
            $this->context->controller->registerStylesheet('modules-idxcpfrontcss', 'modules/' . $this->name . '/views/css/17/front_cart.css', array('media' => 'all', 'priority' => 150));

            $extra_info = $this->getExtraByContext();
            if ($extra_info) {
                $extra_info_wid = array();
                foreach ($extra_info as $extra) {
                    $extra_info_wid[$extra['id_product']] = $extra['customization'];
                }
                $this->context->smarty->assign(array('extra_info' => $extra_info_wid));
                return $this->getTemplatePath('hookDisplayOverrideTemplateCart.tpl');
            }
        }
    }

    public function hookDisplayCustomerAccount($params)
    {
        $id_customer = $this->context->customer->id;
        if ($id_customer) {
            if ($this->es17) {
                return $this->display(__FILE__, '/views/templates/front/account_blockcustomproduct_17.tpl', $this->getCacheId());
            } else {
                return $this->display(__FILE__, '/views/templates/front/account_blockcustomproduct.tpl', $this->getCacheId());
            }
        }
    }

    public function hookActionCartSave($params)
    {
        if (isset($params['cart'])) {
            $products = $params['cart']->getProducts();
        } else {
            return;
        }
        $extra_info = array();
        $file_controller = $this->context->shop->physical_uri . $this->context->shop->virtual_uri . 'modules/' . $this->name . '/file_controller.php?key=';
        foreach ($products as $product) {
            if ($product['id_category_default'] == Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'))) {
                $data = array();
                $data['id_cart'] = $params['cart']->id;
                $data['id_product'] = $product['id_product'];
                $data['public'] = $product['description_short'];
                $sql = 'Select description from ' . _DB_PREFIX_ . 'product_lang where id_product = ' . (int) $product['id_product'];
                $data['private'] = Db::getInstance()->getValue($sql);
                $text_customization = $this->getExtraByCart($params['cart']->id, $product['id_product']);
                $this->addDiscount($product['id_product'], $params['cart']);
                foreach ($text_customization as $text) {
                    if ($text['target_name']) {
                        $data['private'] .= '<p>' . $text['title'] . ': <a href="' . $file_controller . $text['target_name'] . '" target="_blank">' . $text['extra'] . '</a></p>';
                        $data['public'] .= '<p>' . $text['title'] . ': <a href="' . $file_controller . $text['target_name'] . '" target="_blank">' . $text['extra'] . '</a></p>';
                    } else {
                        $data['private'] .= '<p>' . $text['title'] . ': ' . $text['extra'] . '</p>';
                        $data['public'] .= '<p>' . $text['title'] . ': ' . $text['extra'] . '</p>';
                    }
                }
                $extra_info[] = $data;
            }
        }
        $this->updateNotes($extra_info);
    }

    public function adjustStock($id_cart)
    {
        $cart = new Cart($id_cart);
        $products = $cart->getProducts();
        foreach ($products as $prod) {
            $idxproduct = new IdxCustomizedProduct($prod['id_product']);
            $icp_code = $idxproduct->getIcpCode();
            if ($icp_code) {
                $configuration = $idxproduct->getConfiguration();
                $attached_products = $idxproduct->getAttachedProducts();
                if ($attached_products) {
                    if ($configuration->breakdown_attachment === '1') {
                        foreach($attached_products as $attach_product) {
                            $cart->updateQty($attach_product['quantity'] * $prod['cart_quantity'], $attach_product['id_product'], $attach_product['id_product_attribute']);
                        }
                        $cart->deleteProduct($prod['id_product'], $prod['id_product_attribute']);
                        $cart->update();
                        $cart->getPackageList(true);
                    } else {
                        foreach($attached_products as $attach_product) {
                            $this->setQty((-1 * $attach_product['quantity'] * $prod['cart_quantity']) , $attach_product['id_product'], $attach_product['id_product_attribute']);
                        }
                    }
                }
            }
        }
    }

    public function addDiscount($id_product, $cart)
    {
        $idxproduct = new IdxCustomizedProduct($id_product);
        $icp_code = $idxproduct->getIcpCode();
        $id_original = $this->getProductoOriginal($id_product, $icp_code);
        $id_configuration = $this->getConfigurationByProduct($id_original);
        if ($id_configuration) {
            $conf = new IdxConfiguration($id_configuration, true);
            if ($conf->discount) {
                $discount_name = 'custompro_'.$id_product.'_'.$cart->id;
                $discount_amount = $conf->discount_amount;
                $product_price  = Product::getPriceStatic($id_product);
                if ($conf->discount_type == 'percentage') {
                    $discount_amount = $product_price * ($conf->discount_amount/100);
                }
                if ($conf->discount_createdas == 'cartrule') {
                    $id_cart_rule = $this->createCartRule($discount_name, $id_product, $cart, $discount_amount);
                    $cart->addCartRule($id_cart_rule);
                } else {
                    $this->createSpecificPrice($id_product, $cart, $discount_amount);
                }
            }
        }
        return false;
    }

    public function hookActionValidateOrder($params)
    {
        $sql_update = 'Update ' . _DB_PREFIX_ . 'idxrcustomproduct_notes set id_order = ' . (int) $params['order']->id . ' where id_cart = ' . (int) $params['cart']->id . ';';
        Db::getInstance()->execute($sql_update);
        return '';
    }

    public function hookActionOrderReturn($params)
    {
        //Tools::p('aumento de stock');
        //Tools::dieObject($params);
    }

    public function hookActionAdminMetaAfterWriteRobotsFile($params)
    {
        $id_category = (int) Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'));
        if ($this->es17) {
            $url = Category::getUrlRewriteInformation($id_category);
        } else {
            $url = Category::getUrlRewriteInformations($id_category);
        }
        fwrite($params['write_fd'], "# START Idxrcustomproduct disallow customized products\n");
        if (count($url) > 1) {
            foreach ($url as $lang_url) {
                fwrite($params['write_fd'], 'Disallow: /*' . Language::getIsoById($lang_url['id_lang']) . '/' . $lang_url['link_rewrite'] . "/\n");
                fwrite($params['write_fd'], 'Disallow: /*' . Language::getIsoById($lang_url['id_lang']) . '/' . $id_category . '-' . $lang_url['link_rewrite'] . "/\n");
            }
        } else {
            foreach ($url as $lang_url) {
                fwrite($params['write_fd'], 'Disallow: /' . $lang_url['link_rewrite'] . "/\n");
                fwrite($params['write_fd'], 'Disallow: /' . $id_category . '-' . $lang_url['link_rewrite'] . "/\n");
            }
        }
        fwrite($params['write_fd'], "# END Idxrcustomproduct\n");
    }

    public function hookActionAdminProductsListingResultsModifier($params)
    {
        $hidden_categories = Configuration::get(Tools::strtoupper($this->name) . '_CATEGORY');
        $id_shop = $this->context->shop->id;
        $products = Db::getInstance()->ExecuteS('SELECT id_product FROM ' . _DB_PREFIX_ . 'product_shop where active = 1 AND id_shop = ' . (int) $id_shop . ' AND id_category_default = ' . (int) $hidden_categories);
        $cust_prod = array();
        foreach ($products as $prod) {
            $cust_prod[] = $prod['id_product'];
        }

        $count = 0;
        if (isset($params['list'])) {
            foreach ($params['list'] as $key => $list_prod) {
                if (in_array($list_prod['id_product'], $cust_prod)) {
                    unset($params['list'][$key]);
                    $count ++;
                }
            }
            $params['list'] = array_values($params['list']);
            $params['list_total'] -= $count;
        }
        if (isset($params['products'])) {
            foreach ($params['products'] as $key => $list_prod) {
                if (in_array($list_prod['id_product'], $cust_prod)) {
                    unset($params['products'][$key]);
                    $count ++;
                }
            }
            $params['products'] = array_values($params['products']);
            $params['total'] -= $count;
        }
    }

    public function hookDisplayAdminOrder($params)
    {
        if (isset($params['id_order'])) {
            return $this->getPanelForOrder($params['id_order']);
        }
    }

    public function hookDisplayOrderDetail($params)
    {
        return $this->getPanelForOrder($params['order']->id, true);
    }

    public function hookDisplayPDFInvoice($params)
    {
        return $this->getPanelForOrder($params['object']->id_order);
    }

    public function updateRobotsFile()
    {
        $rb_file = _PS_ROOT_DIR_ . '/robots.txt';
        $text = Tools::file_get_contents($rb_file);
        $start = strpos($text, "# START Idxrcustomproduct disallow customized products\n");
        $end = strpos($text, "# END Idxrcustomproduct\n") + Tools::strlen("# END Idxrcustomproduct\n");
        $text_start = Tools::substr($text, 0, $start);
        $text_end = Tools::substr($text, $end);
        $new_text = $text_start . $text_end;

        $id_category = (int) Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'));

        if ($this->es17) {
            $cat = New Category($id_category);
            $langs = Language::getLanguages();
            $url = array();
            foreach ($langs as $lang) {
                $url[$lang['id_lang']]['id_lang'] = $lang['id_lang'];
                $url[$lang['id_lang']]['link_rewrite'] = $cat->getLink(null, $lang['id_lang']);
            }
        } else {
            $url = Category::getUrlRewriteInformations($id_category);
        }

        $new_text .= "# START Idxrcustomproduct disallow customized products\n";
        if (count($url) > 1) {
            foreach ($url as $lang_url) {
                $new_text .= 'Disallow: /*' . Language::getIsoById($lang_url['id_lang']) . '/' . $lang_url['link_rewrite'] . "/\n";
                $new_text .= 'Disallow: /*' . Language::getIsoById($lang_url['id_lang']) . '/' . $id_category . '-' . $lang_url['link_rewrite'] . "/\n";
            }
        } else {//TODO creo que esto tendri que ir sin foreach
            foreach ($url as $lang_url) {
                $new_text .= 'Disallow: /' . $lang_url['link_rewrite'] . "/\n";
                $new_text .= 'Disallow: /' . $id_category . '-' . $lang_url['link_rewrite'] . "/\n";
            }
        }
        $new_text .= "# END Idxrcustomproduct\n";

        file_put_contents($rb_file, $new_text);
    }

    public function renderForm()
    {
        return InnovaTools_2_0_0::adminTabWrap($this);
    }

    public function actualizarClones($clave = 'link_rewrite')
    {
        $id_shop = $this->context->shop->id;
        $sql = 'SELECT p.id_product, p.reference, p.ean13, p.upc, pl.name, pl.description, pl.link_rewrite FROM `' . _DB_PREFIX_ . 'product` p
        INNER JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (p.id_product = pl.id_product' . Shop::addSqlRestrictionOnLang('pl', $id_shop) . ') WHERE pl.description LIKE "%icp_code%"';
        if ($reg = Db::getInstance()->executeS($sql)) {
            foreach ($reg as $elemento) {
                preg_match_all('/(.*)icp_code\((.*)\)(.*)/', $elemento['description'], $pregmatch_result);
                $icp_code = isset($pregmatch_result[2]) && !empty($pregmatch_result[2]) ? $pregmatch_result[2][0] : null;
                if (!$icp_code) {
                    continue;
                }
                if ($this->getProductoOriginal($elemento['id_product'], $icp_code)) {
                    continue;
                }
                switch ($clave) {
                    case 'reference':
                        $where = ' AND p.reference LIKE "' . $elemento['reference'] . '"';
                        break;
                    case 'ean13':
                        $where = ' AND p.ean13 LIKE "' . $elemento['ean13'] . '"';
                        break;
                    case 'upc':
                        $where = ' AND p.upc LIKE "' . $elemento['upc'] . '"';
                        break;
                    case 'name':
                        $where = ' AND pl.name LIKE "' . $elemento['name'] . '"';
                        break;
                    case 'link_rewrite':
                    default:
                        $where = ' AND pl.link_rewrite LIKE "' . $elemento['link_rewrite'] . '"';
                        break;
                }
                $sql = 'SELECT p.id_product FROM `' . _DB_PREFIX_ . 'product` p
        INNER JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (p.id_product = pl.id_product' . Shop::addSqlRestrictionOnLang('pl', $id_shop) . ') WHERE 1' . $where . ' ORDER BY id_product ASC';
                $id_product = Db::getInstance()->getValue($sql);
                $datos = array(
                    'id_producto' => $id_product,
                    'id_clon' => $elemento['id_product'],
                    'icp_code' => $icp_code
                );
                Db::getInstance()->insert($this->name . '_clones', $datos);
            }
        }
    }

    public function helpGenerateForm()
    {
        $this->context->controller->addCSS($this->_path . 'views/css/back.css', 'all');
        return $this->renderModuleConfiguration();
    }

    public function renderConfigurationList()
    {
        $configurations = IdxConfiguration::getConfigurations();

        $fields_list = array(
            'id_configuration' => array('title' => $this->l('id'), 'id_configuration' => 'id_configuration', 'align' => 'left', 'width' => 30),
            'name' => array('title' => $this->l('name'), 'name' => 'name', 'align' => 'left', 'type' => 'text'),
            'active' => array('title' => $this->l('active'), 'active' => 'active', 'align' => 'center', 'type' => 'bool')
        );
        $helper = new HelperList();
        $helper->table = 'idxrcustomproduct_configurations';
        $helper->shopLinkType = '';
        $helper->simple_header = false;
        // Actions to be displayed in the "Actions" column
        $helper->actions = array('edit', 'delete');
        $helper->identifier = 'id_configuration';
        $helper->show_toolbar = false;
        $helper->title = $this->l('Configurations');
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
        return $helper->generateList($configurations, $fields_list);
    }

    public function renderComponentList()
    {
        $components = $this->getComponents();
        foreach ($components as &$comp) {
            switch ($comp['type']) {
                case 'sel':
                    $comp['type_l'] = $this->l('selector');
                    break;
                case 'sel_img':
                    $comp['type_l'] = $this->l('selector with image');
                    break;
                case 'text':
                    $comp['type_l'] = $this->l('text');
                    break;
                case 'textarea':
                    $comp['type_l'] = $this->l('textarea');
                    break;
                case 'file':
                    $comp['type_l'] = $this->l('file');
                    break;
                case 'product':
                    $comp['type_l'] = $this->l('product');
                    break;
                default:
                    $comp['type_l'] = $this->l('other');
                    break;
            }
        }
        $fields_list = array(
            'id_component' => array('title' => $this->l('id'), 'id_component' => 'id_component', 'align' => 'left', 'width' => 30),
            'name' => array('title' => $this->l('name'), 'name' => 'name', 'align' => 'left'),
            'type_l' => array('title' => $this->l('type'), 'type_l' => 'type_l', 'align' => 'left'),
            'title' => array('title' => $this->l('title'), 'title' => 'title', 'align' => 'left'),
            'description' => array('title' => $this->l('description'), 'description' => 'description', 'align' => 'left'),
        );
        $helper = new HelperList();
        $helper->shopLinkType = '';
        $helper->simple_header = false;
        // Actions to be displayed in the "Actions" column
        $helper->actions = array('edit', 'delete');
        $helper->identifier = 'id_component';
        $helper->show_toolbar = false;
        $helper->title = $this->l('Components');
        $helper->table = 'component';
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
        return $helper->generateList($components, $fields_list);
    }

    public function renderModuleConfiguration()
    {
        $categories = Category::getAllCategoriesName(null, $this->context->language->id, false);
        $image_types = ImageType::getImagesTypes();

        foreach($image_types as &$type) {
            $type['name'] .= ' '.$type['width'].'x'.$type['height'];
        }

        $fields_form = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('General Configuration'),
                    'icon' => 'icon-cogs'
                ),
                'input' => array(
                    array(
                        'type' => 'select',
                        'label' => $this->l('Customized category '),
                        'name' => 'customizable_category',
                        'options' => array(
                            'query' => $categories,
                            'id' => 'id_category',
                            'name' => 'name',
                        ),
                        'desc' => $this->l('The new customized product will be attached to this category, keep in mind that the first time that you change this configuration the category selected will be disallow in your robots.txt configuration'),
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Image size in pc'),
                        'name' => 'pc_image_type',
                        'options' => array(
                            'query' => $image_types,
                            'id' => 'id_image_type',
                            'name' => 'name',
                        ),
                        'desc' => $this->l('The module will resize product images to this size in pc'),
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Image size in mobile'),
                        'name' => 'mobile_image_type',
                        'options' => array(
                            'query' => $image_types,
                            'id' => 'id_image_type',
                            'name' => 'name',
                        ),
                        'desc' => $this->l('The module will resize product images to this size in mobile'),
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Image size in tablet'),
                        'name' => 'tablet_image_type',
                        'options' => array(
                            'query' => $image_types,
                            'id' => 'id_image_type',
                            'name' => 'name',
                        ),
                        'desc' => $this->l('The module will resize product images to this size in tablet'),
                    ),
                    array(
                        'type' => 'text',
                        'label' => $this->l('Cover image id'),
                        'lang' => false,
                        'name' => 'coverimageid',
                        'desc' => $this->l('If module don\'t change properly the image of the product check if this id is the image id in your theme.'),
                    ),

                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                )
            ),
        );

        $helper = new HelperForm();
        $helper->show_toolbar = false;
        $lang = new Language((int) Configuration::get('PS_LANG_DEFAULT'));
        $helper->default_form_language = $lang->id;
        $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
        $this->fields_form = array();

        $helper->identifier = $this->identifier;
        $helper->submit_action = 'submitModConfiguration';
        $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->tpl_vars = array(
            'fields_value' => $this->getConfigFieldsValues(),
            'languages' => $this->context->controller->getLanguages(),
            'id_language' => $this->context->language->id
        );

        return $this->display(__FILE__, 'views/templates/admin/module-info.tpl') . $helper->generateForm(array($fields_form));
    }

    public function renderFormAddConfiguration()
    {
        $id_configuration = Tools::getValue('id_configuration');
        if (!$id_configuration && $this->new_id_configuration) {
            $id_configuration = $this->new_id_configuration;
        }
        $this->context->controller->addCSS($this->_path . 'views/css/bootstrap-multiselect.css', 'all');
        $this->context->controller->addCSS($this->_path . 'views/css/uploadfile.css', 'all');
        $this->context->controller->addJS($this->_path . 'views/js/bootstrap-multiselect.js', false);
        $this->context->controller->addJS($this->_path . 'views/js/jquery.uploadfile.min.js', false);

        $categories = Category::getAllCategoriesName();

        $products = $this->getAllProductsNotCloned();
        $components = $this->getComponents();
        if ($id_configuration && !Tools::isSubmit('deleteidxrcustomproduct_configurations')) {
            $configuration = New IdxConfiguration($id_configuration, true);
            if ($configuration) {
                $components_selected = array();
                if ($configuration->components) {
                    foreach ($configuration->components as $sel) {
                        foreach ($components as $key => $comp) {
                            if ($comp['id_component'] == $sel) {
                                if ($sel) {
                                    $comp['constraints'] = IdxComponent::hasConstraint($comp['id_component'], $id_configuration);
                                    $components_selected[] = $comp;
                                    unset($components[$key]);
                                }
                            }
                        }
                    }
                }
            } else {
                $id_configuration = false;
                $components_selected = array();
            }
            $components_available = $components;
            if ($components_selected) {
                $ordered_array = array();
                while (!empty($components_selected)) {
                    $selected = array_shift($components_selected);
                    if (empty($selected['constraints'])) {
                        $ordered_array[] = $selected;
                    } else {
                        $max_position = false;
                        foreach ($selected['constraints'] as $cosnt) {
                            $parent_id = explode('_', $cosnt)[0];
                            foreach ($ordered_array as $key => $actal_comps) {
                                if ($actal_comps['id_component'] == $parent_id) {
                                    if ($max_position === false || $key > $max_position) {
                                        $max_position = $key;
                                        break;
                                    }
                                }
                            }
                        }
                        if ($max_position === false) {
                            if (isset($selected['attempts'])) {
                                $selected['attempts'] ++;
                            } else {
                                $selected['attempts'] = 1;
                            }
                            if ($selected['attempts'] < 3) {
                                $components_selected[] = $selected;
                            }
                        } else {
                            $max_position ++;
                            $head = array_slice($ordered_array, 0, $max_position, true);
                            $head[] = $selected;
                            $tail = array_slice($ordered_array, $max_position, count($ordered_array) - $max_position, true);
                            $ordered_array = array_merge($head, $tail);
                        }
                    }
                }
                $components_selected = $ordered_array;
            }
        } else {
            $components_selected = array();
            $components_available = $components;
        }

        $fields_form = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('Add a new Configuration'),
                    'icon' => 'icon-cogs'
                ),
                'input' => array(
                    array(
                        'type' => 'text',
                        'label' => $this->l('Configuration title'),
                        'lang' => false,
                        'name' => 'addconftitle',
                        'desc' => $this->l('Set the title for this configuration'),
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Position in product page'),
                        'name' => 'configuration_hook',
                        'options' => array(
                            'query' => array(
                                1 => array(
                                    'hook' => $this->es17 ? 'hookDisplayProductButtons' : 'hookDisplayRightColumnProduct',
                                    'name' => $this->l('Right column'),
                                ),
//                                2 => array(
//                                    'hook' => 'hookDisplayProductButtons',
//                                    'name' => $this->l('Product buttons'),
//                                ),
//                                3 => array(
//                                    'hook' => 'hookdisplayProductTab',
//                                    'name' => $this->l('Product tab'),
//                                ),
                                4 => array(
                                    'hook' => 'hookDisplayFooterProduct',
                                    'name' => $this->l('Product footer'),
                                )
                            ),
                            'id' => 'hook',
                            'name' => 'name',
                        ),
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Apply to this categories'),
                        'name' => 'configuration_categories[]',
                        'options' => array(
                            'query' => $categories,
                            'id' => 'id_category',
                            'name' => 'name',
                        ),
                        'multiple' => true,
                        'class' => 'multiselect_cat',
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Apply to this products'),
                        'name' => 'configuration_products[]',
                        'options' => array(
                            'query' => $products,
                            'id' => 'id_product',
                            'name' => 'name',
                        ),
                        'multiple' => true,
                        'class' => 'multiselect_prod',
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Type of visualization'),
                        'name' => 'configuration_vistype',
                        'options' => array(
                            'query' => array(
//                                0 => array(
//                                    'visualization_type' => '3D',
//                                    'visualization_name' => '3D rotation'
//                                ),
                                1 => array(
                                    'visualization_type' => 'accordion',
                                    'visualization_name' => $this->l('Accordion')
                                ),
                                2 => array(
                                    'visualization_type' => 'full',
                                    'visualization_name' => $this->l('By steps in cascade')
                                ),
                                3 => array(
                                    'visualization_type' => 'minified',
                                    'visualization_name' => $this->l('Drop-down selectors')
                                ),
//                                4 => array(
//                                    'visualization_type' => 'steps',
//                                    'visualization_name' =>  $this->l('By steps in slide')
//                                )
                            ),
                            'id' => 'visualization_type',
                            'name' => 'visualization_name',
                        ),
                    ),
                    array(
                        'type' => 'vistype_preview',
                        'label' => $this->l('Visualization preview'),
                        'name' => 'no_process',
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('First step open?'),
                        'name' => 'first_open',
                        'class' => 'accordion',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'first_open_on',
                                'value' => 1,
                                'label' => $this->l('Yes')
                            ),
                            array(
                                'id' => 'first_open_off',
                                'value' => 0,
                                'label' => $this->l('No')
                            )
                        ),
                        'desc' => $this->l('If set yes, the first option in accordion will be open when load the page')
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Keep resume tab always open?'),
                        'name' => 'resume_open',
                        'class' => 'accordion',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'resume_open_on',
                                'value' => 1,
                                'label' => $this->l('Yes')
                            ),
                            array(
                                'id' => 'resume_open_off',
                                'value' => 0,
                                'label' => $this->l('No')
                            )
                        ),
                        'desc' => $this->l('If set yes, the first option in accordion will be open when load the page')
                    ),
                    array(
                        'type' => 'color',
                        'label' => $this->l('Color of the component'),
                        'name' => 'color',
                        'desc' => $this->l('Change the color of the component background'),
                    ),
                    array(
                        'type' => 'color',
                        'label' => $this->l('Background colour resume'),
                        'name' => 'final_color',
                        'desc' => $this->l('Color for the resume container background'),
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Add product price as base?'),
                        'name' => 'add_base',
                        'class' => 't',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'add_base_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'add_base_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'desc' => $this->l('If is enable the price of product will be add as base price')
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Show additional cost in resume list?'),
                        'name' => 'show_increment',
                        'class' => 't',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'show_increment_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'show_increment_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'desc' => $this->l('If is enable the resume break down the additional cost by option')
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Show price and add to cart in top?'),
                        'name' => 'show_topprice',
                        'class' => 't',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'show_topprice_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'show_topprice_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'desc' => $this->l('If is enable will show the price and a add to cart button in the top of the page, the button will be inactive until finish the configuration')
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Use base product combinations?'),
                        'name' => 'productbase_component',
                        'class' => 't',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'productbase_component_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'productbase_component_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'desc' => $this->l('If is enable will add base product combinations as firsts stpeps of configuration')
                    ),
                    array(
                        'type' => 'sortable_lists',
                        'label' => $this->l('List of components'),
                        'name' => 'configuration_components[]',
                        'list_selected' => $components_selected,
                        'list_available' => $components_available,
                    ),
                    array(
                        'type' => 'hidden',
                        'name' => 'configuration_components_order'
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Enable configuration'),
                        'name' => 'active',
                        'class' => 't',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'active_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'active_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'desc' => $this->l('Enable or disable this configuration')
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Breakdown attached products'),
                        'name' => 'bdattachment',
                        'class' => 't',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'bdattachment_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'bdattachment_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'desc' => $this->l('After done the order the attached products will be show as a sepparated row in order')
                    ),
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Create discount'),
                        'name' => 'discount',
                        'class' => 't',
                        'is_bool' => true,
                        'values' => array(
                            array(
                                'id' => 'discount_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'discount_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                        'desc' => $this->l('When the customer customized the product will add to the cart the product with a discount')
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Type of discount'),
                        'name' => 'discount_type',
                        'options' => array(
                            'query' => array(
                                1 => array(
                                    'discount_type' => 'fixed',
                                    'discount_name' => $this->l('Fixed')
                                ),
                                2 => array(
                                    'discount_type' => 'percentage',
                                    'discount_name' => $this->l('Percentage')
                                )
                            ),
                            'id' => 'discount_type',
                            'name' => 'discount_name',
                        ),
                        'class' => 'discount_field',
                    ),
                    array(
                        'type' => 'text',
                        'label' => $this->l('Discount amount'),
                        'lang' => false,
                        'name' => 'discount_amount',
                        'class' => 'discount_field fixed-width-xl',
                    ),
                    array(
                        'type' => 'select',
                        'label' => $this->l('Create as cart rule or specific price'),
                        'name' => 'discount_createdas',
                        'options' => array(
                            'query' => array(
                                1 => array(
                                    'discount_createdas' => 'cartrule',
                                    'discount_name' => $this->l('Cart rule')
                                ),
                                2 => array(
                                    'discount_createdas' => 'specificprice',
                                    'discount_name' => $this->l('Specific price')
                                )
                            ),
                            'id' => 'discount_createdas',
                            'name' => 'discount_name',
                        ),
                        'class' => 'discount_field',
                    ),
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                )
            ),
        );

        if ($id_configuration && !Tools::isSubmit('deleteidxrcustomproduct_configurations')) {
            $fields_form['form']['input'][] = array(
                'type' => 'hidden',
                'lang' => false,
                'name' => 'id_configuration',
                'value' => (int) $id_configuration
            );
        }

        $helper = new HelperForm();
        $helper->show_toolbar = false;
        $lang = new Language((int) Configuration::get('PS_LANG_DEFAULT'));
        $helper->default_form_language = $lang->id;
        $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
        $this->fields_form = array();
        $helper->module = $this;
        $helper->identifier = $this->identifier;
        $helper->submit_action = 'submitConfiguration';
        $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        if ($id_configuration && !Tools::isSubmit('deleteidxrcustomproduct_configurations')) {
            $helper->tpl_vars = array(
                'fields_value' => $this->getConfigFieldsValues('configuration', $id_configuration),
                'languages' => $this->context->controller->getLanguages(),
                'id_language' => $this->context->language->id
            );
        } else {
            $helper->tpl_vars = array(
                'fields_value' => $this->getConfigFieldsValues(),
                'languages' => $this->context->controller->getLanguages(),
                'id_language' => $this->context->language->id
            );
        }
        $helper->back_url = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name . '&token=' . $helper->token;
        $helper->show_cancel_button = true;

        return $helper->generateForm(array($fields_form)) . $this->renderImageUploader($id_configuration) . $this->renderConstraintModal();
    }

    public function getAllProductsNotCloned($onlywithattributes = false)
    {
        $products = Product::getProducts($this->context->language->id, 0, 10000, "name", "ASC");
        foreach ($products as $key => $prod) {
            if ($prod['id_category_default'] == Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'))) {
                unset($products[$key]);
            }
            if ($onlywithattributes) {
                $has_attributes = Db::getInstance()->getValue('select id_product from ' . _DB_PREFIX_ . 'product_attribute where id_product = '.(int)$prod['id_product']);
                if (!$has_attributes) {
                    unset($products[$key]);
                }
            }
        }
        return $products;
    }

    public function renderImageUploader($id_configuration)
    {
        if ($id_configuration) {

            $configuration = new IdxConfiguration($id_configuration);
            $attached_products = $configuration->getProducts();
            if ($attached_products) {
                $product_id = array_shift($attached_products);
                $product = new Product($product_id,false,$this->context->language->id);
                $product_url = $this->getImageConfigurationUrl($product);
            }
            $this->smarty->assign(array(
                'id_configuration' => $id_configuration,
                'max_image_size' => (int) Configuration::get('PS_PRODUCT_PICTURE_MAX_SIZE'),
                'product_url' => $product_url
            ));
            return $this->display(__FILE__, "views/templates/admin/imageUploader_panel.tpl");
        }
    }

    public function getImageConfigurationUrl(Product $product)
    {
        $id_lang = Configuration::get('PS_LANG_DEFAULT', null, null, Context::getContext()->shop->id);

        if (!ShopUrl::getMainShopDomain()) {
            return false;
        }

        $is_rewrite_active = (bool) Configuration::get('PS_REWRITING_SETTINGS');
        if ($this->es17) {
            $preview_url = $this->context->link->getProductLink(
                $product,
                $product->link_rewrite,
                Category::getLinkRewrite($product->id_category_default, $this->context->language->id),
                null,
                $id_lang,
                (int) Context::getContext()->shop->id,
                0,
                $is_rewrite_active,
                false,
                false,
                array('idxcpeditimages' => true)
            );
        } else {
            $preview_url = $this->context->link->getProductLink(
                $product,
                $product->link_rewrite,
                Category::getLinkRewrite($product->id_category_default, $this->context->language->id),
                null,
                $id_lang,
                (int) Context::getContext()->shop->id
            );
            $preview_url = $preview_url.'?idxcpeditimages=true';
        }

        if (!$product->active) {
            $admin_dir = dirname($_SERVER['PHP_SELF']);
            $admin_dir = substr($admin_dir, strrpos($admin_dir, '/') + 1);
            $preview_url .= ((strpos($preview_url, '?') === false) ? '?' : '&') . 'adtoken=' . $this->token . '&ad=' . $admin_dir . '&id_employee=' . (int) $this->context->employee->id .'&idxcpeditimages=true';
        }

        return $preview_url;
    }

    public function renderConstraintModal()
    {
        return $this->display(__FILE__, "views/templates/admin/constraint_modal.tpl");
    }

    public function renderFormAddComponent()
    {
        $types = IdxComponent::getComponentTypes();
        $columns = IdxComponent::getComponentColumns();
        $fields_form = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('Add a new Component'),
                    'icon' => 'icon-cogs'
                ),
                'input' => array(
                    array(
                        'type' => 'text',
                        'label' => $this->l('Component name'),
                        'lang' => false,
                        'name' => 'name',
                        'desc' => $this->l('Set the internal name for this component'),
                    ),
                    array(
                        'type' => 'text',
                        'label' => $this->l('Component title'),
                        'lang' => true,
                        'name' => 'title',
                        'desc' => $this->l('Set the title for this component'),
                    ),
                    array(
                        'type' => 'text',
                        'label' => $this->l('Component description'),
                        'lang' => true,
                        'name' => 'description',
                        'desc' => $this->l('Set the description for this component'),
                    ),
                    array(
                        'type' => 'select',
                        'lang' => false,
                        'label' => $this->l('Type'),
                        'name' => 'type',
                        'desc' => $this->l('Enter the type of the component.'),
                        'options' => array(
                            'query' => $types,
                            'id' => 'id',
                            'name' => 'name'
                        )
                    ),
                    array(
                        'type' => 'select',
                        'lang' => false,
                        'label' => $this->l('Columns'),
                        'name' => 'columns',
                        'desc' => $this->l('Enter the amount of options per line.'),
                        'options' => array(
                            'query' => $columns,
                            'id' => 'id',
                            'name' => 'name'
                        )
                    ),
                    array(
                        'type' => 'file',
                        'label' => $this->l('Option Icon'),
                        'name' => 'icon',
                        'desc' => $this->l('Upload an icon for show just before option name'),
                    ),
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                )
            ),
        );

        $helper = new HelperForm();
        $helper->show_toolbar = false;
        $lang = new Language((int) Configuration::get('PS_LANG_DEFAULT'));
        $helper->default_form_language = $lang->id;
        $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
        $this->fields_form = array();

        $helper->identifier = $this->identifier;
        $helper->submit_action = 'submitComponent';
        $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->tpl_vars = array(
            'fields_value' => $this->getConfigFieldsValues(),
            'languages' => $this->context->controller->getLanguages(),
            'id_language' => $this->context->language->id
        );
        $helper->back_url = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name . '&token=' . $helper->token;
        $helper->show_cancel_button = true;

        $this->smarty->assign(array(
            'components' => $this->getComponents(),
            'products' => $this->getAllProductsNotCloned(true),
            'form_action_url' => $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name . '&token=' . $helper->token
        ));

        return $this->display(__FILE__, "views/templates/admin/component_clone.tpl").$helper->generateForm(array($fields_form));
    }

    public function renderEditComponent()
    {
        $id_component = Tools::getValue('id_component');
        if (!$id_component) {
            $id_component = $this->new_id_component;
        }
        $component = new IdxComponent($id_component, true);
        if ($component) {            
            return $this->editComponent($component);
        }
    }

    public function getConfigFieldsValues($update = null, $value = null)
    {
        $languages = Language::getLanguages(false);

        //Generic
        $fields = array();
        $fields['opt_name'] = $fields['description'] = $fields['title'] = array();
        $fields['addconftitle'] = '';
        foreach ($languages as $lang) {
            $fields['title'][$lang['id_lang']] = '';
            $fields['description'][$lang['id_lang']] = '';
            $fields['opt_name'][$lang['id_lang']] = '';
        }
        $fields['name'] = '';
        $fields['type'] = Tools::getValue('type');
        $fields['type'] = Tools::getValue('optional');
        $fields['zoom_icon'] = Tools::getValue('zoom_icon');
        $fields['columns'] = Tools::getValue('columns');
        $fields['sel_options'] = Tools::getValue('sel_options');
        $fields['configuration_categories[]'] = Tools::getValue('configuration_categories[]');
        $fields['configuration_products[]'] = Tools::getValue('configuration_products[]');
        $fields['configuration_components[]'] = Tools::getValue('configuration_components[]');
        $fields['configuration_vistype'] = Tools::getValue('configuration_vistype');
        $fields['first_open'] = 1;
        $fields['resume_open'] = 0;
        $fields['configuration_hook'] = Tools::getValue('configuration_hook');
        $fields['color'] = '#000000';
        $fields['component_color'] = '#000000';
        $fields['final_color'] = '#000000';
        $fields['customizable_category'] = Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'));
        $fields['pc_image_type'] = Configuration::get(Tools::strtoupper($this->name .'_PCIMGTYPE'));
        $fields['mobile_image_type'] = Configuration::get(Tools::strtoupper($this->name .'_MIMGTYPE'));
        $fields['tablet_image_type'] = Configuration::get(Tools::strtoupper($this->name .'_TIMGTYPE'));
        $fields['coverimageid'] = Configuration::get(Tools::strtoupper($this->name . '_COVERID'));
        $fields['configuration_components_order'] = Tools::getValue('configuration_components_order');
        $fields['active'] = false;
        $fields['bdattachment'] = false;
        $fields['add_base'] = true;
        $fields['show_increment'] = true;
        $fields['show_topprice'] = false;
        $fields['productbase_component'] = false;
        $fields['discount'] = false;
        $fields['discount_type'] = false;
        $fields['discount_amount'] = false;
        $fields['discount_createdas'] = false;
        //with a id
        if ($update) {
            switch ($update) {
                case 'component':
                    $component = $value;
                    if (isset($component)) {
                        foreach ($languages as $lang) {
                            $lang_query = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang where id_component = ' . (int) $component->id_component . ' and id_lang = ' . (int) $lang['id_lang'];                            
                            if ($result = Db::getInstance()->getRow($lang_query)) {
                                $fields['title'][$lang['id_lang']] = $result['title'];
                                $fields['description'][$lang['id_lang']] = $result['description'];
                            }
                        }
                        $fields['name'] = $component->name;
                        $fields['type'] = $component->type;
                        $fields['optional'] = $component->optional;
                        $fields['zoom_icon'] = $component->zoom;
                        $fields['component_color'] = $component->color;
                        $fields['columns'] = $component->columns;
                        $fields['id_component'] = $component->id_component;
                    }
                    break;
                case 'configuration':
                    if ($value) {
                        $configuration = new IdxConfiguration($value, true);
                        if ($configuration) {
                            $fields['addconftitle'] = $configuration->name;
                            $fields['id_configuration'] = $configuration->id_configuration;
                            $fields['configuration_categories[]'] = $configuration->categories;
                            $fields['configuration_products[]'] = $configuration->products;
                            $fields['configuration_components[]'] = $configuration->components;
                            $fields['configuration_vistype'] = $configuration->visualization;
                            $fields['first_open'] = $configuration->first_open;
                            $fields['resume_open'] = $configuration->resume_open;
                            $fields['configuration_hook'] = $configuration->hook;
                            $fields['color'] = $configuration->color;
                            $fields['final_color'] = $configuration->final_color;
                            $fields['configuration_components_order'] = $configuration->components_order;
                            $fields['active'] = $configuration->active;
                            $fields['bdattachment'] = $configuration->breakdown_attachment;
                            $fields['add_base'] = $configuration->add_base;
                            $fields['show_increment'] = $configuration->show_increment;
                            $fields['show_topprice'] = $configuration->show_topprice;
                            $fields['productbase_component'] = $configuration->productbase_component;
                            $fields['discount'] = $configuration->discount;
                            $fields['discount_type'] = $configuration->discount_type;
                            $fields['discount_amount'] = $configuration->discount_amount;
                            $fields['discount_createdas'] = $configuration->discount_createdas;
                        }
                    }
                    break;
            }
        }

        return $fields;
    }

    public function addConfiguration($name, $id_configuration = null)
    {
        $configuration = New IdxConfiguration($id_configuration);
        $configuration->name = $name;
        $configuration->categories = Tools::getValue('configuration_categories');
        $configuration->products = Tools::getValue('configuration_products');
        $configuration->components = Tools::getValue('configuration_components');
        $configuration->components_order = Tools::getValue('configuration_components_order');
        $configuration->visualization = Tools::getValue('configuration_vistype');
        $configuration->first_open = Tools::getValue('first_open');
        $configuration->resume_open = Tools::getValue('resume_open');
        $configuration->color = Tools::getValue('color');
        $configuration->final_color = Tools::getValue('final_color');
        $configuration->active = Tools::getValue('active');
        $configuration->hook = Tools::getValue('configuration_hook');
        $configuration->add_base = Tools::getValue('add_base');
        $configuration->show_increment = Tools::getValue('show_increment');
        $configuration->show_topprice = Tools::getValue('show_topprice');
        $configuration->productbase_component = Tools::getValue('productbase_component');
        $configuration->breakdown_attachment = Tools::getValue('bdattachment');
        $configuration->discount = Tools::getValue('discount');
        $configuration->discount_type = Tools::getValue('discount_type');
        $configuration->discount_amount = Tools::getValue('discount_amount');
        $configuration->discount_createdas = Tools::getValue('discount_createdas');
        return $configuration->update();
    }

    public function addComponent($name, $title, $description, $type, $columns = 12, $id_component = false, $zoom = false, $color = false)
    {
        $exist_sql = 'Select id_component from ' . _DB_PREFIX_ . 'idxrcustomproduct_components where name = "' . pSQL($name) . '"';
        $result = Db::getInstance()->getValue($exist_sql);
        if ($result && !$id_component) {
            return $result;
        } else {
            $data = array(
                'name' => pSQL($name),
                'type' => pSQL($type),
                'zoom' => (bool) $zoom,
                'color' => pSQL($color),
                'columns' => (int) $columns,
            );
            if (!$id_component) {
                Db::getInstance()->insert('idxrcustomproduct_components', $data);
                $component_id = Db::getInstance()->Insert_ID();
            } else {
                $where = 'id_component = ' . (int) $id_component;
                Db::getInstance()->update('idxrcustomproduct_components', $data, $where);
                $component_id = (int) $id_component;
            }

            foreach ($title as $lang => $titlel) {
                $ldata = array(
                    'id_component' => (int) $component_id,
                    'id_lang' => (int) $lang,
                    'title' => pSql($titlel),
                    'description' => pSql($description[$lang])
                );
                if (!$id_component) {
                    Db::getInstance()->insert('idxrcustomproduct_components_lang', $ldata);
                } else {
                    $where = 'id_component = ' . (int) $id_component . ' and id_lang = ' . (int) $lang;
                    Db::getInstance()->update('idxrcustomproduct_components_lang', $ldata, $where);
                }
            }
            return $component_id;
        }
    }

    public function addConstraint($configuration_id, $component_id, $constraint)
    {
        $sql = 'Select constraints_options from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations where id_configuration = ' . (int) $configuration_id;
        $actual_constraint = Db::getInstance()->getValue($sql);
        $constraint_array = explode(',', $actual_constraint);
        $new_constraint = $component_id . '@' . $constraint;
        if (!in_array($new_constraint, $constraint_array)) {
            $constraint_array[] = $new_constraint;
            $new_constraints = implode(',', $constraint_array);
            Db::getInstance()->update('idxrcustomproduct_configurations', array('constraints_options' => pSQL($new_constraints)), 'id_configuration = ' . (int) $configuration_id);
        } else {
            echo 'ya esta en el listado de restricciones';
        }
    }

    public function delConstraint($configuration_id, $component_id, $constraint)
    {
        $sql = 'Select constraints_options from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations where id_configuration = ' . (int) $configuration_id;
        $actual_constraint = Db::getInstance()->getValue($sql);
        $constraint_array = explode(',', $actual_constraint);
        $new_constraint = $component_id . '@' . $constraint;
        if (in_array($new_constraint, $constraint_array)) {
            $key = array_search($new_constraint, $constraint_array);
            unset($constraint_array[$key]);
            $new_constraints = implode(',', $constraint_array);
            Db::getInstance()->update('idxrcustomproduct_configurations', array('constraints_options' => pSQL($new_constraints)), 'id_configuration = ' . (int) $configuration_id);
        } else {
            echo 'no esta en el listado de restricciones';
        }
    }

    public function getConfigurationByProduct($id_product, $hook = '')
    {
        $configurations = IdxConfiguration::getConfigurations($hook);
        $categories = Product::getProductCategories($id_product);
        $id_configuration = false;

        foreach ($configurations as &$conf) {
            if ($conf['active'] == 0) {
                continue;
            }
            $conf['products'] = explode(',', $conf['products']);
            $conf['categories'] = explode(',', $conf['categories']);
            if (in_array($id_product, $conf['products'])) {
                $id_configuration = $conf['id_configuration'];
                break;
            } else {
                if (array_intersect($categories, $conf['categories'])) {
                    $id_configuration = $conf['id_configuration'];
                    break;
                }
            }
        }

        return $id_configuration;
    }

    public function getConfigurationFront($id_configuration)
    {
        $sql_components = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations where id_configuration = ' . (int) $id_configuration;
        $row = Db::getInstance()->getRow($sql_components);
        $components = explode(',', $row['components']);
        $customization = array();
        $customization['visualization'] = $row['visualization'];
        $customization['steps'] = count($components);
        $customization['components'] = array();
        $customization['final_color'] = $row['final_color'];
        $customization['add_base'] = $row['add_base'];
        $customization['show_increment'] = $row['show_increment'];
        $customization['show_topprice'] = $row['show_topprice'];
        $customization['productbase_component'] = $row['productbase_component'];
        $customization['first_open'] = $row['first_open'];
        $customization['resume_open'] = $row['resume_open'];
        $customization['default_configuration'] = $row['default_configuration'] ? $row['default_configuration'] : '';
        $customization['step_active'] = false;
        $customization['discount'] = $row['discount'];
        $customization['discount_type'] = $row['discount_type'];
        $customization['discount_amount'] = $row['discount_amount'];
        $tax_ratio = 100;

        if (isset($this->context->customer)) {
            $without_taxes = Group::getPriceDisplayMethod($this->context->customer->id_default_group);
        } else {
            $without_taxes = false;
        }
        $id_product = Tools::getValue('id_product');
        //if ($without_taxes != 1) {
            $tax_rate = Tax::getProductTaxRate($id_product);
            $tax_ratio += $tax_rate;
        //}

        $tax_ratio /= 100;
        $customization['without_taxes'] = $without_taxes;
        $customization['tax_ratio'] = $tax_ratio;

        if ($customization['productbase_component']) {
            $product_comp_id = IdxComponent::getComponentIdByProduct($id_product);
            if ($product_comp_id) {
                array_unshift($components , $product_comp_id);
            }
        }

        $constraints = $this->proccessConstraints($row['constraints_options']);
        foreach ($components as $id_component) {
            $comps = $this->getComponents($id_component, $id_configuration, true);
            if (!$comps) {
                continue;
            }
            foreach ($comps as $comp) {                
                $comp['options'] = json_decode($comp['json_values']);
                $comp['icon_exist'] = file_exists(_PS_MODULE_DIR_ . $this->name . '/img/icon/' . $id_component . '.png');
                if (strpos($comp['id_component'], '999') === false) {
                    if (!isset($comp['constraint'])) {
                        $comp['constraint'] = array();
                        foreach ($constraints as $constraint) {
                            if ($constraint['target'] == $id_component) {
                                $comp['constraint'][] = $constraint['source'];
                            }
                        }
                    }
                    if (isset($comp['options']->options)) {
                        foreach ($comp['options']->options as &$option) {
                            $option->img_ext = 'png';
                            $this->generateImpact($option, $without_taxes, $tax_ratio, $id_component, $id_product);
                        }
                    }
                } else {
                    if (isset($comp['options']->options)) {                        
                        foreach ($comp['options']->options as &$option) {
                            $option->img_ext = 'png';
                            $this->generateProductImpact($option, $without_taxes, $tax_ratio, $id_component);
                        }
                    }
                } 
                unset($comp['json_values']);
                $customization['components'][] = $comp;
            }
        }

        $customization['step_active'] = false;
        $values = array();
        $show_resume = true;
        foreach ($customization['components'] as &$comp) {
            $values[$comp['id_component']] = $comp['default_opt'];
            $visible = ($comp['default_opt'] >= 0) ? true : false;
            if ($visible && $comp['constraint']) {
                foreach ($comp['constraint'] as $constraint) {
                    $req_val = explode('_', $constraint);
                    if (!isset($values[$req_val[0]]) || $values[$req_val[0]] != $req_val[1]) {
                        $visible = false;
                    } else {
                        break;
                    }
                }
            }
            if ($comp['constraint'] && !$visible) {
                $comp['display'] = false;
            } else {
                $comp['display'] = true;
                if ($comp['default_opt'] == -1) {
                    $show_resume = false;
                }
            }
            if ($visible && $comp['default_opt'] < 0 && !$customization['step_active']) {
                $customization['step_active'] = $comp['id_component'];
            }
        }
        if ($show_resume && !$customization['step_active']) {
            $customization['step_active'] = 'resume';
        }
        return $customization;
    }

    public function generateImpact(&$option, $without_taxes, $tax_ratio, $id_component, $id_product)
    {
        $impact_query = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_opt_impact where id_component = ' . (int) $id_component . ' and id_option = ' . (int) $option->id;
        $result = Db::getInstance()->getRow($impact_query);
        $option->weight_impact = (float) $result['weight_impact'];
        $option->reference = $result['reference'];
        $attached_price = 0;
        if ($result['att_product'] && $result['att_product'] != 'none' && $result['att_qty']) {
            $prod_id = explode('_', $result['att_product']);
            $product_id = (int) $prod_id[0];
            $attr_id = isset($prod_id[1]) ? (int) $prod_id[1] : null;
            $qty = Product::getQuantity($product_id, $attr_id);
            $attached_price = Product::getPriceStatic($product_id, false, $attr_id);
            $product = new Product($product_id);
            $stock_management_active = Configuration::get('PS_STOCK_MANAGEMENT');
            $allow_shipping = true;
            if (isset($this->context->cart->id_address_delivery) && $this->context->cart->id_address_delivery) {
                $avalible_carriers = Carrier::getAvailableCarrierList($product, false, $this->context->cart->id_address_delivery);
                $allow_shipping = count($avalible_carriers);
            }
            if (!$stock_management_active || ($qty >= $result['att_qty'])) {
                $option->active = true;
                if (!$allow_shipping) {
                    $option->active = false;
                    $option->ofs_text = $this->l('No availabe carriers for this combination');
                }
            } else {
                $option->active = false;
                $option->ofs_text = $product->available_later[$this->context->language->id];
            }
            $option->tax = (($product->getTaxesRate()) / 100) + 1;
        } else {
            $option->active = true;
            $option->tax = false;
        }
        if ($id_product && $result['price_impact_type'] == 'calculated' && $result['price_impact_calc']) {
            $equation = $result['price_impact_calc'];
            $base_price = Product::getPriceStatic($id_product, true);
            $search  = array('[BasePrice]', '[AttachedProductPrice]', '[AttachedProductQuantity]');
            $replace = array($base_price, $attached_price, $result['att_qty']);
            $toexecute = str_replace($search, $replace, $equation);
            $result['price_impact'] = eval('return '.$toexecute.';');
        }
        $option->price_impact = (float)($without_taxes?$result['price_impact']/$tax_ratio:$result['price_impact']);
    }
    
    public function generateProductImpact(&$option, $without_taxes, $tax_ratio, $id_component)
    {
        if(isset($option->att_product) && $option->att_product) {
            $prod_id = explode('_', $option->att_product);
            $product_id = (int) $prod_id[0];
            $attr_id = isset($prod_id[1]) ? (int) $prod_id[1] : null;
            $att_stock = Product::getQuantity((int)$product_id, (int)$attr_id);
            $qty = 1;
            $attached_price = Product::getPriceStatic($product_id, true, $attr_id);
            $option->price_impact = (float)($without_taxes?$attached_price/$tax_ratio:$attached_price);
            $product = new Product($product_id);
            $stock_management_active = Configuration::get('PS_STOCK_MANAGEMENT');
            $allow_shipping = true;
            if (isset($this->context->cart->id_address_delivery) && $this->context->cart->id_address_delivery) {
                $avalible_carriers = Carrier::getAvailableCarrierList($product, false, $this->context->cart->id_address_delivery);
                $allow_shipping = count($avalible_carriers);
            }
            if (!$stock_management_active || ($att_stock >= $qty)) {
                $option->active = true;
                if (!$allow_shipping) {
                    $option->active = false;
                    $option->ofs_text = $this->l('No availabe carriers for this combination');
                }
            } else {
                $option->active = false;
                $option->ofs_text = $product->available_later[$this->context->language->id];
            }
            $option->tax = (($product->getTaxesRate()) / 100) + 1;            
        } else {
            $option->active = true;
            $option->tax = false;
        }
    }

    public function proccessConstraints($constraints_text)
    {
        $constaint_array = explode(',', $constraints_text);
        $constraints = array();
        foreach ($constaint_array as $constraint_text) {
            if ($constraint_text) {
                $parts = explode('@', $constraint_text);
                $constraint = array(
                    'target' => $parts[0],
                    'source' => $parts[1]
                );
                $constraints[] = $constraint;
            }
        }
        return $constraints;
    }

    public function getComponents($id_component = false, $id_configuration = false, $only_parents = true, $base_product = false)
    {
        $id_lang = (int) $this->context->language->id;
        $query = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components comp '
            . 'left join ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang compl on comp.id_component = compl.id_component and compl.id_lang = ' . $id_lang
            . ' where 1=1';

        if (!$id_component && Tools::isSubmit('submitFilteridxrcustomproduct_components') and Tools::getValue('submitFilteridxrcustomproduct_components') == '1') {
            $id_filter = Tools::getValue('idxrcustomproduct_componentsFilter_id_component');
            if ($id_filter) {
                $id_component = $id_filter;
            }

            $name_filter = Tools::getValue('idxrcustomproduct_componentsFilter_name');
            if ($name_filter) {
                $query .= ' and comp.name like "%' . pSQL($name_filter) . '%"';
            }

            $title_filter = Tools::getValue('idxrcustomproduct_componentsFilter_title');
            if ($title_filter) {
                $query .= ' and compl.title like "%' . pSQL(($title_filter)) . '%"';
            }

            $desc_filter = Tools::getValue('idxrcustomproduct_componentsFilter_description');
            if ($desc_filter) {
                $query .= ' and compl.description like "%' . pSQL(($desc_filter)) . '%"';
            }
        }

        if ($id_component) {
            $query .= ' and comp.id_component = ' . (int) $id_component;
        }

        if ($only_parents) {
            $query .= ' and (comp.parent = 0 || comp.parent IS NULL) ';
        }

        $results = Db::getInstance()->executeS($query);
        
        if ($results && !$results[0]['id_component']) {
            $this->fixcomponentlanguage($id_lang);
            return $this->getComponents($id_component, $id_configuration);
        }
        if ($id_configuration) {
            $color = Db::getInstance()->getValue('Select color from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations where id_configuration = ' . (int) $id_configuration);           
            foreach ($results as $key => $result) {
                if ($result['type'] == 'product') {
                    $id_parent = $result['id_component'];
                    unset($results[$key]);
                    $product_components = IdxComponent::getChildrenComponent($id_parent, $id_lang);
                    $results = array_merge($results, $product_components);
                }
            }
            foreach ($results as &$result) {              
                if (!$result['color']) {
                    $result['color'] = $color;
                }
            }
        }

        return $results;
    }

    public function fixcomponentlanguage($id_lang) {
        $components = Db::getInstance()->executeS('Select id_component from '._DB_PREFIX_.'idxrcustomproduct_components');
        if ($components) {
            foreach ($components as $component) {
                $id_component = $component['id_component'];
                $exist_lang = Db::getInstance()->getValue('Select id_components_lang from '._DB_PREFIX_.'idxrcustomproduct_components_lang where id_component = '.(int)$id_component.' and id_lang = '.(int)$id_lang);
                if (!$exist_lang) {
                    $data = array(
                        'id_component' => (int)$id_component,
                        'id_lang' => (int)$id_lang,
                        'title' => '',
                        'description' => ''
                    );
                    Db::getInstance()->insert('idxrcustomproduct_components_lang',$data);
                }
            }
        }
    }

    public function getComponentOptions($id_component)
    {
        $getjsonsql = 'Select icl.id_lang ,icl.json_values, ic.type, ic.default_opt from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang icl '
            . 'left join ' . _DB_PREFIX_ . 'idxrcustomproduct_components ic on icl.id_component = ic.id_component '
            . 'where icl.id_component = ' . (int) $id_component . ';';
        $results = Db::getInstance()->executeS($getjsonsql);
        $data = array();
        if ($results && count($results) > 0) {
            $data['type'] = $results[0]['type'];
            $data['lang'] = array();
            foreach ($results as $result) {
                $json_data = Tools::jsonDecode($result['json_values']);
                $options = array();
                if (isset($json_data->options)) {
                    foreach ($json_data->options as $option) {
                        $sql_impact = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_opt_impact where id_component = ' . (int) $id_component . ' and id_option = ' . (int) $option->id;
                        $impact = Db::getInstance()->getRow($sql_impact);
                        $option->price_impact = (float) $impact['price_impact'];
                        $option->weight_impact = (float) $impact['weight_impact'];
                        $option->attach_product = $impact['att_product'];
                        $option->attach_product_qty = $impact['att_qty'];
                        $option->reference = $impact['reference'];
                        $option->img_ext = 'png';
                        if ($option->id == $results[0]['default_opt']) {
                            $option->default = true;
                        } else {
                            $option->default = false;
                        }
                        $options[$option->id] = $option;
                    }
                    unset($json_data->options);
                    $json_data->options = $options;
                }

                $data['lang'][$result['id_lang']] = $json_data;
            }
        }
        return $data;
    }

    public function getComponentName($id_component, $public_name = false, $id_lang = false)
    {
        if (!$public_name) {
            $getNameSql = 'Select name from ' . _DB_PREFIX_ . 'idxrcustomproduct_components where id_component = ' . (int) $id_component;
        } else {
            $getNameSql = 'Select title from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang where id_component = ' . (int) $id_component . ' and id_lang = ' . (int) $id_lang;
        }
        return Db::getInstance()->getValue($getNameSql);
    }

    public function editComponent($component)
    {
        if ($component->type == 'product') {
            return $this->generateProductOptionsSelector($component);
        }
        if (file_exists(_PS_MODULE_DIR_ . $this->name . '/img/icon/' . $component->id_component . '.png')) {
            $component->icon_preview = true;
        }
        $types = IdxComponent::getComponentTypes();
        $columns = IdxComponent::getComponentColumns();
        $inputs = array(
            array(
                'type' => 'text',
                'label' => $this->l('Component name'),
                'lang' => false,
                'name' => 'name',
                'desc' => $this->l('Set the internal name for this component'),
            ),
            array(
                'type' => 'text',
                'label' => $this->l('Component title'),
                'lang' => true,
                'name' => 'title',
                'desc' => $this->l('Set the title for this component'),
            ),
            array(
                'type' => 'text',
                'label' => $this->l('Component description'),
                'lang' => true,
                'name' => 'description',
                'desc' => $this->l('Set the description for this component'),
            ),
            array(
                'type' => 'select',
                'lang' => false,
                'label' => $this->l('Type'),
                'name' => 'type',
                'desc' => $this->l('Enter the type of the component.'),
                'options' => array(
                    'query' => $types,
                    'id' => 'id',
                    'name' => 'name'
                )
            ),
            array(
                'type' => 'switch',
                'label' => $this->l('Optional'),
                'name' => 'optional',
                'values' => array(
                    array(
                        'id' => 'optional_on',
                        'value' => 1,
                        'label' => $this->l('Yes'),
                    ),
                    array(
                        'id' => 'optional_off',
                        'value' => 0,
                        'label' => $this->l('No'),
                    ),
                ),
                'desc' => $this->l('if you check as optional this product can be customized without select any option of this component')
            ),
            array(
                'type' => 'file',
                'label' => $this->l('Option Icon'),
                'name' => 'icon',
                'desc' => $this->l('Upload an icon for show just before option name, image size: 30px x 30px'),
            ),
            array(
                'type' => 'component_icon',
                'label' => $this->l('Icon preview'),
                'name' => 'icon_preview',
                'component' => $component
            ),
            array(
                'type' => 'select',
                'lang' => false,
                'label' => $this->l('Columns'),
                'name' => 'columns',
                'desc' => $this->l('Enter the amount of options per line.'),
                'options' => array(
                    'query' => $columns,
                    'id' => 'id',
                    'name' => 'name'
                )
            ),
            array(
                'type' => 'color',
                'label' => $this->l('Background colour'),
                'name' => 'component_color',
                'desc' => $this->l('Color for the container background'),
            ),
            array(
                'type' => 'switch',
                'label' => $this->l('Show zoom option?'),
                'name' => 'zoom_icon',
                'values' => array(
                    array(
                        'id' => 'zoom_on',
                        'value' => 1,
                        'label' => $this->l('Yes'),
                    ),
                    array(
                        'id' => 'zoom_off',
                        'value' => 0,
                        'label' => $this->l('No'),
                    ),
                ),
            ),
            array(
                'type' => 'hidden',
                'name' => 'id_component',
            ),
        );

        $fields_form = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('Edit a component'),
                    'icon' => 'icon-cogs'
                ),
                'input' => $inputs,
                'submit' => array(
                    'title' => $this->l('Save'),
                )
            ),
        );

        $helper = new HelperForm();
        $helper->show_toolbar = false;
        $lang = new Language((int) Configuration::get('PS_LANG_DEFAULT'));
        $helper->default_form_language = $lang->id;
        $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
        $this->fields_form = array();
        $helper->module = $this;
        $helper->identifier = $this->identifier;
        $helper->submit_action = 'editComponent';
        $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->tpl_vars = array(
            'fields_value' => $this->getConfigFieldsValues('component', $component),
            'languages' => $this->context->controller->getLanguages(),
            'id_language' => $this->context->language->id
        );
        $helper->back_url = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name . '&token=' . $helper->token;
        $helper->show_cancel_button = true;
        if ($component->type != 'text' && $component->type != 'textarea' && $component->type != 'file') {
            return $helper->generateForm(array($fields_form)) . $this->generateOptionsForm($component);
        } else {
            return $helper->generateForm(array($fields_form)) . $this->generateConfigurationForm($component);
        }
    }

    public function deleteConfiguration($id_configuration)
    {
        $configuration = new IdxConfiguration($id_configuration);
        if ($configuration) {
            $configuration->delete();
        }
    }

    public function deleteComponent($id_component)
    {
        $component = new IdxComponent($id_component);
        $component->delete();
    }

    public function saveComponentIcon($id_component)
    {
        $destination_path = _PS_ROOT_DIR_ . '/modules/' . $this->name . '/img/icon' . DIRECTORY_SEPARATOR;
        $array = explode('.', $_FILES['icon']['name']);
        $extension = end($array);
        if ($extension != 'png') {
            return false;
        }
        $destination_path .= (int) $id_component . '.png';
        if (@move_uploaded_file($_FILES['icon']['tmp_name'], $destination_path)) {
            return false;
        } else {
            return true;
        }
    }

    public function updateOption($id_component, $id_option, $data)
    {
        $get_options_sql = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang where id_component = ' . (int) $id_component . ';';
        $results = Db::getInstance()->ExecuteS($get_options_sql);
        $data = json_decode($data);
        if ($results && count($results) > 0) {
            foreach ($results as $result) {
                $lang = $result['id_lang'];
                $json_data = Tools::jsonDecode($result['json_values']);
                $options = array();
                foreach ($json_data->options as $option) {
                    if ($option->id == $id_option) {
                        foreach ($data as $value) {
                            if ($value->id == 'optionname_' . (int) $id_option . '_' . (int) $lang) {
                                $option->name = $value->val;
                            }
                            if ($value->id == 'optiondesc_' . (int) $id_option . '_' . (int) $lang) {
                                $option->description = $value->val;
                            }
                        }
                        $options[] = $option;
                    } else {
                        $options[] = $option;
                    }
                }
                unset($json_data->options);
                $json_data->options = $options;
                $update = array('json_values' => json_encode($json_data, JSON_UNESCAPED_UNICODE));
                $where = 'id_component = ' . (int) $id_component . ' and id_lang = ' . (int) $result['id_lang'];
                Db::getInstance()->update('idxrcustomproduct_components_lang', $update, $where);
            }
            $price_impact = 0;
            $weight_impact = 0;
            $reference = '';

            foreach ($data as $value) {
                if ($value->id == 'priceimpacttype_'.$id_option) {
                    $price_impact_type = ($value->val == 0)?'fixed':'calculated';
                }
                if ($value->id == 'option_priceimpact_'.$id_option) {
                    $price_impact = $value->val;
                }
                if ($value->id == 'option_priceimpactcalc_'.$id_option) {
                    $price_impact_calc = $value->val;
                }
                if ($value->id == 'option_weightimpact') {
                    $weight_impact = $value->val;
                }
                if ($value->id == 'option_reference') {
                    $reference = $value->val;
                }
                if ($value->id == 'option_product_attached') {
                    $product_attached = $value->val;
                }
                if ($value->id == 'option_product_qty') {
                    $product_attached_qty = $value->val;
                }
            }
            $impact_update = 'Update ' . _DB_PREFIX_ . 'idxrcustomproduct_components_opt_impact set'
                . ' price_impact_type = "' . pSQL($price_impact_type) . '" '
                . ', price_impact = ' . (float) $price_impact
                . ', price_impact_calc = "' . pSQL($price_impact_calc) . '" '
                . ', weight_impact = ' . (float) $weight_impact
                . ', reference = "' . pSQL($reference) . '" '
                . ', att_product = "' . pSQL($product_attached) . '" '
                . ', att_qty = "' . (int) $product_attached_qty . '" '
                . ' where id_component = ' . (int) $id_component . ' and id_option = ' . (int) $id_option . ';';

            Db::getInstance()->execute($impact_update);
        }
    }

    public function updateOptionFile($id_component, $file_size, $extensions)
    {
        $data = new stdClass();
        $data->size = $file_size;
        $data->allowed_extension = $extensions;
        $languages = Language::getLanguages(false);
        foreach ($languages as $lang) {
            $update = array('json_values' => json_encode($data, JSON_UNESCAPED_UNICODE));
            $where = 'id_component = ' . (int) $id_component . ' and id_lang = ' . (int) $lang['id_lang'];
            Db::getInstance()->update('idxrcustomproduct_components_lang', $update, $where);
        }
    }

    public function deleteOption($id_component, $id_option)
    {
        $get_options_sql = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang where id_component = ' . (int) $id_component . ';';
        $results = Db::getInstance()->ExecuteS($get_options_sql);
        if ($results && count($results) > 0) {
            foreach ($results as $result) {
                $json_data = Tools::jsonDecode($result['json_values']);
                $options = array();
                foreach ($json_data->options as $option) {
                    if ($option->id != $id_option) {
                        $options[] = $option;
                    }
                }
                unset($json_data->options);
                $json_data->options = $options;
                $update = array(
                    'json_values' => json_encode($json_data, JSON_UNESCAPED_UNICODE)
                );
                $where = 'id_component = ' . (int) $id_component . ' and id_lang = ' . (int) $result['id_lang'];
                Db::getInstance()->update('idxrcustomproduct_components_lang', $update, $where);
                $sql_delete = 'Delete from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_opt_impact where id_component = ' . (int) $id_component . ' and id_option = ' . (int) $id_option . ';';
                Db::getInstance()->execute($sql_delete);
            }
        }
    }

    public function setDefaultComponentOption($component_id, $option_id)
    {
        $data = array(
            'default_opt' => (int) $option_id
        );
        Db::getInstance()->update('idxrcustomproduct_components', $data, 'id_component = ' . (int) $component_id);
    }

    public function setDefaultConfigurationComponentOption($configuration_id, $component_id, $option_id)
    {
        $actual_default = Db::getInstance()->getValue('Select default_configuration from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations where id_configuration = ' . (int) $configuration_id);
        $default_arr = json_decode($actual_default, true);
        if (!$default_arr) {
            $default_arr = array();
        }
        $value = false;
        switch ($option_id) {
            case 'disable':
                $value = -1;
                break;
            case 'inherit':
                $value = -2;
                break;
            default:
                $option_parts = explode('_', $option_id);
                if (isset($option_parts[1])) {
                    $value = $option_parts[1];
                }
                break;
        }
        $default_arr[$component_id] = $value;
        $update = array(
            'default_configuration' => json_encode($default_arr, JSON_UNESCAPED_UNICODE)
        );
        $where = 'id_configuration = ' . (int) $configuration_id;
        Db::getInstance()->update('idxrcustomproduct_configurations', $update, $where);
    }

    public function generateOptionsForm($component)
    {
        if ($component->parent > 0) {
            return '';
        }
        $languages = Language::getLanguages(false);
        $actual_lang_id = $this->context->language->id;
        $products = $this->getProducts();
        $this->smarty->assign(array(
            'component' => $component,
            'options' => $component->options_lang,
            'products' => $products,
            'link' => $this->context->link,
            'languages' => $languages,
            'defaultFormLanguage' => $actual_lang_id,
            'images_dir' => _PS_IMG_ . $this->name . DIRECTORY_SEPARATOR
        ));

        return $this->display(__FILE__, 'views/templates/admin/component-form.tpl');
    }
    
    public function generateProductOptionsSelector($component)
    {
        $subcomponents = Db::getInstance()->executeS('Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components comp where parent = '.(int)$component->id_component);
        $this->smarty->assign(array(
            'component' => $component,
            'subcomponents' => $subcomponents,
            'backurl' => $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name .'&module_name=' . $this->name .'&updatecomponent&id_component=',
            'token' => Tools::getAdminTokenLite('AdminModules')
        ));

        return $this->display(__FILE__, 'views/templates/admin/component-product-selector.tpl');
    }

    public function generateConfigurationForm($component)
    {
        $max_server = str_replace('M', '', ini_get('post_max_size'));
        $max_file = $max_server;
        $this->smarty->assign(array(
            'component' => $component,
            'max_file' => $max_file,
            'max_file_server' => $max_server,
            'file_extensions' => $this->getFileExtensions(),
            'currentIndex' => $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name,
            'token' => Tools::getAdminTokenLite('AdminModules')
        ));
        if ($component->type == 'file') {
            return $this->display(__FILE__, 'views/templates/admin/component-file-form.tpl');
        }
    }

    public function generateProductComponentForm($id_product)
    {
        $product = new Product($id_product);
        $combinations = $product->getAttributeCombinations($this->context->language->id);
        $this->smarty->assign(array(
            'combinations' => $combinations
        ));

        return $this->display(__FILE__, 'views/templates/admin/productcomponent-form.tpl');
    }

    public function getFileExtensions()
    {
        return array(
            'ai' => 'Documento Adobe Ilustrator',
            'aif' => 'Archivo de intercambio de audio',
            'avi' => 'Audio Video Interleave',
            'bat' => 'Archivos por lotes',
            'bin' => 'Archivo binario',
            'bmp' => 'Mapa de bits de Windows',
            'bup' => 'Archivo de copia de seguridad',
            'cab' => 'Microsoft Windows archivo comprimido',
            'cda' => 'Atajo CD Audio Track',
            'cdr' => 'Corel Draw Vector o CD de audio sin procesar',
            'chm' => 'Microsoft HTML Help comprimido',
            'dat' => 'Datos',
            'divx' => 'Vídeo DivX',
            'dll' => 'Biblioteca de vínculos dinámicos',
            'dmg' => 'Imagen de disco',
            'doc' => 'Documento Microsoft Word',
            'docx' => 'Documento Microsoft Word',
            'dwg' => 'AutoCAD DWG',
            'eml' => 'Mensaje de correo electrónico',
            'eps' => 'PostScript encapsulado',
            'exe' => 'Archivo ejecutable',
            'fla' => 'Adobe Flash',
            'flv' => 'Flash Video',
            'gif' => 'Imagen GIF (Graphics Interchange Format)',
            'gz' => 'Gzip archivo empaquetado',
            'hqx' => 'BinHex',
            'htm' => 'Web – Hypertext Markup Language (HTML)',
            'html' => 'Web – Hypertext Markup Language (HTML)',
            'ifo' => 'DVD Información del archivo',
            'indd' => 'Documento de InDesign',
            'iso' => 'Imagen de disco óptico',
            'jar' => 'Archivo Java',
            'jpeg' => 'De imagen JPEG',
            'jpg' => 'Imagen JPEG',
            'lnk' => 'Acceso directo – Atajo',
            'log' => 'Archivo de registro',
            'm4a' => 'MPEG-4 Parte 14',
            'm4b' => 'MPEG-4 Parte 14',
            'm4p' => 'AAC protegido Archivo',
            'm4v' => 'MPEG-4 Parte 14',
            'mdb' => 'Microsoft Access',
            'mid' => 'Audio midi – Musical Instrument Digital Interface',
            'mov' => 'QuickTime',
            'mp2' => 'MPEG-1 Audio Layer II',
            'mp3' => 'Archivo de Audio MP3',
            'mp4' => 'MPEG-4 Parte 14',
            'mpeg' => 'MPEG 1 Sistema Stream',
            'mpg' => 'MPEG-1 Video',
            'msi' => 'Windows Installer',
            'mswmm' => 'Windows Movie Maker Archivo de Proyecto',
            'pdf' => 'Documento PDF',
            'png' => 'Graficos – Portable Network Graphics',
            'pps' => 'Mostrar PowerPoint',
            'ppt' => 'Microsoft PowerPoint Presentation',
            'pptx' => 'Microspft PowerPoint 2007+',
            'ps' => 'PostScript',
            'psd' => 'Photoshop documento',
            'pst' => 'Microsoft Outlook emails – Personal Storage',
            'pub' => 'Microsoft Publisher',
            'qbb' => 'QuickBooks archivo de copia de seguridad',
            'qbw' => 'Hoja de cálculo; QuickBooks para Windows',
            'ram' => 'RealAudio',
            'rar' => 'RAR Archive',
            'rm' => 'RealMedia',
            'rmvb' => 'RealMedia Variable Bitrate',
            'rtf' => 'Formato de texto enriquecido',
            'sql' => 'Lenguaje de consulta estructurado',
            'ss' => 'Gráficos de mapas de bits; Splash',
            'swf' => 'SWF de gráficos vectoriales',
            'tgz' => 'Archivo; WinZipNT – TAR – GNUzip',
            'tif' => 'Tagged Image File Format',
            'torrent' => 'BitTorrent',
            'ttf' => 'Tipos de Fuente – Letra',
            'txt' => 'Archivo de texto plano',
            'vcd' => 'Virtual CD-ROM CD Archivo de imagen',
            'vob' => 'DVD-Video Object',
            'wav' => 'Waveform Audio Formato',
            'wma' => 'Windows Media Audio',
            'wmv' => 'Windows Media Video',
            'wpd' => 'WordPerfect Document',
            'wps' => 'Documento de texto, MS Works',
            'xls' => 'Microsoft Excel hoja de cálculo',
            'xlsx' => 'Microsoft Excel 2007+',
            'zip' => 'Archivo empaquetado',
        );
    }

    public function getProducts()
    {
        $hidden_categories = Configuration::get(Tools::strtoupper($this->name) . '_CATEGORY');
        $id_shop = $this->context->shop->id;
        $lang_id = $this->context->language->id;
        $products = Db::getInstance()->ExecuteS('SELECT `id_product` FROM `' . _DB_PREFIX_ . 'product_shop` where active = 1 AND id_shop = ' . (int) $id_shop . ' AND id_category_default != ' . (int) $hidden_categories);
        $return_products = array();
        foreach ($products as $p) {
            $product = new Product($p['id_product'], false, $lang_id);
            if ($product_combinations = $product->getAttributesResume($lang_id)) {
                foreach ($product_combinations as $combination) {
                    $return_products[] = array(
                        'id_product' => $product->id,
                        'name' => $product->name,
                        'id_product_attribute' => $combination['id_product_attribute'],
                        'attrname' => $combination['attribute_designation'],
                        'reference' => $combination['reference']?$combination['reference']:$product->reference
                    );
                }
            } else {
                $return_products[] = array(
                    'id_product' => $product->id,
                    'name' => $product->name,
                    'id_product_attribute' => 0,
                    'attrname' => ''
                );
            }
            unset($product);
        }

        return $return_products;
    }

    public function activeConfiguration($id)
    {
        $toggle_query = 'UPDATE ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations SET active = 1 - active where id_configuration = ' . (int) $id . ';';
        Db::getInstance()->execute($toggle_query);
    }

    public function createProduct($product_id, $attribute_id, $customization, $extra = false)
    {
        $languages = Language::getLanguages(false);
        $add_price = 0;
        $add_weight = 0;
        $add_ref = '';
        $add_desc = '';
        $add_shortdesc = array();
        $icp_code = '';
        $icp_sep = '';
        foreach ($languages as $lang) {
            $add_shortdesc[$lang['id_lang']] = '';
        }
        $id_configuration = $this->getConfigurationByProduct($product_id);
        $configuration = new IdxConfiguration($id_configuration, true);
        $this->checkConstraints($customization, $id_configuration);

        $id_product_old = (int) $product_id;
        $product = new Product($id_product_old);

        $product_source = new Product($id_product_old);
        $tax = (($product->getTaxesRate()) / 100) + 1;
        
        foreach ($customization as &$option) {
            if (strpos($option['id_component'],'999') > 0) {
                $id_data = explode('999', $option['id_component']);
                $option['id_component'] = $id_data[0];
                $option['att_product'] = IdxComponent::getProductByCustomization($id_data[0], $customization);
                $option['from_product'] = true;
            }
            $icp_code .= $icp_sep . $option['id_component'] . '-' . $option['id_option'];
            $icp_sep = ',';
            $options = $this->getComponentOptions($option['id_component']);

            if ($options['type'] != 'textarea' && $options['type'] != 'text' && $options['type'] != 'file') {
                foreach ($options['lang'][$this->context->language->id]->options as $item) {                    
                    if ($item->id == $option['id_option']) {
                        if (isset($option['from_product'])) {
                            $item->att_product = $option['att_product'];                            
                            $this->generateProductImpact($item, false, $tax, $option['id_component']);    
                        } else {
                            $this->generateImpact($item, false, $tax, $option['id_component'], $product_id);
                        }
                        $add_price += $item->price_impact;
                        $add_weight += $item->weight_impact;
                        $add_ref .= $item->reference;
                        $add_desc .= '<p>' . $this->getComponentName($option['id_component']) . ': ' . $item->name
                            . (($item->reference != '' && $item->reference != $item->name) ? ' - ' . $item->reference . '</p>' : '</p>');
                        foreach ($languages as $lang) {
                            $add_shortdesc[$lang['id_lang']] .= '<p>' . $this->getComponentName($option['id_component'], true, $lang['id_lang']) . ': ' . $item->name . '</p>';
                        }
                        $option['option'] = $item;
                        break;
                    }
                }
            }
        }

        $add_price_wt = $add_price / $tax;

        $base_price = 0;
        if ($configuration->add_base) {
            $base_price = $product_source->price;
        }
        $actual_price = Tools::ps_round($base_price + $add_price_wt, 6);

        $add_desc .= '<p>icp_code(' . $icp_code . ')</p>';
        $exist = $this->productByIcpcode($product_id, $icp_code);
        $extra_ids = array();
        foreach ($extra as $opt_extra) {
            if (!$this->context->cart->id) {
                if (Context::getContext()->cookie->id_guest) {
                    $guest = new Guest(Context::getContext()->cookie->id_guest);
                    $this->context->cart->mobile_theme = $guest->mobile_theme;
                }
                $this->context->cart->add();
                if ($this->context->cart->id) {
                    $this->context->cookie->id_cart = (int) $this->context->cart->id;
                }
            }
            $extra = explode('_', $opt_extra);
            if (isset($extra[1])) {
                $extra[1] = json_decode($extra[1]);
            }
            if (!isset($extra[1]) || $extra[1] == "false") {
                continue;
            } else {
                $data = array(
                    'id_component' => (int) $extra[0],
                    'extra' => pSQL($extra[1]),
                    'id_cart' => (int) $this->context->cart->id,
                );
                $exist_q = 'Select id_extra from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra where id_component = ' . (int) $extra[0] . ' and id_cart = ' . (int) $this->context->cart->id . ' and id_product = ' . (int) $exist;
                $id_extra = Db::getInstance()->getValue($exist_q);
                if ($id_extra) {
                    $extra_ids[] = $id_extra;
                    Db::getInstance()->update('idxrcustomproduct_customer_extra', $data, 'id_extra = ' . (int) $id_extra);
                } else {
                    Db::getInstance()->insert('idxrcustomproduct_customer_extra', $data);
                    $extra_ids[] = Db::getInstance()->Insert_ID();
                }
            }
        }
        if ($exist) {
            if ($extra_ids) {
                $extra_sql = 'Update ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra set id_product = ' . (int) $exist . ' where id_extra in (' . pSQL(implode(',', $extra_ids)) . ')';
                Db::getInstance()->execute($extra_sql);
            }
            $this->setQty(1, $exist);
            $old_price = Product::getPriceStatic($exist, false);
            if ($old_price !== $actual_price) {
                $customized_product = new Product($exist);
                $customized_product->price = $actual_price;
                $customized_product->update();
            }
            return $exist;
        }

        $product->price = $actual_price;
        unset($product->id);
        unset($product->id_product);
        $product->indexed = 0;
        $product->active = 1;
        $product->id_category_default = (int) Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'));
        $reference = $product->reference;
        if ($add_ref != '') {
            $reference .= '_' . $add_ref;
        } else {
            $reference .= '_CUSTOM';
        }
        $product->reference = Tools::substr($reference, 0, 32);
        $product->out_of_stock = 2;
        $product->depends_on_stock = false;
        $product->visibility = 'none';
        foreach ($languages as $lang) {
            $product->description[$lang['id_lang']] = $add_desc;
            $product->description_short[$lang['id_lang']] = $add_shortdesc[$lang['id_lang']];
        }
        $product->add();
        $product->setCarriers($product_source->getCarriers());
        $this->setProductoOriginal($id_product_old, $product->id, $icp_code);
        $categories = array();
        $categories[0] = (int) Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'));
        $product->updateCategories($categories);
        if ($extra_ids) {
            $extra_sql = 'Update ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra set id_product = ' . (int) $product->id . ' where id_extra in (' . pSQL(implode(',', $extra_ids)) . ')';
            Db::getInstance()->execute($extra_sql);
        }
        $this->setQty(1, $product->id);
        Image::duplicateProductImages($id_product_old, $product->id, 0);
        return $product->id;
    }

    public function checkConstraints(&$customization, $id_configuration)
    {
        $options_selected = array();
        foreach ($customization as $option) {
            $options_selected[] = $option['id_component'] . '_' . $option['id_option'];
        }
        $sql = 'Select constraints_options from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations where id_configuration = ' . (int) $id_configuration;
        $constrains = Db::getInstance()->getValue($sql);

        if ($constrains) {
            $rules = array();
            $contstraints_array = explode(',', $constrains);
            foreach ($contstraints_array as $cont) {
                if ($cont) {
                    $cont_val = explode('@', $cont);
                    $rules[$cont_val[0]][] = explode('+', $cont_val[1]);
                }
            }

            foreach ($customization as $key => $option) {
                if (isset($rules[$option['id_component']])) {
                    $delete = true;
                    foreach ($rules[$option['id_component']] as $rules) {
                        $sub_delete = false;
                        foreach ($rules as $rule) {
                            if (!in_array($rule, $options_selected)) {
                                $sub_delete = true;
                            }
                        }
                        if (!$sub_delete) {
                            $delete = false;
                        }
                    }
                    if ($delete) {
                        unset($customization[$key]);
                    }
                }
            }
        }
    }

    public function getProductoOriginal($id_producto, $icp_code = false)
    {
        $sql = 'SELECT id_producto FROM ' . _DB_PREFIX_ . $this->name . '_clones WHERE id_clon = ' . (int) $id_producto . ' AND icp_code LIKE "' . pSQL($icp_code) . '"';
        return Db::getInstance()->getValue($sql);
    }

    public function setProductoOriginal($id_producto, $id_clon, $icp_code)
    {
        return Db::getInstance()->insert($this->name . '_clones', array(
                'id_producto' => $id_producto,
                'id_clon' => $id_clon,
                'icp_code' => $icp_code
        ));
    }

    public function productByIcpcode($id_producto, $icp_code)
    {
        $sql = 'SELECT id_clon FROM ' . _DB_PREFIX_ . $this->name . '_clones WHERE id_producto = ' . (int) $id_producto . ' AND icp_code LIKE "' . pSQL($icp_code) . '"';
        $id_product = Db::getInstance()->getValue($sql);
        $already_exist = Db::getInstance()->getValue('Select id_product from '._DB_PREFIX_.'product where id_product = '.(int)$id_product);
        if (!$already_exist) {
            Db::getInstance()->delete($this->name . '_clones', 'id_producto = ' . (int) $id_producto . ' AND icp_code LIKE "' . pSQL($icp_code) . '"');
            return false;
        }
        return $id_product;
    }

    public function updateNotes($data)
    {
        foreach ($data as $note) {
            if (isset($note['id_cart'])) {
                $sql_exist = 'Select id_note from ' . _DB_PREFIX_ . 'idxrcustomproduct_notes where id_cart = ' . (int) $note['id_cart'] . ' and id_cart_product = ' . (int) $note['id_product'];
                $id_note = Db::getInstance()->getValue($sql_exist);
                if ($id_note) {
                    $update_data = array(
                        'private_note' => $note['private'],
                        'public_note' => $note['public']
                    );
                    $where = 'id_note = ' . (int) $id_note;
                    Db::getInstance()->update('idxrcustomproduct_notes', $update_data, $where);
                } else {
                    $insert_data = array(
                        'id_cart' => (int) $note['id_cart'],
                        'id_cart_product' => (int) $note['id_product'],
                        'private_note' => pSQL($note['private']),
                        'public_note' => pSQL($note['public'])
                    );
                    Db::getInstance()->insert('idxrcustomproduct_notes', $insert_data, true);
                }
            }
        }
        if (count($data)) {
            $id_cart = $data[0]['id_cart'];
            //Delete the notes that isn't in the data
            $all_notes = 'Select id_note, id_cart, id_cart_product from ' . _DB_PREFIX_ . 'idxrcustomproduct_notes where id_cart = ' . (int) $id_cart;
            $result = Db::getInstance()->executeS($all_notes);
            foreach ($result as $old_note) {
                $exist = false;
                foreach ($data as $new_note) {
                    if ($new_note['id_product'] == $old_note['id_cart_product']) {
                        $exist = true;
                    }
                }
                if (!$exist) {
                    Db::getInstance()->delete('idxrcustomproduct_notes', 'id_cart = ' . (int) $id_cart . ' and id_cart_product = ' . (int) $old_note['id_cart_product']);
                }
            }
        }
    }

    public function getNotesByOrder($id_order)
    {
        $sql = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_notes where id_order = ' . (int) $id_order;
        if ($result = Db::getInstance()->executeS($sql)) {
            $productos_pedido = array();
            if ($listadoProductos = OrderDetail::getList($id_order)) {
                foreach ($listadoProductos as $producto) {
                    $productos_pedido[] = $producto['product_id'];
                }
            }
            foreach ($result as $index => $nota) {
                if (!in_array($nota['id_cart_product'], $productos_pedido)) {
                    unset($result[$index]);
                }
            }
            return $result;
        }
    }

    public function getPanelForOrder($id_order, $front = false)
    {
        $notes = $this->getNotesByOrder($id_order);
        if ($notes) {
            if ($front) {
                foreach ($notes as &$note) {
                    $notes_in_p = $note['public_note'];
                    $notes_array = explode('</p>', str_replace('<p>', '', $notes_in_p));
                    $note['notes_a'] = $notes_array;
                }
                $this->smarty->assign(array('notes' => $notes));
                return $this->display(__FILE__, 'views/templates/front/order-notes.tpl');
            } else {
                foreach ($notes as &$note) {
                    $note['product_name'] = Product::getProductName($note['id_cart_product']);
                }
                $this->smarty->assign(array('notes' => $notes));
                return $this->display(__FILE__, 'views/templates/admin/order-notes.tpl');
            }
        }
    }

    public function getToppriceBlock($id_product)
    {
        $product_price = Tools::ps_round(Product::getPriceStatic($id_product), _PS_PRICE_COMPUTE_PRECISION_);
        $this->smarty->assign(array('product_price' => $product_price));
        if ($this->es17) {
            return $this->display(__FILE__, 'views/templates/front/17/topBlock.tpl');
        } else {
            return $this->display(__FILE__, 'views/templates/front/16/topBlock.tpl');
        }
    }

    public function getExtraByContext($clean = false)
    {
        $cart = new Cart((int) $this->context->cart->id);
        $extra_options = $this->getExtraByCart((int) $this->context->cart->id);
        $products = $cart->getProducts();
        $extra_info = array();
        $file_controller = $this->context->shop->physical_uri . $this->context->shop->virtual_uri . 'modules/' . $this->name . '/file_controller.php?key=';
        foreach ($products as $product) {
            if ($product['id_category_default'] == Configuration::get(Tools::strtoupper($this->name . '_CATEGORY'))) {
                $data = array();
                $data['id_product'] = $product['id_product'];
                if ($clean) {
                    $data['customization'] = '<table class=\"table-config\">';
                } else {
                    $data['customization'] = '<table class=\"tabla-resumen table table-bordered\">';
                }
                $data['customization'] .= str_replace(array('<p>', ':', '</p>'), array('<tr><td>', ':</td><td>', '</td></tr>'), $product['description_short']);
                foreach ($extra_options as $extra) {
                    if ($extra['id_product'] == $product['id_product']) {
                        if ($extra['original_name']) {
                            $data['customization'] .= '<tr><td>' . $extra['title'] . ':</td><td><a href="' . $file_controller . $extra['target_name'] . '" target="_blank">' . $extra['extra'] . '</a></td></tr>';
                        } else {
                            $data['customization'] .= '<tr><td>' . $extra['title'] . ':</td><td>' . $extra['extra'] . '</td></tr>';
                        }
                    }
                }
                $data['customization'] .= '</table>';
                $extra_info[] = $data;
            }
        }
        return $extra_info;
    }

    public function getExtraByCart($id_cart, $id_product = false)
    {
        $query = 'Select ext.*, comp.title, files.original_name, files.target_name from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra ext '
            . 'inner join ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang comp on ext.id_component = comp.id_component '
            . 'left join ' . _DB_PREFIX_ . 'idxrcustomproduct_files files on files.id_component = ext.id_component and files.id_cart = ext.id_cart and files.original_name = ext.extra '
            . 'where ext.id_cart = ' . (int) $id_cart . ' and comp.id_lang = ' . (int) $this->context->language->id;
        if ($id_product) {
            $query .= ' and ext.id_product = ' . (int) $id_product;
        }

        return Db::getInstance()->executeS($query);
    }

    public function getExtraByFav($id_fav)
    {
        $query = 'Select ext.*, comp.title from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra ext '
            . 'inner join ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang comp on ext.id_component = comp.id_component '
            . 'where id_fav = ' . (int) $id_fav . ' and comp.id_lang = ' . (int) $this->context->language->id;
        return Db::getInstance()->executeS($query);
    }

    public function saveFavorite($product_id, $attribute_id, $customization, $extra_values)
    {
        $customer_id = $this->context->customer->id;
        $icp_code = '';
        $icp_sep = '';
        $add_shortdesc = '';

        foreach ($customization as &$option) {
            $option_arr = explode('_', $option);
            $option = array();
            $option['id_component'] = $option_arr[0];
            $option['id_option'] = $option_arr[1];
            $icp_code .= $icp_sep . $option['id_component'] . '-' . $option['id_option'];
            $icp_sep = ',';
            $options = $this->getComponentOptions($option['id_component']);
            if ($options['type'] != 'textarea' && $options['type'] != 'text') {
                foreach ($options['lang'][$this->context->language->id]->options as $item) {
                    if ($item->id == $option['id_option']) {
                        $add_shortdesc .= '<p>' . $this->getComponentName($option['id_component'], true, $this->context->language->id) . ': ' . $item->name . '</p>';
                        break;
                    }
                }
            }
        }

        $exist_sql = 'Select id_fav from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_fav where id_customer = ' . (int) $customer_id . ' and id_product = ' . (int) $product_id . ' and icp_code = "' . pSQL($icp_code) . '"';
        if (Db::getInstance()->getValue($exist_sql)) {
            $this->addExtraFavorite($exist_sql, $product_id, $extra_values);
            return 2;
        } else {
            $insert_data = array(
                'id_customer' => (int) $customer_id,
                'id_product' => (int) $product_id,
                'icp_code' => pSQL($icp_code),
                'description' => $add_shortdesc
            );
            Db::getInstance()->insert('idxrcustomproduct_customer_fav', $insert_data);
            $fav_id = Db::getInstance()->Insert_ID();
            $this->addExtraFavorite($fav_id, $product_id, $extra_values);
            return 1;
        }
    }

    public function addExtraFavorite($fav_id, $product_id, $extra_values)
    {
        foreach ($extra_values as $opt_extra) {
            $extra = explode('_', $opt_extra);
            $extra[1] = json_decode($extra[1]);
            if ($extra[1] == "false") {
                continue;
            } else {
                $data = array(
                    'id_component' => (int) $extra[0],
                    'extra' => pSQL($extra[1]),
                    'id_fav' => (int) $fav_id,
                    'id_product' => (int) $product_id,
                );
                $exist_q = 'Select id_extra from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra where id_component = ' . (int) $extra[0] . ' and id_fav = ' . (int) $fav_id . ' and id_product = ' . (int) $product_id;
                $id_extra = Db::getInstance()->getValue($exist_q);
                $extra_ids = array();
                if ($id_extra) {
                    $extra_ids[] = $id_extra;
                    Db::getInstance()->update('idxrcustomproduct_customer_extra', $data, 'id_extra = ' . (int) $id_extra);
                } else {
                    Db::getInstance()->insert('idxrcustomproduct_customer_extra', $data);
                    $extra_ids[] = Db::getInstance()->Insert_ID();
                }
            }
        }
    }

    public function delFavorite($favorite_id)
    {
        $customer_id = $this->context->customer->id;
        $del_sql = 'Delete from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_fav where id_customer = ' . (int) $customer_id . ' and id_fav = ' . (int) $favorite_id . ';';
        Db::getInstance()->execute($del_sql);
        $del_extra_sql = 'Delete from ' . _DB_PREFIX_ . 'idxrcustomproduct_customer_extra where id_fav = ' . (int) $favorite_id . ';';
        return Db::getInstance()->execute($del_extra_sql);
    }

    public function setQty($qty_diff, $id_product, $id_product_attribute = null, $id_shop = null)
    {
        // Si se recibe un entero como diferencia en el stock
        if (is_int($qty_diff) && $qty_diff != 0) {
            // Instanciamos un producto con el id recibido
            $product = new Product($id_product);
            $qty = 0;
            //En caso de stock avanzado...
            if ($product->available_for_order && Configuration::get('PS_STOCK_MANAGEMENT')) {
                if ($product->advanced_stock_management && !$this->es17) {

                    $employeer_q = 'select id_employee from ' . _DB_PREFIX_ . 'employee where active = 1 and id_profile = ' . _PS_ADMIN_PROFILE_;
                    $employe_id = Db::getInstance()->getValue($employeer_q);
                    $employee = new Employee($employe_id);
                    if (!isset($this->context->employee) || !$this->context->employee) {
                        $this->context->employee = $employee;
                    }
                    $warehouses = Warehouse::getWarehousesByProductId($id_product, $id_product_attribute);
                    if (!empty($warehouses)) {
                        foreach ($warehouses as $warehouse) {
                            $WarehouseStock = new Warehouse(array_shift($warehouses)['id_warehouse']);
                        }
                    } else {
                        $query = new DbQuery();
                        $query->select('DISTINCT w.id_warehouse, CONCAT(w.reference, " - ", w.name) as name');
                        $query->from('warehouse', 'w');
                        $query->leftJoin('warehouse_product_location', 'wpl', 'wpl.id_warehouse = w.id_warehouse');
                        $query->limit(1);
                        $warehouses = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
                        $WarehouseStock = new Warehouse(array_shift($warehouses)['id_warehouse']);
                    }
                    // Asignamos el nuevo stock en gestion avanzada de stock
                    $stockmanager = StockManagerFactory::getManager();
                    $price = Product::getPriceStatic($id_product, false, $id_product_attribute);

                    if ($qty_diff > 0) {
                        $stockmanager->addProduct($id_product, (int) $id_product_attribute, $WarehouseStock, $qty_diff, 'tracking', $price, true, null, $employee);
                        StockAvailable::synchronize($id_product);
                        $location = Warehouse::getProductLocation($id_product, (int) $id_product_attribute, $WarehouseStock->id);
                        if (!$location) {
                            Warehouse::setProductLocation($id_product, (int) $id_product_attribute, $WarehouseStock->id, null);
                        }
                    } else {
                        $negqtydiff = $qty_diff * -1;
                        $stockmanager->removeProduct($id_product, (int) $id_product_attribute, $WarehouseStock, $negqtydiff, 'tracking', true, null, 0, $employee);
                        StockAvailable::synchronize($id_product);
                    }
                } else {
                    // Gestión normal de stock
                    //Calculamos la nueva cantidad de stock
                    $qty = $qty_diff + StockAvailable::getQuantityAvailableByProduct($id_product, $id_product_attribute, $id_shop);
                    // Asignamos el nuevo stock
                    StockAvailable::setQuantity($id_product, $id_product_attribute, (int) $qty);
                }
            }
            // Ejecutamos el hook correspondiente para cuando hay cambios en productos
            Hook::exec('actionProductUpdate', array('id_product' => (int) $id_product, 'product' => $product));
            return true;
        } else {
            //Si no es un entero
            return false;
        }
    }

    public function createCartRule($discount_name, $id_product, $cart, $amount)
    {
        $cartrule_code = $discount_name;
        if ($cart_rule_exist = !CartRule::getCartsRuleByCode($cartrule_code, $this->context->language->id)) {
            $cartrule = new CartRule();
            $expiration = 30;
            $cartrule->code = $cartrule_code;
            $name = array();
            foreach (Language::getLanguages(true, false, true) as $language_id) {
                $name[$language_id] = $this->l('Custom product discount ');
            }
            $cartrule->name = $name;
            $cartrule->id_customer = $cart->id_customer;
            $cartrule->date_from = date('Y-m-d 00:00:00');
            $cartrule->date_to = date('Y-m-d 00:00:00',strtotime("+".$expiration." day"));
            $cartrule->partial_use = 0;
            $cartrule->minimum_amount_currency = 1;
            $cartrule->reduction_amount = $amount;
            $cartrule->reduction_currency = 1;
            $cartrule->active = 1;
            if($cartrule->add()) {
                $this->createCartRuleProduct($id_product, $cartrule->id);
                return $cartrule->id;
            }
        } else {
            return $cart_rule_exist;
        }
    }

    public function createCartRuleProduct($id_product, $id_cart_rule)
    {
        Db::getInstance()->execute('INSERT INTO `' . _DB_PREFIX_ . 'cart_rule_product_rule_group` (`id_cart_rule`, `quantity`)
                        VALUES (' . (int) $id_cart_rule . ', 1)');
        $id_product_rule_group = Db::getInstance()->Insert_ID();
        Db::getInstance()->execute('INSERT INTO `' . _DB_PREFIX_ . 'cart_rule_product_rule` (`id_product_rule_group`, `type`)
                        VALUES (' . (int) $id_product_rule_group . ', "products")');
        $id_product_rule = Db::getInstance()->Insert_ID();
        Db::getInstance()->execute('INSERT INTO `' . _DB_PREFIX_ . 'cart_rule_product_rule_value` (`id_product_rule`, `id_item`) VALUES ('.(int)$id_product_rule.', '.(int)$id_product.')');
    }

    public function createSpecificPrice($id_product, $cart, $amount)
    {
        if (!SpecificPrice::exists($id_product, 0, $this->context->shop->id, 0, 0, $cart->id_currency, $cart->id_customer, 1, '0000-00-00 00:00:00', '0000-00-00 00:00:00')) {
            $specificPrice = new SpecificPrice();
            $specificPrice->id_product = (int) $id_product;
            $specificPrice->id_product_attribute = 0;
            $specificPrice->id_shop = (int) $this->context->shop->id;
            $specificPrice->id_currency = (int) $cart->id_currency;
            $specificPrice->id_customer = (int) $cart->id_customer;
            $specificPrice->id_group = 0;
            $specificPrice->id_country = 0;
            $specificPrice->price = (float) (-1);
            $specificPrice->from_quantity = 1;
            $specificPrice->reduction = (float) ($amount);
            $specificPrice->reduction_tax = false;
            $specificPrice->reduction_type = 'amount';
            $specificPrice->from = '0000-00-00 00:00:00';
            $specificPrice->to = '0000-00-00 00:00:00';
            return $specificPrice->add();
        }
    }

    public static function getImagesTypes()
    {
        $types = array();
        $types[] = Configuration::get(Tools::strtoupper('IDXRCUSTOMPRODUCT_PCIMGTYPE'));
        $types[] = Configuration::get(Tools::strtoupper('IDXRCUSTOMPRODUCT_MIMGTYPE'));
        $types[] = Configuration::get(Tools::strtoupper('IDXRCUSTOMPRODUCT_TIMGTYPE'));
        return array_unique($types);
    }
    
    public static function formatPrice($price)
    {
        if (version_compare(_PS_VERSION_, '1.7.6.0', '>')) {
            if (!is_numeric($price)) {
                return $price;
            }
            $context = Context::getContext();
            $currency = $context->currency;
            if (is_int($currency)) {
                $currency = Currency::getCurrencyInstance($currency);
            }
            $locale = $context->getCurrentLocale();
            $currencyCode = is_array($currency) ? $currency['iso_code'] : $currency->iso_code;
            return $locale->formatPrice($price, $currencyCode);
        } else {
            return Tools::displayPrice($price);
        }
    }
    
    public function setInnovaTabs()
    {
        $isoLinks = InnovaTools_2_0_0::getIsoLinks($this);
        $default_cat = (Configuration::get(Tools::strtoupper($this->name . '_CATEGORY')) || Tools::getValue('customizable_category'));
        $locked = true;
        $current_cat = 'helpGenerateForm';
        if ($default_cat) {
            $current_cat = 'renderConfigurationList';
            $locked = false;
        }

        if (
            (Tools::isSubmit('editComponent') && !Tools::isSubmit('editComponentStay')) || Tools::isSubmit('deleteidxrcustomproduct_components') || Tools::isSubmit('submitFilteridxrcustomproduct_components')
        ) {
            $current_cat = 'renderComponentList';
        }

        if (
            Tools::isSubmit('updatecomponent') || Tools::isSubmit('editComponentStay') || Tools::isSubmit('submitComponentStay') || Tools::isSubmit('submitCloneComponent') || Tools::isSubmit('submitGenerateComponent')
        ) {
            $current_cat = 'renderEditComponent';
        }

        if (
            Tools::isSubmit('updateconfiguration') || Tools::isSubmit('submitConfigurationStay') || Tools::isSubmit('updateidxrcustomproduct_configurations')
        ) {
            $current_cat = 'renderFormAddConfiguration';
        }


        $this->innovatabs = array();

        $this->innovatabs [] = array(
            "title" => $this->l('General configuration'),
            "icon" => "wrench",
            "link" => "helpGenerateForm",
            "type" => "tab",
            "show" => "both",
            "active" => $locked
        );

        if (!$locked) {
            $this->innovatabs [] = array(
                "title" => $this->l('Configurer'),
                "icon" => "list",
                "link" => "renderConfigurationList",
                "type" => "tab",
                "show" => "both",
                "active" => ($current_cat == 'renderConfigurationList') ? true : false,
            );

            $this->innovatabs [] = array(
                "title" => $this->l('Components'),
                "icon" => "list",
                "link" => "renderComponentList",
                "type" => "tab",
                "show" => "both",
                "active" => ($current_cat == 'renderComponentList') ? true : false,
            );
        }

        $this->innovatabs [] = array(
            "title" => $this->l('Documentation'),
            "icon" => "file",
            "link" => $this->doclink,
            "type" => "doc",
            "show" => "both",
        );

        $this->innovatabs [] = array(
            "title" => $this->l('Support'),
            "icon" => "life-saver",
            "link" => $isoLinks["support"],
            "type" => "url",
            "show" => "whmcs",
        );

        if (!$locked) {
            if (Tools::isSubmit('updatecomponent') || Tools::isSubmit('editComponentStay') || Tools::isSubmit('submitComponentStay') || Tools::isSubmit('submitCloneComponent') || Tools::isSubmit('submitGenerateComponent')) {
                $this->innovatabs [] = array(
                    "title" => $this->l('Edit component'),
                    "icon" => "pencil",
                    "link" => 'renderEditComponent',
                    "type" => "tab",
                    "show" => "both",
                    "active" => true
                );
            } else {
                $this->innovatabs [] = array(
                    "title" => $this->l('New component'),
                    "icon" => "plus-circle",
                    "link" => 'renderFormAddComponent',
                    "type" => "tab",
                    "show" => "both",
                );
            }

            if (Tools::isSubmit('updateconfiguration') || Tools::isSubmit('submitConfigurationStay') || Tools::isSubmit('updateidxrcustomproduct_configurations')) {
                $this->innovatabs [] = array(
                    "title" => $this->l('Edit configuration'),
                    "icon" => "pencil",
                    "link" => 'renderFormAddConfiguration',
                    "type" => "tab",
                    "show" => "both",
                    "active" => true
                );
            } else {
                $this->innovatabs [] = array(
                    "title" => $this->l('New configuration'),
                    "icon" => "plus-circle",
                    "link" => 'renderFormAddConfiguration',
                    "type" => "tab",
                    "show" => "both",
                );
            }
        }

        $this->innovatabs[] = array(
            "title" => $this->l('Our Modules'),
            "icon" => "cubes",
            "link" => $isoLinks["ourmodules"],
            "type" => "url",
            "show" => "both",
        );
    }

    public function innovaTitle()
    {
        //tabs version
        $innovaTabs = "";
        if (method_exists(get_class($this), "setInnovaTabs")) {
            $innovaTabs = $this->setInnovaTabs();
        }
        $this->smarty->assign(array(
            "module_dir" => $this->_path,
            "module_name" => $this->displayName,
            "module_description" => $this->description,
            "isoLinks" => InnovaTools_2_0_0::getIsoLinks($this),
            "isAddons" => InnovaTools_2_0_0::isAddons($this),
            "tabs" => InnovaTools_2_0_0::getVersionTabs($this),
        ));

        $this->context->controller->addCSS(($this->_path) . "views/css/backinnova.css", "all");
        return $this->display(__FILE__, "views/templates/admin/innova-title.tpl");
    }

    public function fixCategoryProductPosition()
    {
        //Backup de la tabla
        if(!Db::getInstance()->execute('create table '._DB_PREFIX_.'category_product_bk select * from '._DB_PREFIX_.'category_product;')) {
            return false;
        }

        $categories = Db::getInstance()->executeS('select distinct id_category from '._DB_PREFIX_.'category_product where position = 0;');
        foreach ($categories as $category) {
            $id_category = $category['id_category'];
            $products = Db::getInstance()->executeS('select distinct id_product from '._DB_PREFIX_.'category_product where id_category = '.(int)$id_category.' and position = 0;');
            foreach ($products as $product) {
                $new_position = Db::getInstance()->getValue('select MAX(position)+1 from '._DB_PREFIX_.'category_product where id_category = '.(int)$id_category);
                $data = array('position' => (int)$new_position);
                $where = 'id_product = '.(int)$product['id_product'].' and id_category = '.(int)$id_category;
                Db::getInstance()->update('category_product',$data,$where);
            }
        }
    }
}
