<?php

/**
 * 2007-2018 PrestaShop
 *
 * NOTICE OF LICENSE
 *
 * @author    Innova Deluxe SL
 * @copyright 2018 Innova Deluxe SL

 * @license   INNOVADELUXE
 */
include('IdxOption.php');

class IdxComponent
{

    public $id_component;
    public $name;
    public $type;
    public $optional;
    public $columns;
    public $zoom;
    public $color;
    public $default_opt = -1;
    public $parent = false;
    public $title_lang = array();
    public $description_lang = array();
    public $options_lang = array();
    public $module;
    public $has_constraints = false;
    public $icon_preview = false;
    //only for type file
    public $size;
    public $allowed_extensions = array();

    public function __construct($id_component = null, $full = false, $lang = false)
    {
        if ($id_component) {
            $this->id_component = (int) $id_component;
            if ($full) {
                $this->fillObject($lang);
            }
        }
    }

    public function fillObject($lang = false)
    {
        $q = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components where id_component = ' . (int) $this->id_component;
        $db_row = Db::getInstance()->getRow($q);
        $this->id_component = $db_row['id_component'];
        $this->name = $db_row['name'];
        $this->type = $db_row['type'];
        $this->optional = $db_row['optional'];
        $this->columns = $db_row['columns'];
        $this->zoom = $db_row['zoom'];
        $this->color = $db_row['color'];
        $this->default_opt = $db_row['default_opt'];
        $this->parent = $db_row['parent'];
        $this->generateOptions($lang);
    }

    public function getOptions($lang_id = false)
    {
        if (!$lang_id) {
            return $this->options_lang;
        } else {
            return $this->option_lang[$lang_id];
        }
    }

    public function generateOptions($id_lang = false)
    {
        $lang_q = 'Select * from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang where id_component = ' . (int) $this->id_component;
        if ($id_lang) {
            $lang_q .= ' and id_lang = ' . (int) $id_lang;
        }
        $languages = Db::getInstance()->executeS($lang_q);
        if ($this->type == 'file') {
            $values = array_shift($languages);
            if ($values && $values['json_values']) {
                $values_raw = json_decode($values['json_values']);
                $this->size = $values_raw->size;
                $this->allowed_extensions = $values_raw->allowed_extension;
            }
        } else {
            foreach ($languages as $language) {
                $lang = array();
                $this->title_lang[$language['id_lang']] = $lang['title'] = $language['title'];
                $this->description_lang[$language['id_lang']] = $lang['description'] = $language['description'];
                $lang['options'] = array();
                $options_raw = json_decode($language['json_values']);
                if ($options_raw) {
                    if (isset($options_raw->options)) {
                        foreach ($options_raw->options as $option_raw) {
                            $option_raw->id_component = $this->id_component;
                            $option = new IdxOption($option_raw);
                            $lang['options'][] = $option;
                        }
                    }
                    $this->options_lang[$language['id_lang']] = $lang;
                }
            }
        }
    }
    
    public function add()
    {
        $main_data = $this->getMainTableArray();
        Db::getInstance()->insert('idxrcustomproduct_components', $main_data);
        $this->id_component = Db::getInstance()->Insert_ID();
        $languages = Language::getLanguages(false);
        foreach ($languages as $lang) {
            $data_lang = array(
                'id_component' => (int) $this->id_component,
                'id_lang' => (int)$lang['id_lang'] ,
                'title' => pSQL($this->title_lang[$lang['id_lang']]),
                'description' => pSQL($this->description_lang[$lang['id_lang']])
            );            
            Db::getInstance()->insert('idxrcustomproduct_components_lang', $data_lang);
            unset($data_lang);
        }
        
        return $this->id_component;
    }
    
    public function update()
    {
        $data = $this->getMainTableArray();
        $where = 'id_component = ' . (int) $this->id_component;
        Db::getInstance()->update('idxrcustomproduct_components', $data, $where);
        $languages = Language::getLanguages(false);
        foreach ($languages as $lang) {
            $data = array(
                'title' => pSQL($this->title_lang[$lang['id_lang']]),
                'description' => pSQL($this->description_lang[$lang['id_lang']])
            );
            $where = 'id_component = ' . (int)$this->id_component . ' and id_lang = ' . (int)$lang['id_lang'] . ';';
            Db::getInstance()->update('idxrcustomproduct_components_lang', $data, $where);
        }
    }
    
    private function getMainTableArray()
    {
        $data = array(
            'name' => pSQL($this->name),
            'type' => pSQL($this->type),
            'optional' => (bool)$this->optional,
            'columns' => (int)$this->columns,
            'zoom' => (bool)$this->zoom,
            'color' => pSQL($this->color),
            'default_opt' => (int)$this->default_opt,
            'parent' => (int)$this->parent
        );
        return $data;
    }
    
    public function clone($index = 0)
    {
        $this->fillObject();
        if (!$index) {
            $new_name = $this->name.'_clon';
        } else {
            $new_name = $this->name.'_clon'.(int)$index;
        }
        $exist = Db::getInstance()->getValue('Select id_component from ' . _DB_PREFIX_ . 'idxrcustomproduct_components where name ="'. pSQL($new_name).'"');
        if($exist) {
            $index ++;
            return $this->clone($index);
        }
        
        unset($this->id_component);
        $this->name = $new_name;
        $this->add();
    }

    public function delete()
    {
        $del_components = 'delete from ' . _DB_PREFIX_ . 'idxrcustomproduct_components where id_component = ' . (int)$this->id_component . ';';
        $del_lang = 'delete from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_lang where id_component = ' . (int)$this->id_component . ';';
        $del_impact = 'delete from ' . _DB_PREFIX_ . 'idxrcustomproduct_components_opt_impact where id_component = ' . (int)$this->id_component . ';';
        $del_component_attr = 'delete from ' . _DB_PREFIX_ . 'idxrcustomproduct_component_attribute where id_component = ' . (int)$this->id_component . ';';
        Db::getInstance()->execute($del_components);
        Db::getInstance()->execute($del_lang);
        Db::getInstance()->execute($del_impact);
        Db::getInstance()->execute($del_component_attr);
        
        if ($children = Db::getInstance()->executeS('Select id_component from ' . _DB_PREFIX_ . 'idxrcustomproduct_components where parent = ' . (int)$this->id_component)) {
            foreach ($children as $child) {
                $comp_child = new IdxComponent($child['id_component']);
                $comp_child->delete();
            }
        }
    }
    
    public function getComponentOptions()
    {
        $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) $this->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) $this->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'];
                        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 static function getComponentTypes()
    {
        $module = Module::getInstanceByName('idxrcustomproduct');
        $types = array();
        $types[] = array(
            'id' => 'sel',
            'name' => $module->l('select')
        );
        $types[] = array(
            'id' => 'sel_img',
            'name' => $module->l('select with images')
        );
        $types[] = array(
            'id' => 'text',
            'name' => $module->l('text field')
        );
        $types[] = array(
            'id' => 'file',
            'name' => $module->l('attach a file')
        );
//        $components[] = array(
//            'id' => 'textarea',
//            'name' => $this->l('text area box')
//        );
//        $components[] = array(
//            'id' => 'product',
//            'name' => $this->l('product additional')
//        );
        return $types;
    }

    public static function getComponentColumns()
    {
        $module = Module::getInstanceByName('idxrcustomproduct');
        $columns = array();
        $columns[] = array(
            'id' => '12',
            'name' => $module->l('12 options')
        );
        $columns[] = array(
            'id' => '6',
            'name' => $module->l('6 options')
        );
        $columns[] = array(
            'id' => '4',
            'name' => $module->l('4 options')
        );
        $columns[] = array(
            'id' => '3',
            'name' => $module->l('3 options')
        );
        $columns[] = array(
            'id' => '2',
            'name' => $module->l('2 options')
        );
        $columns[] = array(
            'id' => '1',
            'name' => $module->l('1 options')
        );
        return $columns;
    }

    public static function hasConstraint($id_component, $id_configuration)
    {
        $sql = 'Select constraints_options from ' . _DB_PREFIX_ . 'idxrcustomproduct_configurations where id_configuration = ' . (int) $id_configuration;
        $actual_constraint = Db::getInstance()->getValue($sql);
        if (!$actual_constraint) {
            return false;
        }
        $constraint_array = explode(',', $actual_constraint);
        $contraints = array();
        foreach ($constraint_array as $constraint) {
            if (!$constraint) {
                continue;
            }
            $contraint_parts = explode('@', $constraint);
            if ($contraint_parts[0] == $id_component) {
                $contraints[] = $contraint_parts[1];
            }
        }
        return $contraints;
    }

    public static function generateFromProduct($id_product)
    {        
        //Primero generamos el componente base que va a ser el padre del resto
        $product_name = Product::getProductName($id_product,0,Context::getContext()->language->id);
        $parent = new IdxComponent();
        $parent->name = $product_name;
        $parent->type = 'product';
        $parent->add();
        $data = array(
            'id_component' => (int)$parent->id_component,
            'id_option' => 0,
            'att_product' => (int)$id_product
        );
        Db::getInstance()->insert('idxrcustomproduct_components_opt_impact', $data);
        //Por cada grupo de atributos creamos un componente con sus opciones
        $attr_groups = Db::getInstance()->executeS('
            select att.id_attribute_group from '._DB_PREFIX_.'product_attribute pa
            inner join '._DB_PREFIX_.'product_attribute_combination pac on pa.id_product_attribute = pac.id_product_attribute
            inner join '._DB_PREFIX_.'attribute att on pac.id_attribute = att.id_attribute
            where pa.id_product = '.(int)$id_product.' 
            group by att.id_attribute_group;');
        foreach ($attr_groups as $attr_group) {
            $attribute_group = new AttributeGroup($attr_group['id_attribute_group']);
            
            $attr_comp = new IdxComponent();
            $attr_comp->name = $product_name.' - '.$attribute_group->name[Context::getContext()->language->id];
            //if ($attribute_group->is_color_group) { //No da tiempo en este desarrollo
            //    $attr_comp->type = 'sel_img';
            //} else {
                $attr_comp->type = 'sel';
            //}
            $attr_comp->optional = false;
            $attr_comp->zoom = false;
            $attr_comp->columns = 4;
            $attr_comp->parent = $parent->id_component;
            $attr_comp->title_lang = $attribute_group->public_name;
            $attr_comp->add();
            
            $comp_attr = array(
                'id_component' => (int)$attr_comp->id_component,
                'id_attribute_group' => (int)$attr_group['id_attribute_group']
            );
            Db::getInstance()->insert('idxrcustomproduct_component_attribute', $comp_attr);
            
            $options = Db::getInstance()->executeS('select distinct pac.id_attribute from '._DB_PREFIX_.'product_attribute pa
                inner join '._DB_PREFIX_.'product_attribute_combination pac on pa.id_product_attribute = pac.id_product_attribute
                inner join '._DB_PREFIX_.'attribute att on pac.id_attribute = att.id_attribute
                where pa.id_product = '.(int)$id_product.' and att.id_attribute_group = '.(int)$attr_group['id_attribute_group'].';');
            
            $languages = Language::getLanguages(false);
            foreach ($languages as $lang) {            
                $values = new stdClass();
                $values->options = array();
                
                foreach($options as $option) {                
                    $ps_option = new AttributeCore($option['id_attribute'], $lang['id_lang']);
                    $idxoption = new stdClass();
                    $idxoption->id = $option['id_attribute'];
                    $idxoption->name = $ps_option->name;
                    $idxoption->description = '';                    
                    $idxoption->img_ext = 'png';
                    $values->options[] = $idxoption;
                }
                $update = array(
                    'json_values' => json_encode($values, JSON_UNESCAPED_UNICODE)
                );
                $where = 'id_component = ' . (int) $attr_comp->id_component . ' and id_lang = ' . (int) $lang['id_lang'];
                Db::getInstance()->update('idxrcustomproduct_components_lang', $update, $where);
            }                       
            
            foreach($options as $option) {
                $idx_option = new IdxOption();
                $idx_option->id = (int)$option['id_attribute'];
                $idx_option->id_component = (int)$attr_comp->id_component;
                $idx_option->add();
            }
            
        }
    }
    
    public static function getChildrenComponent($parent, $language = false)
    {
        if (!$language) {
            $language = Context::getContext()->language->id;
        }
        $childrens = array();
        $constraint = false;
        $components = Db::getInstance()->executeS('Select * from '._DB_PREFIX_.'idxrcustomproduct_components where parent = '.(int)$parent);
        if ($components) {
            $childrens = IdxComponent::generateChildren($components, $parent, $language);
        }
        return $childrens;
    }
    
    public static function generateChildren($components, $parent, $language, $contraint = false, $atttibutes = false)
    {
        if (!$attributes){
            $attributes = array();
        }
        $component = array_shift($components);
        $component_obj = new IdxComponent($component['id_component'],true,$language);
        $attribute_group = self::getAttributeGroupbyComponentId($component['id_component']);
        $json_values = Db::getInstance()->getValue('select json_values from '._DB_PREFIX_.'idxrcustomproduct_components_lang where id_component = '.(int)$component['id_component'].' and id_lang = '.(int)$language);
        $component_array = array(
            "id_component" => $component_obj->id_component.($contraint?'999'.str_replace('_','',$contraint):''),
            "name" => $component_obj->name,
            "type" => $component_obj->type,
            "optional" => $component_obj->optional,
            "columns" => $component_obj->columns,
            "zoom" => $component_obj->zoom,
            "color" => $component_obj->color,
            "default_opt" => $component_obj->default_opt,
            "parent" => $component_obj->parent,
            "id_components_lang" => $component_obj->id_component,
            "id_lang" => $language,
            "title" => $component_obj->title_lang[$language],
            "description" => $component_obj->description_lang[$language],
            "json_values" => $json_values,
            "constraint" => $contraint ? array($contraint) : array()
        );
        
        if (!$components) {//opciones hijo hay que añadir el producto
            $product_id = Db::getInstance()->getValue('Select att_product from '._DB_PREFIX_.'idxrcustomproduct_components_opt_impact where id_component = '.(int)$parent);            
            $options = json_decode($component_array['json_values']);
            foreach ($options->options as &$option) {
                $atttibutes[$attribute_group] = $option->id;
                $id_attributes = implode(',', $atttibutes);
                $id_product_attribute = Db::getInstance()->getValue('select pa.id_product_attribute from '._DB_PREFIX_.'product_attribute pa
                        inner join '._DB_PREFIX_.'product_attribute_combination pac on pa.id_product_attribute = pac.id_product_attribute
                        where pac.id_attribute in ('.$id_attributes.') and pa.id_product = '.(int)$product_id.'
                        group by pa.id_product_attribute order by count(id_product) desc');
                $option->att_product = $product_id.'_'.$id_product_attribute;
            }
            $component_array['json_values'] = json_encode($options);
            $childrens[] = $component_array;
        } else {
            $childrens[] = $component_array;
            $constraints = array_shift($component_obj->options_lang);            
            foreach ($constraints['options'] as $option) {
                $opt_constraint = $option->id_component.'_'.$option->id;
                $atttibutes[$attribute_group] = $option->id;
                $subchildrens = IdxComponent::generateChildren($components, $parent, $language, $opt_constraint, $atttibutes);
                $childrens = array_merge($childrens,$subchildrens);
            }
            
        }
        return $childrens;
    }
    
    private static function getAttributeGroupbyComponentId($component_id)
    {
        return Db::getInstance()->getValue('Select id_attribute_group from '._DB_PREFIX_.'idxrcustomproduct_component_attribute where id_component = '.(int)$component_id); 
    }
    
        
    public static function getComponentIdByProduct($id_product)
    {
        if ($exist = self::existComponentIdByProduct($id_product)) {
            return $exist;
        }
        
        $product_component = self::generateFromProduct($id_product);
        return self::existComponentIdByProduct($id_product);
        
    }
    
    public static function existComponentIdByProduct($id_product)
    {
        return Db::getInstance()->getValue('select comp.id_component from '._DB_PREFIX_.'idxrcustomproduct_components comp'
                    .' inner join '._DB_PREFIX_.'idxrcustomproduct_components_opt_impact compim on comp.id_component = compim.id_component'
                    .' where comp.type = "product" and att_product = '.(int)$id_product.';');        
    }
    
    public static function getProductByCustomization($final_component, $customization)
    {
        $parent = Db::getInstance()->getValue('Select parent from '._DB_PREFIX_.'idxrcustomproduct_components where id_component = '.(int)$final_component);
        $product = Db::getInstance()->getValue('Select att_product from '._DB_PREFIX_.'idxrcustomproduct_components_opt_impact where id_component = '.(int)$parent);        
        $attributes = array();
        foreach($customization as $component) {
            $valid = Db::getInstance()->executeS('Select id_component from '._DB_PREFIX_.'idxrcustomproduct_components where id_component = '.(int)$component['id_component'].' and parent = '.(int)$parent);
            if ($valid) {
                $attributes[] = $component['id_option'];
            }
        }        
        $sql = 'select id_product_attribute from '._DB_PREFIX_.'product_attribute where id_product = '.(int)$product.' and id_product_attribute  in (select id_product_attribute from '._DB_PREFIX_.'product_attribute_combination where id_attribute in ('.implode(',', $attributes).') group by id_product_attribute having count(id_product_attribute) = '.count($attributes).')';
        $id_attribute =  Db::getInstance()->getValue($sql);
        return $product.'_'.($id_attribute?$id_attribute:0);
    }
}



// Para cuando se pueda si el child es un color generar la imagen
//$im = imagecreatetruecolor(100, 100);
//
//// establece el fondo a rojo
//$rojo = imagecolorallocate($im, 255, 0, 0);
//imagefill($im, 0, 0, $rojo);