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

class HDColumn extends ObjectModel
{
    public $name;
    public $title;
    public $placeholder;
    public $required;
    public $type;
    public $field_type;
    public $field_length;
    public $description;
    public $display_field;
    public $display_field_admin;
    public $active;
    public $metadata;
    public $default;
    public $position;
    public static $definition = array(
        'table' => 'ets_hd_column',
        'primary' => 'id_ets_hd_column',
        'multilang' => true,
        'fields' => array(
            'name' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 255),
            'required' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
            'type' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 255),
            'field_type' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 255),
            'field_length' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml', 'size' => 255),
            'display_field' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
            'display_field_admin' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
            'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
            'default' => array('type' => self::TYPE_STRING, 'validate' => 'isCleanHtml'),
            'position' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
            // Lang fields
            'title' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCleanHtml', 'size' => 255),
            'placeholder' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCleanHtml', 'size' => 255),
            'description' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCleanHtml', 'size' => 255),
        )
    );

    public static function getColumn($name, $type = 'file')
    {
        $dq = new DbQuery();
        $dq
            ->select('*')
            ->from('ets_hd_column', 'c')
            ->where('c.name=\'' . pSQL(trim($name)) . '\'');
        if (trim($type) !== '') {
            $dq
                ->where('c.type=\'' . pSQL($type) . '\'');
        }
        return Db::getInstance()->getRow($dq);
    }

    /**
     * @param int $id
     * @param false $active
     * @param int $nb
     * @param int $p
     * @param int $n
     * @param string $sort_by
     * @param Context $context
     * @return array|bool|int|mysqli_result|PDOStatement|resource|null
     * @throws PrestaShopDatabaseException
     */
    public static function getColumns($id = 0, $active = false, $nb = 0, $p = 0, $n = 0, $sort_by = null, $context = null)
    {
        if ($context == null) {
            $context = Context::getContext();
        }
        $dq = new DbQuery();
        $dq
            ->from('ets_hd_column', 'c')
            ->leftJoin('ets_hd_column_lang', 'cl', 'c.id_ets_hd_column = cl.id_ets_hd_column AND cl.id_lang=' . (int)$context->language->id);

        if ($id > 0) {
            $dq
                ->select('*')
                ->where('c.id_ets_hd_column=' . (int)$id);

            return Db::getInstance()->getRow($dq);
        }

        if ($active) {
            $dq->where('c.active=' . (int)$active);
        }

        if ($nb) {
            $dq->select('COUNT(c.id_ets_hd_column)');

            return (int)Db::getInstance()->getValue($dq);
        } else {
            $dq->select('*');
            if ($sort_by === null) {
                $sort_by = 'c.position ASC';
            }
            if (trim($sort_by) !== '') {
                $dq->orderBy($sort_by);
            }
            if ($p > 0 && $n > 0)
                $dq->limit($p * ($n - 1), $n);

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

    /**
     * @param int $id_ets_hd_column
     * @param null $idLang
     * @return array|bool|int|mysqli_result|PDOStatement|resource|null
     * @throws PrestaShopDatabaseException
     */
    public static function getColumnOptions($id_ets_hd_column = null, $idLang = null)
    {
        if ((int)$id_ets_hd_column <= 0 ||
            !Validate::isUnsignedId($id_ets_hd_column)
        ) {
            return false;
        }
        $dq = new DbQuery();
        $dq
            ->select('co.position,o.*')
            ->from('ets_hd_column_option', 'co')
            ->leftJoin('ets_hd_option', 'o', 'co.id_ets_hd_option = o.id_ets_hd_option');

        if ($idLang > 0) {
            $dq
                ->select('ol.title')
                ->leftJoin('ets_hd_option_lang', 'ol', 'ol.id_ets_hd_option = o.id_ets_hd_option AND ol.id_lang=' . (int)$idLang);
        }
        $dq
            ->where('co.id_ets_hd_column = ' . (int)$id_ets_hd_column)
            ->orderBy('co.position ASC');

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

    public function addOptions($options)
    {
        if ($this->id > 0
            && is_array($options)
            && count($options) > 0
            && Validate::isArrayWithIds($options)
        ) {
            $data = array();
            foreach ($options as $option) {
                $data[] = array(
                    'id_ets_hd_column' => (int)$this->id,
                    'id_ets_hd_option' => (int)$option,
                    'position' => $this->lastPositionOption() + 1,
                );
            }
            if (is_array($data)
                && count($data) > 0
            ) {
                return Db::getInstance()->insert('ets_hd_column_option', $data, true, true, Db::INSERT_IGNORE);
            }
        }

        return false;
    }

    public function updatePositionOptions($indexes)
    {
        if ($this->id > 0
            && is_array($indexes)
            && count($indexes) > 0
        ) {
            $queries = array();
            $part = 'UPDATE `' . _DB_PREFIX_ . 'ets_hd_column_option` SET ';
            foreach ($indexes as $id_ets_hd_option => $index) {
                $queries[] = $part . '`position` = ' . (int)$index . ' WHERE id_ets_hd_column=' . (int)$this->id . ' AND id_ets_hd_option=' . (int)$id_ets_hd_option;
            }
            return Db::getInstance()->execute(implode(';', $queries));
        }

        return false;
    }

    public function lastPositionOption()
    {
        return (int)Db::getInstance()->getValue('SELECT MAX(`position`) FROM `' . _DB_PREFIX_ . 'ets_hd_column_option` WHERE id_ets_hd_column=' . (int)$this->id);
    }

    public function removeOptions($options)
    {
        if ($this->id > 0
            && is_array($options)
            && count($options) > 0
            && Validate::isArrayWithIds($options)
        ) {
            $res = Db::getInstance()->delete('ets_hd_column_option', 'id_ets_hd_column=' . (int)$this->id . ' AND id_ets_hd_option IN (' . implode(',', $options) . ')');
            $res &= $this->cleanPositionOption();

            return $res;
        }

        return false;
    }

    public function lastPosition()
    {
        return (int)Db::getInstance()->getValue('SELECT MAX(`position`) FROM `' . _DB_PREFIX_ . 'ets_hd_column`');
    }

    public function delete()
    {
        if (!parent::delete()) {
            return false;
        }

        if (!Db::getInstance()->execute('
                DELETE co, o, ol
                FROM `' . _DB_PREFIX_ . 'ets_hd_column_option` co
                LEFT JOIN `' . _DB_PREFIX_ . 'ets_hd_option` o ON (o.id_ets_hd_option = co.id_ets_hd_option)
                LEFT JOIN `' . _DB_PREFIX_ . 'ets_hd_option_lang`ol ON (ol.id_ets_hd_option = o.id_ets_hd_option)
                WHERE co.`id_ets_hd_column` = ' . (int)$this->id . '
            ')) {
            return false;
        }
        // update positions
        $this->cleanPosition();

        return true;
    }

    public function cleanPosition()
    {
        $res = Db::getInstance()->execute('SET @position:=0', false);
        $res &= Db::getInstance()->execute('UPDATE `' . _DB_PREFIX_ . 'ets_hd_column` SET position=(@position:=@position+1) ORDER BY position ASC');

        return $res;
    }

    public function cleanPositionOption()
    {
        $res = Db::getInstance()->execute('SET @position:=0', false);
        $res &= Db::getInstance()->execute('UPDATE `' . _DB_PREFIX_ . 'ets_hd_column_option` SET position=(@position:=@position+1) WHERE id_ets_hd_column=' . (int)$this->id . ' ORDER BY position ASC');

        return $res;
    }

    public function updatePosition($previousId = 0)
    {
        $move_position = $this->position;

        if ($previousId > 0) {
            $previous = new HDColumn($previousId);
            if (!$previous->id)
                return false;
            if ($previous->position > 0)
                $this->position = ($previous->position < $move_position ? ($previous->position + 1) : $previous->position);
            else
                $this->position = 1;
        } else
            $this->position = 1;

        if ($move_position != $this->position && $this->update()) {
            if ($this->position < $move_position) {
                $sql = "UPDATE `" . _DB_PREFIX_ . "ets_hd_column`
                        SET position = position + 1 
                        WHERE position != 0 AND position >= " . (int)$this->position . " AND position <= " . (int)$move_position . " AND id_ets_hd_column != " . (int)$this->id;
            } else {
                $sql = "UPDATE `" . _DB_PREFIX_ . "ets_hd_column`
                        SET position = position - 1 
                        WHERE position != 0 AND position <= " . (int)$this->position . " AND position >= " . (int)$move_position . " AND id_ets_hd_column != " . (int)$this->id;
            }

            return Db::getInstance()->execute($sql);
        }

        return false;
    }

    public static function hasOptions($type)
    {
        return $type !== '' && in_array($type, array(
                'radio',
                'checkbox',
                'select',
            ));
    }

    public static function getColumnFields($context = null, $display_field = false, $is_staff = false)
    {
        if ($context == null) {
            $context = Context::getContext();
        }
        $fields = array();
        $columns = self::getColumns(0, true);
        $fields_length = HDDefines::getInstance()->getConfigsFieldType();
        if (is_array($columns) && count($columns) > 0) {
            foreach ($columns as $column) {
                if (isset($column['name'])
                    && trim(($key = trim($column['name']))) !== ''
                    && isset($column['type'])
                    && trim($column['type']) !== ''
                    && (!$display_field || !$is_staff && $column['display_field'] || $is_staff && $column['display_field_admin'])
                ) {
                    $fields[$key] = array(
                        'name' => $column['name'],
                        'type' => $column['type'] !== 'email' && $column['type'] !== 'numeric' ? $column['type'] : 'text',
                        'label' => isset($column['title']) && trim($column['title']) !== '' ? $column['title'] : Tools::ucfirst(str_replace('_', ' ', $column['name'])),
                        'size' => isset($column['field_length']) && (int)$column['field_length'] > 0 ? (int)$column['field_length'] : '',
                        'field_type' => isset($column['field_type']) ? $column['field_type'] : 'varchar',
                    );
                    $multiple = false;
                    if (isset($column['multiple']) && (int)$column['multiple'] > 0 || trim($column['type']) == 'checkbox') {
                        $multiple = true;
                        $fields[$key]['multiple'] = $multiple;
                    }

                    $field_type = $fields[$key]['field_type'];

                    if (trim($column['type']) == 'email') {
                        $fields[$key]['validate'] = 'isEmail';
                        $fields[$key]['col'] = 3;
                    } elseif (isset($fields_length[$field_type])) {
                        $fields[$key]['validate'] = isset($fields_length[$field_type]['validate']) ? trim($fields_length[$field_type]['validate']) : 'isCleanHtml';
                    }
                    if (trim($fields[$key]['size']) === '') {
                        $fields[$key]['size'] = isset($fields_length[$field_type]['default']) ? $fields_length[$field_type]['default'] : '';
                    }
                    switch ($field_type) {
                        case 'tinyint':
                            $fields[$key]['size'] = 127;
                            break;
                        case 'int':
                            $fields[$key]['size'] = 2147483647;
                            break;
                        case 'decimal':
                            if ($fields[$key]['size'] === '') {
                                $fields[$key]['size'] = array(
                                    HDTools::lastNumber(14),
                                    HDTools::lastNumber(6)
                                );
                            } else {
                                $number_split = explode(',', $fields[$key]['size']);
                                $fields[$key]['size'] = array(
                                    HDTools::lastNumber((int)$number_split[0] - (int)$number_split[1]),
                                    HDTools::lastNumber(isset($number_split[1]) && $number_split[1] > 0 ? $number_split[1] : 6)
                                );
                            }
                            break;
                        case 'char':
                        case 'varchar':
                            if (trim($fields[$key]['size']) === '') {
                                $fields[$key]['size'] = 255;
                            }
                            $fields[$key]['maxlength'] = (int)$fields[$key]['size'];
                            break;
                        case 'text':
                            if (trim($fields[$key]['size']) === '') {
                                $fields[$key]['size'] = 65535;//65535;
                            }
                            $fields[$key]['maxlength'] = (int)$fields[$key]['size'];
                            break;
                        case 'mediumtext':
                            if (trim($fields[$key]['size']) === '') {
                                $fields[$key]['size'] = 16777215;;
                            }
                            $fields[$key]['maxlength'] = (int)$fields[$key]['size'];
                            break;
                        case 'longtext':
                            if (trim($fields[$key]['size']) === '') {
                                $fields[$key]['size'] = 4294967295;;
                            }
                            $fields[$key]['maxlength'] = (int)$fields[$key]['size'];
                            break;
                    }

                    $options = self::hasOptions(trim($column['type'])) ? HDOption::getOptions((int)$column['id_ets_hd_column'], $context->language->id) : array();
                    if (isset($column['id_ets_hd_column'])
                        && $column['id_ets_hd_column'] > 0
                        && $options
                    ) {
                        if ($display_field) {
                            $fields[$key]['class'] = 'fixed-width-lg';
                            foreach ($options as $option) {
                                $fields[$column['name']]['list'][] = array(
                                    'id' => trim($option['title']),
                                    'name' => trim($option['title'])
                                );
                            }
                        } else {
                            $fields[$column['name']]['options'] = array(
                                'query' => $options,
                                'id' => 'title',
                                'name' => 'title',
                            );
                        }
                    }
                    if ($display_field) {
                        $fields[$key]['filter'] = 'a.' . $key;
                    } else {
                        $default = isset($column['default']) ? $column['default'] : '';
                        if (isset($options) && $options) {
                            $default = array();
                            foreach ($options as $option) {
                                if (isset($option['default']) && $option['default']) {
                                    $default[] = $option['title'];
                                    if (!$multiple) {
                                        break;
                                    }
                                }
                            }
                            $default = implode(PHP_EOL, $default);
                        }
                        $fields[$key] = array_merge($fields[$key], array(
                            'required' => isset($column['required']) && (int)$column['required'] > 0,
                            'placeholder' => isset($column['placeholder']) ? $column['placeholder'] : '',
                            'desc' => isset($column['description']) ? $column['description'] : '',
                            'default' => $default,
                            'form_group_class' => 'ets_hd_custom_field',
                        ));
                    }
                }
            }
        }

        return $fields;
    }
}