<?php
/**
 * Copyright (C) 2019 Futurenext srl
 *
 * This file is part of Zakeke.
 *
 * Zakeke Interactive Product Designer can not be copied and/or distributed
 * without the express permission of Futurenext srl
 *
 * @author    Futurenext srl <help@zakeke.com>
 * @copyright 2019 Futurenext srl
 * @license   https://portal.zakeke.com/Contracts/GeneralConditions
 */

if (!defined('_PS_VERSION_')) {
    exit;
}

include_once dirname(__FILE__) . '/webservice/WebserviceSpecificManagementZakekeCurrency.php';
include_once dirname(__FILE__) . '/classes/ZakekeEnabled.php';
include_once dirname(__FILE__) . '/classes/ZakekeConfiguratorEnabled.php';
include_once dirname(__FILE__) . '/classes/ZakekeApi.php';
include_once dirname(__FILE__) . '/classes/ZakekeItem.php';
include_once dirname(__FILE__) . '/classes/ZakekeConfiguratorItem.php';
include_once dirname(__FILE__) . '/classes/ZakekePrice.php';
include_once dirname(__FILE__) . '/classes/ZakekeCompatibility.php';
include_once dirname(__FILE__) . '/classes/ZakekeOrderService.php';
include_once dirname(__FILE__) . '/classes/ZakekeDisplayCustomization.php';

define('ZAKEKE_VERSION', '3.0.0');

class Zakeke extends Module
{
    /** @var ZakekeApi */
    protected $zakekeApi;

    /** @var bool */
    private $cart_action_is_executing = false;

    /**
     * Zakeke constructor.
     */
    public function __construct()
    {
        $this->name = 'zakeke';
        $this->tab = 'front_office_features';
        $this->version = '3.0.0';
        $this->author = 'Futurenext srl';
        $this->need_instance = 0;
        $this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
        $this->bootstrap = true;

        $this->module_key = '8b06b71e6e82c5824a020e70178a4e1a';

        parent::__construct();

        $this->displayName = $this->l('Zakeke Interactive Product Designer');
        $this->description = $this->l(
            'Innovative platforms to enable your customers with live product customization on your e-store.'
        );

        $this->confirmUninstall = $this->l('Are you sure you want to uninstall?');

        if (!$this->hasAccountConnected()) {
            $this->warning = $this->l('You must set your Zakeke credentials');
        }

        $this->zakekeApi = new ZakekeApi($this->isDebugModeActive());
    }

    /**
     * Check if the module has all necessary data to work properly
     *
     * @return bool
     */
    private function hasAccountConnected()
    {
        return Configuration::get('ZAKEKE_API_CLIENT_ID') &&
            Configuration::get('ZAKEKE_API_SECRET_KEY');
    }

    /**
     * Check if Zakeke is in debug mode.
     *
     * @return bool
     */
    private function isDebugModeActive()
    {
        $debug = Configuration::get('ZAKEKE_DEBUG');

        return $debug && $debug == 'yes';
    }

    /**
     * Check if Zakeke is forcing the product customization
     *
     * @return bool
     */
    protected function isForceActive()
    {
        $zakekeForce = Configuration::get('ZAKEKE_FORCE');

        return $zakekeForce == 1;
    }

    /**
     * Get an instance of the Zakeke API.
     *
     * @return ZakekeApi
     */
    public function getZakekeApi()
    {
        return $this->zakekeApi;
    }

    /**
     * Get an identifier for the Zakeke guest
     *
     * @param bool $create Create a Zakeke guest cookie if not present
     *
     * @return string
     */
    public function getZakekeGuestCode($create = true)
    {
        $guestCode = $this->context->cookie->zakeke_guest;
        if ($create && !$guestCode) {
            if (_PS_VERSION_ < 1.7) {
                $guestCode = Tools::passwdGen(90, 'RANDOM');
            } else {
                $guestCode = PhpEncryption::createNewRandomKey();
            }

            $this->context->cookie->zakeke_guest = $guestCode;
            $this->context->cookie->write();
        }

        return Tools::substr($guestCode, 0, 90);
    }

    public function displayForm()
    {
        // Get default language
        $default_lang = (int)Configuration::get('PS_LANG_DEFAULT');

        // Init Fields form array
        $fields_form = array();

        $fields_form[] = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('Zakeke API keys'),
                ),
                'input' => array(
                    array(
                        'type' => 'text',
                        'label' => $this->l('Zakeke API Client ID'),
                        'name' => 'ZAKEKE_API_CLIENT_ID',
                        'desc' => vsprintf(
                            $this->l('Your Zakeke account API. Need a Zakeke account? %sClick here to get one%s'),
                            array('<a href="https://portal.zakeke.com/Admin/Register" target="_blank">', '</a>')
                        ),
                        'required' => true,
                        'class' => 'fixed-width-xl'
                    ),
                    array(
                        'type' => 'password',
                        'label' => $this->l('Zakeke API Secret Key'),
                        'name' => 'ZAKEKE_API_SECRET_KEY',
                        'desc' => $this->l('Your Zakeke account API secret key.'),
                        'required' => true,
                        'class' => 'fixed-width-xl'
                    )
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                    'class' => 'btn btn-default pull-right',
                    'name' => 'ZAKEKE_SAVE_CREDENTIALS'
                )
            )
        );

        $fields_form[] = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('Settings'),
                ),
                'input' => array(
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Force product customization'),
                        'name' => 'ZAKEKE_FORCE',
                        'desc' => $this->l(
                            'Your customers will be forced to customize the product before adding it to cart.'
                        ),
                        'align' => 'center',
                        'active' => 'status',
                        'orderby' => false,
                        'class' => 'fixed-width-xs',
                        'values' => array(
                            array(
                                'id' => 'active_on',
                                'value' => 1,
                                'label' => $this->l('Enabled')
                            ),
                            array(
                                'id' => 'active_off',
                                'value' => 0,
                                'label' => $this->l('Disabled')
                            )
                        ),
                    )
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                    'class' => 'btn btn-default pull-right',
                    'name' => 'ZAKEKE_SAVE_SETTINGS'
                )
            )
        );

        $helper = new HelperForm();

        // Module, token and currentIndex
        $helper->module = $this;
        $helper->name_controller = $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;

        // Language
        $helper->default_form_language = $default_lang;
        $helper->allow_employee_form_lang = $default_lang;

        // Title and toolbar
        $helper->title = $this->displayName;
        $helper->show_toolbar = true;        // false -> remove toolbar
        $helper->toolbar_scroll = true;      // yes - > Toolbar is always visible on the top of the screen.
        $helper->submit_action = 'submit' . $this->name;
        $helper->toolbar_btn = array(
            'save' =>
                array(
                    'desc' => $this->l('Save'),
                    'href' => AdminController::$currentIndex . '&configure=' . $this->name . '&save' . $this->name .
                        '&token=' . Tools::getAdminTokenLite('AdminModules'),
                ),
            'back' => array(
                'href' => AdminController::$currentIndex . '&token=' . Tools::getAdminTokenLite('AdminModules'),
                'desc' => $this->l('Back to list')
            )
        );

        // Load current value
        $helper->fields_value['ZAKEKE_API_CLIENT_ID'] = Configuration::get('ZAKEKE_API_CLIENT_ID');
        $helper->fields_value['ZAKEKE_API_SECRET_KEY'] = Configuration::get('ZAKEKE_API_SECRET_KEY');
        $helper->fields_value['ZAKEKE_FORCE'] = Configuration::get('ZAKEKE_FORCE');

        return $helper->generateForm($fields_form);
    }

    public function getContent()
    {
        $output = '';

        if (Tools::isSubmit('ZAKEKE_SAVE_CREDENTIALS')) {
            $zakekeApiClientId = (string)Tools::getValue('ZAKEKE_API_CLIENT_ID');
            $zakekeApiSecretKey = (string)Tools::getValue('ZAKEKE_API_SECRET_KEY');

            if (empty($zakekeApiClientId) || empty($zakekeApiSecretKey)) {
                $zakekeApiClientId = '';
                $zakekeApiSecretKey = '';
                $output .= $this->displayError($this->l('Zakeke API Client ID and Secret Key must not be empty'));
            } else {
                if (!$this->getZakekeApi()->checkCredentials($zakekeApiClientId, $zakekeApiSecretKey)) {
                    $zakekeApiClientId = '';
                    $zakekeApiSecretKey = '';
                    $output .= $this->displayError($this->l('Invalid Zakeke API keys'));
                } else {
                    $output .= $this->displayConfirmation($this->l('Zakeke API keys updated'));
                }
            }

            Configuration::updateValue('ZAKEKE_API_CLIENT_ID', $zakekeApiClientId);
            Configuration::updateValue('ZAKEKE_API_SECRET_KEY', $zakekeApiSecretKey);
        } elseif (Tools::isSubmit('ZAKEKE_SAVE_SETTINGS')) {
            $zakekeForce = (string)Tools::getValue('ZAKEKE_FORCE');

            if ($zakekeForce != 0 && $zakekeForce != 1) {
                $output .= $this->displayError($this->l('Invalid or empty value for force customization'));
            } else {
                $output .= $this->displayConfirmation($this->l('Settings updated'));
            }

            Configuration::updateValue('ZAKEKE_FORCE', $zakekeForce);
        }

        $output .= $this->display(__FILE__, 'infos.tpl');

        return $output . $this->displayForm();
    }

    /**
     * Register the Zakeke WS endpoint
     *
     * @param array $params
     *
     * @return array
     */
    public function hookAddWebserviceResources($params)
    {
        return array(
            'zakeke_currency' => array(
                'description' => 'ZakekeCurrency',
                'specific_management' => true,
                'forbidden_method' => array('POST', 'PUT', 'DELETE', 'HEAD')
            ),
            'zakeke_enabled_list' => array('description' => 'Zakeke enabled products', 'class' => 'ZakekeEnabled')
        );
    }

    private function customizerHookDisplayHeaderPS16()
    {
        $customizeButtonLabel = $this->l('Customize');
        $zakekeAddUrl = $this->context->link->getModuleLink('zakeke', 'customizer');

        Media::addJsDef(array(
            'zakekeCustomizeLabel' => addcslashes($customizeButtonLabel, "'"),
            'zakekeAddUrl' => addcslashes($zakekeAddUrl, "'")
        ));

        if ($this->isForceActive()) {
            $this->context->controller->addJS(
                $this->_path . '/views/js/ps16/product-page-force.js'
            );
        } else {
            $this->context->controller->addJS(
                $this->_path . '/views/js/ps16/product-page.js'
            );
        }
    }

    private function configuratorHookDisplayHeaderPS16()
    {
        $customizeButtonLabel = $this->l('Configure');
        $zakekeConfiguratorAddUrl = $this->context->link->getModuleLink('zakeke', 'configurator');

        Media::addJsDef(array(
            'zakekeConfigureLabel' => addcslashes($customizeButtonLabel, "'"),
            'zakekeConfiguratorAddUrl' => addcslashes($zakekeConfiguratorAddUrl, "'")
        ));

        if ($this->isForceActive()) {
            $this->context->controller->addJS(
                $this->_path . '/views/js/ps16/configurator/product-page-force.js'
            );
        } else {
            $this->context->controller->addJS(
                $this->_path . '/views/js/ps16/configurator/product-page.js'
            );
        }
    }

    /**
     * Add the Zakeke elements inside the product page of customizable products for PS 1.6
     */
    public function hookDisplayHeaderPS16()
    {
        try {
            $this->context->controller->addJS(
                $this->_path . '/views/js/ps16/update.js'
            );

            $zakekeInfoUrl = $this->context->link->getModuleLink('zakeke', 'info');
            Media::addJsDef(array(
                'zakekeInfoUrl' => addcslashes($zakekeInfoUrl, "'")
            ));

            if (!method_exists($this->context->controller, 'getProduct')) {
                return;
            }

            $product = $this->context->controller->getProduct();

            if (!$product) {
                return;
            }

            $zakekeEnabledId = ZakekeEnabled::productEnabledId($product->id);
            if ($zakekeEnabledId !== false) {
                $this->customizerHookDisplayHeaderPS16();
            }

            $zakekeConfiguratorEnabledId = ZakekeConfiguratorEnabled::productEnabledId($product->id);
            if ($zakekeConfiguratorEnabledId !== false) {
                $this->configuratorHookDisplayHeaderPS16();
            }
        } catch (Exception $e) {
            PrestaShopLogger::addLog('Zakeke hookDisplayHeader Call error: ' . $e);
            $this->context->controller->errors[] = $this->l('Zakeke failed to initialize');
        }
    }

    private function customizerHookDisplayHeaderPS17()
    {
        $zakekeAddUrl = $this->context->link->getModuleLink('zakeke', 'customizer');
        $customizeButtonLabel = $this->l('Customize');

        Media::addJsDef(array(
            'zakekeAddUrl' => addcslashes($zakekeAddUrl, "'"),
            'zakekeCustomizeLabel' => addcslashes($customizeButtonLabel, "'")
        ));

        if ($this->isForceActive()) {
            $this->context->controller->registerJavascript(
                'modules-zakake-product-page',
                'modules/' . $this->name . '/views/js/product-page-force.js',
                array('position' => 'bottom', 'priority' => 150)
            );
        } else {
            $this->context->controller->registerJavascript(
                'modules-zakake-product-page',
                'modules/' . $this->name . '/views/js/product-page.js',
                array('position' => 'bottom', 'priority' => 150)
            );
        }
    }

    private function configuratorHookDisplayHeaderPS17()
    {
        $configureButtonLabel = $this->l('Configure');
        $zakekeConfiguratorAddUrl = $this->context->link->getModuleLink('zakeke', 'configurator');

        Media::addJsDef(array(
            'zakekeConfigureLabel' => addcslashes($configureButtonLabel, "'"),
            'zakekeConfiguratorAddUrl' => addcslashes($zakekeConfiguratorAddUrl, "'")
        ));

        if ($this->isForceActive()) {
            $this->context->controller->registerJavascript(
                'modules-zakake-configurator-product-page',
                'modules/' . $this->name . '/views/js/configurator/product-page-force.js',
                array('position' => 'bottom', 'priority' => 150)
            );
        } else {
            $this->context->controller->registerJavascript(
                'modules-zakake-configurator-product-page',
                'modules/' . $this->name . '/views/js/configurator/product-page.js',
                array('position' => 'bottom', 'priority' => 150)
            );
        }
    }

    /**
     * Add the Zakeke elements inside the product page of customizable products
     */
    public function hookDisplayHeaderPS17()
    {
        try {
            if (!method_exists($this->context->controller, 'getProduct')) {
                return;
            }

            $product = $this->context->controller->getProduct();
            if (!$product) {
                return;
            }

            $zakekeEnabledId = ZakekeEnabled::productEnabledId($product->id);
            if ($zakekeEnabledId !== false) {
                $this->customizerHookDisplayHeaderPS17();
            }

            $zakekeConfiguratorEnabledId = ZakekeConfiguratorEnabled::productEnabledId($product->id);
            if ($zakekeConfiguratorEnabledId !== false) {
                $this->configuratorHookDisplayHeaderPS17();
            }
        } catch (Exception $e) {
            PrestaShopLogger::addLog('Zakeke hookDisplayHeader Call error: ' . $e);
            $this->context->controller->errors[] = $this->l('Zakeke failed to initialize');
        }
    }

    /**
     * Add the Zakeke elements inside the product page of customizable products
     *
     * @param array $params
     */
    public function hookDisplayMobileHeader($params)
    {
        if (_PS_VERSION_ < 1.7) {
            $this->hookDisplayHeaderPS16();
        }
    }

    /**
     * Add the Zakeke elements inside the product page of customizable products
     *
     * @param array $params
     */
    public function hookDisplayHeader($params)
    {
        if (_PS_VERSION_ < 1.7) {
            $this->hookDisplayHeaderPS16();
        } else {
            $this->hookDisplayHeaderPS17();
        }
    }

    /**
     * dd the Zakeke elements inside the Prestashop's admin
     *
     * @param array $params
     */
    public function hookActionAdminControllerSetMedia($params)
    {
        if (_PS_VERSION_ < 1.7) {
            $zakekeAdminInfo = $this->context->link->getAdminLink('AdminZakeke');
            Media::addJsDef(array(
                'zakekeAdminInfo' => addcslashes($zakekeAdminInfo, "'")
            ));
            $this->context->controller->addJS($this->_path . 'views/js/ps16/admin_update.js');
        }
    }

    /**
     * Correctly display the Zakeke customization both on FO and BO
     *
     * @param array $params
     *
     * @return string
     */
    public function hookDisplayCustomization($params)
    {
        try {
            $customization = $params['customization'];
            $zakekeData = json_decode($customization['value'], true);

            $zakekeDisplayCustomization = new ZakekeDisplayCustomization($this->getZakekeApi(), $this->context);
            $templatesVariables = $zakekeDisplayCustomization->getTemplatesVariables($zakekeData);
            $this->context->smarty->assign($templatesVariables);

            return $this->display(__FILE__, 'displayCustomization.tpl');
        } catch (Exception $e) {
            PrestaShopLogger::addLog('Zakeke hookDisplayCustomization Call error: ' . $e);
            $this->context->controller->errors[] = $this->l('Zakeke failed to get the customization details');
        }
    }

    /**
     * Correctly display the Zakeke customization both on FO and BO
     *
     * @param array $params
     *
     * @return string
     */
    public function hookDisplayCartExtraProductActions($params)
    {
        try {
            $product = $params['product'];

            if (!isset($product['id_customization'])) {
                return '';
            }

            $id_customization = $product['id_customization'];
            $customization_data = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(
                'SELECT `value` FROM `' . _DB_PREFIX_ . 'customized_data` 
                            WHERE `id_customization` = ' . (int)($id_customization)
            );
            if (!$customization_data) {
                return '';
            }

            if (_PS_VERSION_ < 1.7) {
                $id_zakeke_configuration_item = ZakekeConfiguratorItem::zakekeConfiguratorItemId($customization_data);
                if ($id_zakeke_configuration_item === false) {
                    return '';
                }

                $configuration = $customization_data;
            } else {
                try {
                    $zakekeData = json_decode($customization_data, true);
                    if (!isset($zakekeData['c'])) {
                        return '';
                    }

                    $configuration = $zakekeData['c'];
                } catch (Exception $e) {
                    return '';
                }
            }

            $inputArray = array(
                'id_product' => $product['id_product'],
                'configuration' => $configuration,
                'token' => Tools::getToken(false),
                'qty' => $product['cart_quantity'],
                'remove_from_cart_url' => $product['remove_from_cart_url']
            );
            $id_product_attribute = $product['id_product_attribute'];
            $combination = new Combination($id_product_attribute);
            foreach ($combination->getWsProductOptionValues() as $idx => $value) {
                $inputArray['group[' . ($idx + 1) . ']'] = $value['id'];
            }
            $edit_url = $this->context->link->getModuleLink('zakeke', 'configurator', $inputArray);
            $this->context->smarty->assign('zakeke_edit_url', $edit_url);
            return $this->display(__FILE__, 'displayCartExtraProductActions.tpl');
        } catch (Exception $e) {
            PrestaShopLogger::addLog('Zakeke hookDisplayCartExtraProductActions Call error: ' . $e);
            $this->context->controller->errors[] = $this->l('Zakeke failed to get the edit link');
        }
    }

    /**
     * Register orders that contains Zakeke products
     *
     * @param array $params
     */
    public function hookDisplayOrderConfirmation($params)
    {
        try {
            /** @var Order $order */
            $order = null;

            if (_PS_VERSION_ < 1.7) {
                $order = $params['objOrder'];
            } else {
                $order = $params['order'];
            }

            $zakekeOrderService = new ZakekeOrderService($this);
            $zakekeOrderService->process($order);
        } catch (Exception $e) {
            PrestaShopLogger::addLog('Zakeke hookDisplayOrderConfirmation Call error: ' . $e);
            $this->context->controller->errors[] = $this->l('Zakeke failed to register the order');
        }
    }

    /**
     * Register the Admin controller for Zakeke
     *
     * @return bool
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     */
    public function createAjaxController()
    {
        $tab = new Tab();
        $tab->active = 1;
        $languages = Language::getLanguages(false);
        if (is_array($languages)) {
            foreach ($languages as $language) {
                $tab->name[$language['id_lang']] = 'zakeke';
            }
        }
        $tab->class_name = 'AdminZakeke';
        $tab->module = $this->name;
        $tab->id_parent = -1;
        return (bool)$tab->add();
    }

    /**
     * Associate a Zakeke guest to the store customer
     *
     * @param $params
     */
    public function hookActionAuthentication($params)
    {
        try {
            /** @var Customer $customer */
            $customer = $params['customer'];

            $zakekeGuestCode = $this->getZakekeGuestCode(false);

            if (!$zakekeGuestCode) {
                return;
            }

            $this->getZakekeApi()->associateGuest($zakekeGuestCode, $customer->id);
        } catch (Exception $e) {
            PrestaShopLogger::addLog('Zakeke hookActionAuthentication Call error: ' . $e);
            $this->context->controller->errors[] = $this->l('Zakeke failed to associate the guest user');
        }
    }

    public function hookActionCartSave()
    {
        if ($this->cart_action_is_executing || _PS_VERSION_ >= 1.7) {
            return;
        }

        $this->cart_action_is_executing = true;
        ZakekePrice::updateCartZakekePrice($this->context);
        $this->cart_action_is_executing = false;
    }

    public function installDB()
    {
        $return = true;
        $return &= Db::getInstance()->execute('
            CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'zakeke_enabled` (
                `id_zakeke_enabled` INT UNSIGNED NOT NULL AUTO_INCREMENT,
                `id_product` int(11) NOT NULL,
                PRIMARY KEY (`id_zakeke_enabled`),
                UNIQUE KEY `id_product` (`id_product`)
            ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 ;');

        $return &= Db::getInstance()->execute('
            CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'zakeke_item` (
                `id_zakeke_item` INT UNSIGNED NOT NULL AUTO_INCREMENT,
                `id_item` varchar(254) NOT NULL,
                `preview` varchar(254) NOT NULL,
                `pricing_json` varchar(254) NOT NULL,
                PRIMARY KEY (`id_zakeke_item`),
                UNIQUE KEY `id_item` (`id_item`)
            ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 ;');

        $return &= Db::getInstance()->execute('
            CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'zakeke_configurator_enabled` (
                `id_zakeke_configurator_enabled` INT UNSIGNED NOT NULL AUTO_INCREMENT,
                `id_product` int(11) NOT NULL,
                PRIMARY KEY (`id_zakeke_configurator_enabled`),
                UNIQUE KEY `id_product` (`id_product`)
            ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 ;');

        $return &= Db::getInstance()->execute('
            CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'zakeke_configurator_item` (
                `id_zakeke_configurator_item` INT UNSIGNED NOT NULL AUTO_INCREMENT,
                `id_configurator_item` varchar(254) NOT NULL,
                `preview` varchar(254) NOT NULL,
                `price` DECIMAL(20,6) NOT NULL,
                `items_json` varchar(6000) NOT NULL,
                PRIMARY KEY (`id_zakeke_configurator_item`),
                UNIQUE KEY `id_item` (`id_configurator_item`)
            ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 ;');

        return $return;
    }

    private function registerHooks()
    {
        $result = $this->registerHook('displayHeader') &&
            $this->registerHook('displayOrderConfirmation');

        if (_PS_VERSION_ < 1.7) {
            return $result
                && $this->registerHook('displayMobileHeader')
                && $this->registerHook('actionAdminControllerSetMedia')
                && $this->registerHook('actionCartSave')
                && $this->createAjaxController();
        }

        return $result &&
            $this->registerHook('addWebserviceResources') &&
            $this->registerHook('displayCustomization') &&
            $this->registerHook('displayCartExtraProductActions');
    }

    public function install()
    {
        if (Shop::isFeatureActive()) {
            Shop::setContext(Shop::CONTEXT_ALL);
        }

        return parent::install() &&
            $this->installDB() &&
            $this->registerHooks();
    }

    public function uninstall()
    {
        Configuration::deleteByName('ZAKEKE_FORCE');

        $id_tab = (int)Tab::getIdFromClassName('AdminZakeke');
        if ($id_tab) {
            $tab = new Tab($id_tab);
            $tab->delete();
        }

        return parent::uninstall();
    }
}
