<?php
/**
* @author OfficeBrain 4160 <info@officebrain.com>
*
* Description :  Product Queue Extended Class
*
**/
namespace OfficeBrain\Bundle\QueueBundle\Manager\Extended;

use OfficeBrain\Bundle\QueueBundle\Manager\AbstractManager\QueueAbstract;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use OfficeBrain\Bundle\QueueBundle\Document\ProductQueue;
#use OfficeBrain\Bundle\QueueBundle\Document\CentralProductQueue;

class ProductQueueExtended extends QueueAbstract
{
    protected $container;
    protected $dm;
    
    public function __construct(Container $container, $entityParameters)
    {
        $this->container = $container;
        $this->entityParameters = $entityParameters;
        $this->dm = $container->get('doctrine_mongodb')->getManager();
        #$this->gdm = $container->get('doctrine_mongodb.odm.centralconn_document_manager');
        $this->repository = $this->dm->getRepository('OfficeBrainQueueBundle:ProductQueue');
        #$this->centralRepository = $this->gdm->getRepository('OfficeBrainQueueBundle:CentralProductQueue');
        $this->request = $this->container->get('request');
        $this->projectSetting = $this->request->get('project_setting');
        $this->emailManager = $container->get('office_brain_email_service');
        $this->productAdminManager = $container->get('office_brain_product_admin_manager');
    }
    
    public function mapQueue($action, $data, $type='json')
    {
        if($this->projectSetting['instance_type']!="sub_shop" && $this->projectSetting['instance_type']!="association")
        {
            $object = $this->request->attributes->get('object');
            $formatedData = $this->processData($data, $this->entityParameters[$object]['dataMapping'], $type);
            if (is_array($formatedData) && array_key_exists('exception', $formatedData)) {
                $this->setQueue($object, $action, array(), $formatedData['exception']);
            } else {
                $formatedData = array('scalar' => $formatedData);
                $this->setQueue($object, $action, $formatedData);
            }
        }
    }
    
    /**
    * @author Employee Id: 4160
    * Description :
    * setData method to set values in queue
    *
    * @param 1 : string object of queue
    * @param 2 : string object object name of entity
    * @param 3 : string action action name to perform
    * @param 4 : array args fields mapping arguments
    *
    * @return object
    *
    **/
    public function setData($queueObj, $date, $object, $action, $args, $msg=null)
    {
        $queueObj->setFrom(1);
        $queueObj->setInstanceId($this->projectSetting['instance_id']);
        $queueObj->setInstanceType($this->projectSetting['instance_type']);
        $queueObj->setObjectName($object);
        $queueObj->setAction($action);
        $queueObj->setPriority(0);
        $queueObj->setCreatedAt($date);
        $queueObj->setUpdatedAt($date);
        if ($msg == null) {
            $queueObj->setArgs($args);
            $queueObj->setStatus('New');
            $queueObj->setVirtualStatus('New');
        } else {
            $queueObj->setStatus('Error');
            $queueObj->setVirtualStatus('Error');
            $queueObj->setMessage($msg);
        }
        return $queueObj;
    }
    
    /**
    * @author Employee Id: 4160
    * Description :
    * setQueue method to set values in queue
    *
    * @param 1 : string name name of supplier or distributor
    * @param 2 : string object object name of entity
    * @param 3 : string action action name to perform
    * @param 4 : array args fields mapping arguments
    *
    * @return object
    *
    **/
    public function setQueue($object, $action, $args, $msg=null)
    {
        $queueObj = new ProductQueue();
        #$centralQueueObj = new CentralProductQueue();
        $date = parent::setDateFormat();
        try{
            $queueObj = $this->setData($queueObj, $date, $object, $action, $args, $msg);
            $queue = $this->repository->save($queueObj);
            
            #$centralQueueObj = $this->setData($centralQueueObj, $date, $object, $action, $args, $msg);
            #$centralQueue = $this->centralRepository->save($centralQueueObj);
            if ($msg) {
                $db_name = $this->container->getParameter('mongodb_database');
                $db_server_name = $this->container->getParameter('mongodb_server');
                $params = array('message' => $msg, 'queueName' => 'ProductQueue','db_name' => $db_name,'db_server_name' => $db_server_name);
                
                $this->emailManager->sendMail('error_queue', $this->container->getParameter('mongo_error_email'), $params, $this->projectSetting['culture_id']);
                
                #$params = array('message' => $msg, 'queueName' => 'CentralProductQueue','db_name' => $db_name,'db_server_name' => $db_server_name);
                #$this->emailManager->sendMail('error_queue', $this->container->getParameter('mongo_error_email'), $params, $this->projectSetting['culture_id']);
            }
            return $queue;
        } catch (\Exception $e) {
            if ($msg == null) {
               $status ='New';
            } else {
                $status ='Error';
            }
           $queueData= '{ from : "1",</br>
               instance_id : "'.$this->projectSetting['instance_id'].'",</br>
               instance_type : "'.$this->projectSetting['instance_type'].'",</br>
               objectName : "'.$object.'",</br>
               action : "'.$action.'",</br>
               priority : 0,</br>
               created_at :"'.$date->format("Y-m-d H:i:s").'",</br>
               updated_at : "'.$date->format("Y-m-d H:i:s").'",</br>
               args : '.json_encode($args).',</br>
               status : "'.$status.'"</br>
           }';
            $params = array('message' => $e->getMessage(), 'queueName' => 'ProductQueue','queueData' => $queueData);
            $this->emailManager->send('dhvani@officebrain.com',$this->container->getParameter('mongo_error_email'),$e->getMessage(), $queueData); 
        }
    }
    
    /**
    * @author Employee Id: 4160
    * Description :
    * processData method to data mapping process
    *
    * @param 1 : array data data array of keys and values
    * @param 2 : array configObject configuration parameters of object with dataMapping fields, methods, parameters
    * @param 3 : string type type of formatting
    *
    * @return array
    *
    **/
    public function processData($data, $configObject, $type="json")
    {
        try {
            $erpData = parent::processData($data, $configObject);
            $resultData = parent::formatData($erpData, $type);
            return $resultData;
        } catch (\Exception $e) {
            return array('exception' => $e->getMessage());
        }
    }
    
    /**
    * @author Employee Id: 4160
    * Description :
    * processRunQueue method to read records from queue and update status
    *
    * @param 1 : string name name of supplier or distributor or association
    * @param 2 : integer count count of jobs to execute in batch
    *
    * @return
    *
    **/
    public function processRunQueue($instance_id, $count)
    {
        $progressResult = $this->repository->findInProgressJobs(intval($instance_id));
        if (count($progressResult) > 0) {
            echo "In Progress jobs are running so terminated product queue...";
            die;
        }
        $cursorResult = $this->repository->findRunJobs(intval($instance_id), $count);
        try {
            if (count($cursorResult) > 0) {
                foreach ($cursorResult as $document) {
                    $from = $document->getFrom();
                    if ($from == '3') {
                        $status = $document->getWebStatus();
                    } else {
                        $status = $document->getStatus();
                    }
                    
                    if ($status == 'Error') {
                        echo "\n Error job record found so terminated product queue...";
                        die;
                    }
                    $date = parent::setDateFormat();
                    $document->setStarted($date);
                    if ($from == '3') {
                        $document->setWebStatus('In Progress');
                    } else {
                        $document->setStatus('In Progress');   
                    }
                    $this->repository->save($document);
                    
                    $distributor_id = $document->getDistributorId();
                    $instance_type = $document->getInstanceType();
                    
                    $action = $document->getAction();
                    $object = $document->getObjectName();
                    $args = $document->getArgs();
                    $id = $document->getId();
                    $instance_id = $document->getInstanceId();
                    $project_instance_id = $this->projectSetting['instance_id'];
                    $project_instance_type = $this->projectSetting['instance_type'];
                    
                    $decodeData = (array) json_decode($args['scalar']);
                    if (count($decodeData) == 0) {
                        echo "\n\n Not proper formatted data in Record Id ($id) of Product Queue so terminated product queue...\n";
                        die;
                    }
                    $accessListener = $this->container->get('office_brain_access_management.access_configuration');
                    $accessListener->PrepareAccessAndConfigurationRulesForCli ($this->request);
                    $result = $this->processExecuteAction($object, $action, $decodeData, $document);
                    $flag = 1;
                    if ($result) {
                        if (array_key_exists('status', $result) && $result['status'] == 'Success') {
                            if ($from == '3') {
                                $document->setWebStatus('Success');
                            } else {
                                $document->setStatus('Success');
                            }
                        } else if (array_key_exists('status', $result) && $result['status'] == 'Delete') {
                            $this->repository->deleteQueue($document);
                        }
                    } else {
                        if ($from == '3') {
                            $document->setWebStatus('Error');
                        } else {
                            $document->setStatus('Error');
                        }
                    }
                    if ($flag == 1) {
                        $finishedDate = new \DateTime();
                        $document->setUpdatedAt($finishedDate);
                        $document->setFinished($finishedDate);
                        $this->repository->save($document);
                    }
                }
            } else {
                echo "No jobs are to execute in product queue...";
                die;
            }
        } catch (\Exception $e) {
            echo "\n Error in Product Queue Records...\n", $e->getMessage();
            echo "\n Error line : ", $e->getLine(), $e->getTraceAsString(), $e->getFile(), $e->getCode();
            die;
        }
    } 
    
    /**
    * @author Employee Id: 4160
    * Description :
    * processExecuteAction method to execute action based on recordData of Queue
    *
    * @param 1 : string object object key name
    * @param 2 : string action action to perform
    * @param 3 : formatted args key values dataArray
    *
    * @return object or array
    *
    **/
    public function processExecuteAction($object, $action, $decodeData, $document)
    {
        // To Solr Update to sync product
        $supplier_id = $document->getSupplierId();
        $project_id = $document->getProjectId();
        //$culture = $document->getCulture();
        $culture = $decodeData['culture'];
        foreach ($this->container->getParameter('country') as $key=>$value) {
            foreach($value['language'] as $k => $v) {
                $cultureCountry[] = $k.'_'.$value['short_name'];
            }
        }
        if(in_array($culture, $cultureCountry)) {
            //$result = exec('app/console office_brain:solr:sync:product --projectId='.$project_id.' --culture='.$culture.'  --supplierId='.$supplier_id.' --productId='.$decodeData['product_id']);
            $from = $document->getFrom();
            if ($from == 2) {
                // TODO add product api call
                $product_id = $this->processExecuteServiceMethodAction($object, $action, $decodeData, $document);
                $project_id = $decodeData['project_id'];
                $supplier_id = $decodeData['supplier_id'];
                $culture = $decodeData['culture'];
                //echo $product_id, $project_id, $supplier_id, $culture; die;
                //$result = exec('app/console office_brain:solr:sync:product --projectId='.$project_id.' --culture='.$culture.'  --supplierId='.$supplier_id.' --productId='.$product_id);
            }
            return array('status' => 'Success');
        } else {
            return array('status' => 'Delete');
        }
    }

    /**
    * @author Employee Id: 4160
    * Description :
    * processExecuteServiceMethodAction method to execute action based on configure of Queue
    *
    * @param 1 : string object object key name
    * @param 2 : string action action to perform
    * @param 3 : formatted args key values dataArray
    *
    * @return object or array
    *
    **/
    public function processExecuteServiceMethodAction($object, $action, $decodeData, $document)
    {
        if (array_key_exists($object, $this->entityParameters)) {
            $configObject = $this->entityParameters[$object];
            $service = $configObject[$action]['service'];
            $method = $configObject[$action]['method'];
            $methodParameters = array();
            if (array_key_exists('methodParameters', $configObject[$action])) {
                $parameters = $configObject[$action]['methodParameters'];
                $methodParameters = $this->setProcessParameters($parameters, $decodeData);
            }
            $serviceManager = $this->container->get($service);
            $result = call_user_func_array(array($serviceManager, $method), $methodParameters);
            return $this->processOnResult($result, $document, $action, $object, $decodeData);
        }
    }

    /**
    * @author Employee Id: 4160
    * Description :
    * processOnResult method to process on result data
    *
    * @param 1 : object or array of result
    * @param 2 : object of document
    * @param 3 : string action name
    * @param 4 : string object name
    * @param 5 : array of data
    * 
    * @return
    *
    **/
    public function processOnResult($result, $document, $action, $object, $decodeData)
    {
        if ($result) {
            if (array_key_exists('status', $result) && $result['status'] == 'error') {
                echo "\n\n ", $result['message'];
                echo "\n Exception from Result...\n Exception Error in Service Manager on Return result so terminated product queue...\n";
                $this->setStatusData($document, 'Error', $result['message'], $decodeData);
                die;
            }
            if (array_key_exists('status', $result) && $result['status'] == 'success' && array_key_exists('master_product_id', $result) && isset($result['master_product_id'])) {
                $culture = '';
                if (isset($decodeData['culture'])) {
                    $culture = $decodeData['culture'];
                    $returnData = $this->productAdminManager->view($result['master_product_id'], $culture, true);
                    if($returnData['status'] == 'success') {
                        $this->request->attributes->set('object', $object);
                        $this->request->attributes->set('instance_id', $document->getInstanceId());
                        $this->mapQueue('update', $returnData['data'][$result['master_product_id']]);
                    }
                }
                $this->setStatusData($document, 'Success', 'Successfully Implemented');
                return $result['master_product_id'];
            }
        } else {
            $this->setStatusData($document, 'Error', 'Error in result of manager service ', $decodeData);
            echo "\n Error in Service Manager on Return result so terminated product queue...\n";
            die;
            break;
        }
    }
    
    /**
    * @author Employee Id: 4160
    * Description :
    * setStatusData method to set status and dates of mongodb document
    *
    * @param 1 : object document mongodb document
    * @param 2 : string status status to update
    * @param 3 : string message message update to document
    *
    * @return
    *
    **/
    public function setStatusData($document, $status, $message, $data=array())
    {
        $finishedDate = parent::setDateFormat();
        $document->setUpdatedAt($finishedDate);
        $document->setFinished($finishedDate);
        $document->setStatus($status);
        $document->setMessage($message);
        $this->repository->save($document);
        if ($status == 'Error') {
            $ddata = json_encode($data);
            $db_name = $this->container->getParameter('mongodb_database');
            $db_server_name = $this->container->getParameter('mongodb_server');
            $params = array('message' => $message, 'queueName' => 'ProductQueue', 'queueData' => $ddata,'db_name' => $db_name,'db_server_name' => $db_server_name);
            $this->emailManager->sendMail('error_queue', $this->container->getParameter('mongo_error_email'), $params, $this->projectSetting['culture_id']);
        }
    }
    
    /**
    * @author Employee Id: 4160
    * Description :
    * setProcessParameters method to process on parameters and return array
    *
    * @param 1 : array parameters
    * @param 2 : array decodeData
    * @param 3 : array methodResult
    * @param 4 : object form
    *
    * @return array
    *
    **/
    public function setProcessParameters($parameters, $decodeData, $flag=TRUE)
    {
        $keyFlag = FALSE;
        $methodParameters = array();
        foreach ($parameters as $key => $value) {
            if (is_array($parameters[$key])) {
                $methodParameters = $this->setProcessParameters($parameters[$key], $decodeData, FALSE);
                if (array_key_exists('required_key', $parameters)) {
                    $methodParameters[$key] = $methodParameters[0];
                }
                return $methodParameters;
            }
            if (array_key_exists($key, $decodeData)) {
                if (array_key_exists('required_key', $parameters) && $parameters['required_key'] == 1) {
                    if (is_object($decodeData[$key])) {
                        $decodeData[$key] = (array) $decodeData[$key];
                    }
                    if (is_array($decodeData[$key])) {
                        $methodParameters[$value] = $decodeData[$key];
                    } else {
                        $methodParameters[$value] = $decodeData[$key];
                    }
                }
                else $methodParameters[] = $decodeData[$key];
            } elseif ($key == 'container') {
                $methodParameters[] = $this->container;
            } elseif ($key == 'request') {
                $methodParameters[] = $this->request;
            } elseif($key != '' && $value == 'all') {
                $decodeData = (array) json_decode(json_encode($decodeData), true);
                $methodParameters[$key] = $decodeData;
            } elseif ($key == 'service') {
                $methodParameters[$key] = $this->container->get($value);
            } else {
                if (array_key_exists('key', $parameters) && $parameters['key'] == 1) {
                    $keyFlag = TRUE;
                }
                if (array_key_exists('required_key', $parameters) && $parameters['required_key'] == 1 && $key != 'required_key' && $key != 'key') {
                    if ($keyFlag == TRUE) {
                        $methodParameters[$key] = $value;
                    } else {
                        $methodParameters[$value] = $value;
                    }
                }
                else {
                    if ($key != 'required_key' && $key != 'key') {
                        if ($keyFlag == TRUE) {
                            $methodParameters[$key] = $value;
                        } else {
                            $methodParameters[] = $value;
                        }
                    }
                }
            }
        }
        if (!$flag) {
            $methodP[] = $methodParameters;
            return $methodP;
        }
        return $methodParameters;
    }
}
