<?php

class exchangeImportTask extends sfBaseTask
{

    private $g_propertyByInnerId = false;
    private $g_propertyListByInnerId = false;

    protected function configure()
    {
        // // add your own arguments here
        $this->addArguments(array(
            //new sfCommandArgument('file_path', sfCommandArgument::REQUIRED, 'file path'),
            new sfCommandArgument('file_path', sfCommandArgument::OPTIONAL, 'file path', 'import.xml'),
        ));

        $this->addOptions(array(
            new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name', 'www'),
            new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The environment', 'arm'),
            new sfCommandOption('connection', null, sfCommandOption::PARAMETER_REQUIRED, 'The connection name', 'doctrine'),
            // add your own options here
        ));

        $this->namespace = 'exchange';
        $this->name = 'import';
        $this->briefDescription = '';
        $this->detailedDescription = <<<EOF
The [exchange:import|INFO] task does things.
Call it with:

  [php symfony exchange:import|INFO]
EOF;
    }


    protected function execute($arguments = array(), $options = array())
    {
        $task_time_start = date('Y-m-d H:i:s');

        $databaseManager = new sfDatabaseManager($this->configuration);
        $connection = $databaseManager->getDatabase($options['connection'])->getConnection();

        $instance = sfContext::createInstance($this->configuration);

        $file_path = $arguments['file_path'];

        if (file_exists(sfConfig::get('sf_data_dir') . '/exchange/' . $file_path)) {
            $file = simplexml_load_file(sfConfig::get('sf_data_dir') . '/exchange/' . $file_path, 'SimpleXMLIterator');
        } else {
            $this->log('file not exist!');
            die();
        }
        $time_start = microtime(true);
        $category_data = $file->Классификатор->Группы->Группа;
        $category_report = $this->category($category_data);

        $this->log('category import done: [' . round((microtime(true) - $time_start) * 1000) . ' ms]');
        unset($category_data);


        $time_start = microtime(true);
        $property_data = $file->Классификатор->Свойства->Свойство;

        $property_report = $this->property($property_data);
        $this->log('property import done: [' . round((microtime(true) - $time_start) * 1000) . ' ms]');
        unset($property_data);

        $time_start = microtime(true);
        $products_data = $file->Каталог->Товары->Товар;
        $product_report = $this->products($products_data);

        $this->log('products import done: [' . round((microtime(true) - $time_start) * 1000) . ' ms]');
        unset($products_data);


        $mail_body = 'Импорт файла ' . $file_path . ' завершен' . "\n";

        $mail_body .= 'Начало импорта ' . $task_time_start . ', окончание ' . date('Y-m-d H:i:s') . "\n";

        $mail_body .= "\n\n";
        $mail_body .= 'Категории:' . "\n";
        $mail_body .= $this->buildReportPart($category_report);

        $mail_body .= "\n\n";
        $mail_body .= 'Свойства:' . "\n";
        $mail_body .= $this->buildReportPart($property_report);

        $mail_body .= "\n\n";
        $mail_body .= 'Товары:' . "\n";
        $mail_body .= $this->buildReportPart($product_report);

        $instance->getConfiguration()->loadHelpers('Partial');

        $emails_dirty = NotificationEmailsTable::getInstance()->createQuery('e')
            ->select('e.email')
            ->where("e.is_active = 1")
            ->andWhere("e.notic_type = 'exchange' OR e.notic_type = 'all'")
            ->fetchArray();

        if (count($emails_dirty) > 0)
        {
            $emails = array();

            foreach ($emails_dirty as $e)
            {
                $emails[] = $e['email'];
            }

            get_component('pages', 'emailSender',
                array(
                    'type' => 'simple',
                    'emailTo' => $emails,
                    'param' => array('mailBody' => $mail_body, 'subject' => 'Импорт файла ' . $file_path . ' завершен')
                )
            );
        }





    }

    protected function buildReportPart($report)
    {
        $mail_body = 'Всего: ' . $report['all'] . "\n";
        $mail_body .= 'Новых: ' . $report['new'] . "\n";
        $mail_body .= 'Изменений ' . $report['change'] . "\n";

        return $mail_body;
    }


    protected function valueOrNull($value)
    {
        return strlen($value) > 0 ? $value : null;
    }

    /**
     * @param  $data SimpleXMLIterator
     * @return mixed
     */
    protected function products($data)
    {
        $report['all'] = 0;
        $report['change'] = 0;
        $report['new'] = 0;

        $productByInnerId_dirty = Doctrine_Query::create()
            ->select("p.*,c.*")
            ->from("Product p INDEXBY p.inner_id")
            ->leftJoin("p.Cats c")
            ->where("p.inner_id is not null")
            ->execute();
        $productByInnerId = array();
        if (count($productByInnerId_dirty) > 0) {
            foreach ($productByInnerId_dirty as $product) {
                $productCatalog = $product->getCatProduct()->getFirst();
                $catalogId = null;
                $catalogInnerId = null;
                if ($productCatalog instanceof Cat) {
                    $catalogId = $productCatalog->getId();
                    $catalogInnerId = $productCatalog->getInnerId();
                }
                $productByInnerId[$product->getInnerId()] = array(
                    'title' => $product->getTranslation()->ru->title,
                    'id' => $product->getId(),
                    'catalogId' => $catalogId,
                    'catalogInnerId' => $catalogInnerId,
                    'imgString' => $product->getProductImg()
                );
            }
        }

        $categoryByInnerId_dirty = Doctrine_Query::create()
            ->select("c.*, t.*")
            ->from("Cat c")
            ->innerJoin("c.Translation t")
            ->execute();
        $categoryByInnerId = array();
        if (count($categoryByInnerId_dirty) > 0) {
            foreach ($categoryByInnerId_dirty as $category) {
                $categoryByInnerId[$category->getInnerId()] = array(
                    'title' => $category->getTranslation()->ru->title,
                    'id' => $category->getId()
                );
            }
        }

        unset($productByInnerId_dirty);
        unset($categoryByInnerId_dirty);

        foreach ($data as $item) {
            $report['all']++;
            $inner_id = trim($item->Ид);
            $category_inner_id = trim($item->Группы->Ид);
            $description = $this->valueOrNull(trim($item->Описание));
            $req = array(
                'full_name' => (string)$item->Наименование
            );
            if(count($item->Картинка) > 0){
                foreach ($item->Картинка as $image){
                    $req['img'][] = (string)$image;
                }
            }
            if (key_exists($inner_id, $productByInnerId) && key_exists($category_inner_id, $categoryByInnerId)) {
                $enter = false;

                $oldProduct = Doctrine::getTable('Product')->findOneById($productByInnerId[$inner_id]['id']);
                $oldProduct->setIsDelete(isset($item['Статус']) && $item['Статус'] == 'Удален');
                $oldProduct->getTranslation()->ru->set('description', $description);
                //$this->imgRemove($oldProduct->getProductImg());
                $oldProduct->setProductImg(null);
                $oldProduct->save();


                if ($productByInnerId[$inner_id]['catalogInnerId'] != $category_inner_id) {
                    $oldCatProduct = Doctrine::getTable('CatProduct')->findOneByProductId($productByInnerId[$inner_id]['id']);
                    $oldCatProduct = $oldCatProduct instanceof CatProduct ? $oldCatProduct : CatProduct::make($productByInnerId[$inner_id]['id']);
                    $oldCatProduct->setCatId($categoryByInnerId[$category_inner_id]['id']);

                    $oldCatProduct->save();
                    $enter = true;
                    unset($oldCatProduct);
                }
                if ($productByInnerId[$inner_id]['title'] != $req['full_name'] || isset($req['img'])) {
                    if ($productByInnerId[$inner_id]['title'] != $req['full_name']) {
                        $oldProduct->getTranslation()->ru->set('title', $req['full_name']);
                        $oldProduct->getTranslation()->en->set('title', $req['full_name']);
                    }
                    file_put_contents(sfConfig::get('sf_log_dir') . '/importImages', print_r($req['full_name'] . '_____________1', true) . "\n\n", FILE_APPEND);
                    if (isset($req['img']) && count($req['img']) > 0) {

                        $img = $this->imgUploader($req['img'], 'product');
                        file_put_contents(sfConfig::get('sf_log_dir') . '/importImages', print_r($img . '_____________1', true) . "\n\n", FILE_APPEND);
                        $oldProduct->setProductImg($img);

                        $oldProduct->save();
                        file_put_contents(sfConfig::get('sf_log_dir') . '/importImages', print_r($oldProduct->getProductImg() . '_________________2', true) . "\n\n", FILE_APPEND);
                    }
                    $oldProduct->save();
                    $enter = true;
                    unset($oldProduct);
                }
                if ($enter) {
                    $report['change']++;
                }
                if (count($item->ЗначенияСвойств->ЗначенияСвойства) > 0) {
                    $this->property_set_value($item->ЗначенияСвойств->ЗначенияСвойства, $productByInnerId[$inner_id]['id']);
                }
                unset($productByInnerId[$inner_id]);
            } elseif (key_exists($category_inner_id, $categoryByInnerId)) {
                $newProduct = new Product();
                $newProduct->setInnerId($inner_id);
                $newProduct->getTranslation()->ru->set('title', $req['full_name']);
                $newProduct->getTranslation()->en->set('title', $req['full_name']);
                $newProduct->getTranslation()->ru->set('description', $description);
                $newProduct->setIsDelete(isset($item['Статус']) && $item['Статус'] == 'Удален');

                if (isset($req['img']) && count($req['img']) > 0) {
                    $newProduct->setProductImg($this->imgUploader($req['img'], 'product'));
                }

                $newProduct->save();

                $newCatProduct = new CatProduct();
                $newCatProduct->setCatId($categoryByInnerId[$category_inner_id]['id']);
                $newCatProduct->setProductId($newProduct->getId());
                $newCatProduct->save();
                $report['new']++;
                if (count($item->ЗначенияСвойств->ЗначенияСвойства) > 0) {
                    $this->property_set_value($item->ЗначенияСвойств->ЗначенияСвойства, $newProduct->getId());
                }
            }
        }
        if (count($productByInnerId) > 0) {
            $softDeleteIds = array();
            foreach ($productByInnerId as $product) {
                $softDeleteIds[] = $product['id'];
            }
            $softDelete = Doctrine_Query::create()
                ->update('Product p')
                ->set('p.is_delete', true)
                ->whereIn('p.id', $softDeleteIds)
                ->execute();
            unset($softDeleteIds);
            unset($softDelete);
        }
        return $report;
    }

    protected function property_set_value($data, $productId)
    {
        if ($this->g_propertyByInnerId == false || $this->g_propertyListByInnerId == false) {
            $propertyByInnerId_derty = Doctrine::getTable('ProductProp')->findAll();
            $propertyByInnerId = array();
            $propertyListByInnerId = array();

            if (count($propertyByInnerId_derty) > 0) {
                foreach ($propertyByInnerId_derty as $property) {
                    $propertyByInnerId[$property->getInnerId()] = array(
                        'id' => $property->getId(),
                        'isList' => $property->getIsList()
                    );

                    if ($property->getIsList()) {
                        $lists = $property->getProductPropList();

                        foreach ($lists as $list) {
                            $propertyListByInnerId[$list->getInnerId()] = array(
                                'id' => $list->getId(),
                                'propId' => $list->getProductPropId(),
                                'variant' => $list->getTranslation()->ru->variant
                            );
                        }

                    }
                }
            }

            $this->g_propertyByInnerId = $propertyByInnerId;
            $this->g_propertyListByInnerId = $propertyListByInnerId;
        } else {
            $propertyByInnerId = $this->g_propertyByInnerId;
            $propertyListByInnerId = $this->g_propertyListByInnerId;
        }

        $productPropValueByInnerId_derty = Doctrine::getTable('ProductPropValue')->findByProductId($productId);
        $productPropValueByPropId = array();
        foreach ($productPropValueByInnerId_derty as $productPropValue) {
            $productPropValueByPropId[$productPropValue->getPropId()] = array(
                'id' => $productPropValue->getId()
            );
        }

        foreach ($data as $item) {
            $propInnerId = trim($item->Ид);
            $propValue = trim($item->Значение);

            $idInBaseProperty = Doctrine::getTable('ProductProp')->findOneByInnerId($propInnerId)->getId();
            $nameProperty = Doctrine::getTable('ProductPropTranslation')->findById($idInBaseProperty)->toArray();

            unset($idInBaseProperty);
            if (strpos($nameProperty['ru']['title'], 'доставка') != false) {
                if (stristr($propValue, 'Да')) {
                    Doctrine::getTable('Product')->findOneById($productId)->setFreeShipping(true)->save();
                }else {
                    Doctrine::getTable('Product')->findOneById($productId)->setFreeShipping(false)->save();
                }
            }else {
                if ($propertyByInnerId[$propInnerId]['isList'] && key_exists($propValue, $propertyListByInnerId) && $propertyListByInnerId[$propValue]['propId'] == $propertyByInnerId[$propInnerId]['id']) {
                    $propValue = $propertyListByInnerId[$propValue]['id'];
                }
                if (key_exists($propInnerId, $propertyByInnerId)) {
                    if (key_exists($propertyByInnerId[$propInnerId]['id'], $productPropValueByPropId)) {
                        $productPropValueId = $productPropValueByPropId[$propertyByInnerId[$propInnerId]['id']]['id'];
                        unset($productPropValueByPropId[$propertyByInnerId[$propInnerId]['id']]);
                    } else {
                        $newProductPropValue = new ProductPropValue();
                        $newProductPropValue->setPropId($propertyByInnerId[$propInnerId]['id']);
                        $newProductPropValue->setProductId($productId);
                        $newProductPropValue->setValue($propValue);
                        $newProductPropValue->save();
                    }
                }
            }
            unset($nameProperty);

        }
        if (count($productPropValueByPropId) > 0) {
            $needDelete = array();
            foreach ($productPropValueByPropId as $productPropValue) {
                $needDelete[] = $productPropValue['id'];
            }
            $net_use_product_prop_value = Doctrine_Query::create()
                ->delete('ProductPropValue ppv')
                ->whereIn('ppv.id', $needDelete)
                ->execute();
            unset($net_use_product_prop_value);
        }
    }

    protected function property($data)
    {
        $report['all'] = 0;
        $report['change'] = 0;
        $report['new'] = 0;

        $propertyByInnerId_derty = Doctrine_Query::create()
            ->select("p.*, t.*")
            ->from("ProductProp p")
            ->innerJoin("p.Translation t")
            ->execute();
        $propertyByInnerId = array();
        if (count($propertyByInnerId_derty) > 0) {
            foreach ($propertyByInnerId_derty as $property) {
                $propertyByInnerId[$property->getInnerId()] = $property->getTranslation()->ru->title;
            }
        }
        unset($propertyByInnerId_derty);

        foreach ($data as $item) {

            $report['all']++;

            $inner_id = trim($item->Ид);
            $title = trim($item->Наименование);
            $type = trim($item->ТипЗначений);


            $listsByInnerId_fromFile = array();

            if ($type == 'Справочник') {
                foreach ($item->ВариантыЗначений->Справочник as $list) {
                    $listsByInnerId_fromFile[trim($list->ИдЗначения)] = trim($list->Значение);
                }
            }

            if (key_exists($inner_id, $propertyByInnerId)) {
                $old_property = Doctrine::getTable('ProductProp')->findOneByInnerId($inner_id);
                $enter = false;

                if ($propertyByInnerId[$inner_id] != $title) {
                    $enter = true;
                    $old_property->getTranslation()->ru->set('title', $title);
                    $old_property->getTranslation()->en->set('title', $title);
                }
                if ($type == 'Справочник') {
                    $enter = true;

                    $old_property->setIsList(1);

                    $old_property_list = $old_property->getProductPropList();

                    if ($old_property_list && count($old_property_list) > 0) {
                        foreach ($old_property_list as $old_property_list_element) {
                            $needDelete = array();
                            if (key_exists($old_property_list_element->getInnerId(), $listsByInnerId_fromFile)) {
                                $old_property_list_element->getTranslation()->ru->set('variant', $listsByInnerId_fromFile[$old_property_list_element->getInnerId()]);
                                $old_property_list_element->getTranslation()->en->set('variant', $listsByInnerId_fromFile[$old_property_list_element->getInnerId()]);
                                $old_property_list_element->save();
                                unset($listsByInnerId_fromFile[$old_property_list_element->getInnerId()]);
                            } else {
                                $needDelete[] = $old_property_list_element->getId();
                            }
                            if (count($needDelete) > 0) {
                                $net_use_property_list = Doctrine_Query::create()
                                    ->delete('ProductPropList ppl')
                                    ->whereIn('ppl.id', $needDelete)
                                    ->execute();
                                unset($net_use_property_list);
                            }
                        }
                    }

                    if (count($listsByInnerId_fromFile) > 0) // if isset new value in file
                    {
                        foreach ($listsByInnerId_fromFile as $listInnerId => $listTitle) {
                            $new_property_list = new ProductPropList();
                            $new_property_list->setProductPropId($old_property->getId());
                            $new_property_list->getTranslation()->ru->set('variant', $listTitle);
                            $new_property_list->getTranslation()->en->set('variant', $listTitle);
                            $new_property_list->setInnerId($listInnerId);
                            $new_property_list->save();

                            unset($new_property_list);
                        }
                    }
                } else {
                    $old_property->setIsList(0);
                }

                $old_property->save();
                unset($old_property);

                if ($enter) {
                    $report['change']++;
                }

            } else {
                $new_property = new ProductProp();
                $new_property->setInnerId($inner_id);
                $new_property->getTranslation()->ru->set('title', $title);
                $new_property->getTranslation()->en->set('title', $title);
                $new_property->save();

                if ($type == 'Справочник') {
                    $new_property->setIsList(1)->save();

                    foreach ($listsByInnerId_fromFile as $listInnerId => $listTitle) {
                        $new_property_list = new ProductPropList();
                        $new_property_list->setProductPropId($new_property->getId());
                        $new_property_list->getTranslation()->ru->set('variant', $listTitle);
                        $new_property_list->getTranslation()->en->set('variant', $listTitle);
                        $new_property_list->setInnerId($listInnerId);
                        $new_property_list->save();

                        unset($new_property_list);
                    }

                }

                unset($new_property);

                $report['new']++;
            }
            unset($inner_id);
            unset($title);
            unset($type);
        }

        unset($propertyByInnerId);

        return $report;
    }

    protected function category($data, $parentInnerId = false)
    {
        $report['all'] = 0;
        $report['change'] = 0;
        $report['new'] = 0;

        $categoryByInnerId = Doctrine_Query::create()
            ->select("c.id, c.inner_id, c.parent_id, t.*, t.title AS title")
            ->from("Cat c INDEXBY c.inner_id")
            ->innerJoin("c.Translation t ON (t.id = c.id AND t.lang = 'ru')")
            ->groupBy("c.inner_id")
            ->where("c.inner_id is not null")
            ->fetchArray();
        $parentId = null;
        if ($parentInnerId) {
            $parentId = Doctrine_Query::create()
                ->select('c.id')
                ->from('Cat c')
                ->where('c.inner_id = ?', $parentInnerId)
                ->fetchArray();

            if ($parentId) {
                $parentId = $parentId[0]['id'];
            } else {
                $parentId = null;
            }
        }
        foreach ($data as $item) {
            $report['all']++;

            $inner_id = trim($item->Ид);
            $title = trim($item->Наименование);

            if (isset($categoryByInnerId[$inner_id])) {
                if ($categoryByInnerId[$inner_id]['title'] != $title || (isset($categoryByInnerId[$inner_id]['parentId']) && $categoryByInnerId[$inner_id]['parentId'] != $parentId)) {

                    $report['change']++;

                    $old_category = Doctrine::getTable("Cat")->findOneByInnerId($inner_id);
                    $old_category->getTranslation()->ru->set('title', $title);
                    $old_category->getTranslation()->en->set('title', $title);
                    $old_category->setAlias('');
                    $old_category->setParentId($parentId);
                    $old_category->save();

                    unset($old_category);
                }
            } else {

                $report['new']++;

                $new_category = new Cat();
                $new_category->setInnerId($inner_id);
                $new_category->getTranslation()->ru->set('title', $title);
                $new_category->getTranslation()->en->set('title', $title);
                $new_category->setParentId($parentId);
                $new_category->save();

                unset($new_category);
            }

            if (isset($item->Группы->Группа)) {
                $recursion_report = $this->category($item->Группы->Группа, $inner_id);
                $report['new'] = $report['new'] + $recursion_report['new'];
                $report['change'] = $report['change'] + $recursion_report['change'];
                $report['all'] = $report['all'] + $recursion_report['all'];
            }

            unset($title);
            unset($inner_id);
        }

        unset($parentId);
        unset($categoryByInnerId);

        return $report;
    }

    protected function imgUploader($imgs, $key)
    {
        file_put_contents(sfConfig::get('sf_log_dir') . '/importImages', print_r(implode($imgs,';'), true) . "\n\n", FILE_APPEND);
        $imgs_result = array();
        if (is_array($imgs) && count($imgs) > 0) {
            foreach ($imgs as $img) {
                $upload_result = json_decode(Page::uploader('data/exchange/' . $img, 'file', false, array('key' => $key), true));
                if ($upload_result->state == 'success') {
                    $imgs_result[] = $upload_result->filename;
                }
            }
        }
        file_put_contents(sfConfig::get('sf_log_dir') . '/importImages', print_r($upload_result, true) . "\n\n", FILE_APPEND);
        return (count($imgs_result) > 0 ? implode(';', $imgs_result) : null);
    }

    protected function imgRemove($str)
    {
        if($str != ''){
            foreach (explode(';', $str) as $imagename){
                $exp = explode('.', $imagename);
                if(count($exp) == 2){
                    $ways = glob(sfConfig::get('sf_upload_dir') . '/i/' . $exp[0] . '*.' . $exp[1]);
                    if(count($ways) > 0){
                        foreach ($ways as $way){
                            if(!is_dir($way)){
                                unlink($way);
                            }
                        }
                    }
                }
            }
        }
    }
}
