<?php

namespace Modules\Admin\QcRules;

class Controller extends \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing
{

	/**
	 * Indicates if the entity execution should use or not a transaction.
	 * @var Boolean
	 */
	protected $useSqlTransaction=true;

	/**
	 * The list of columns which support ordering.
	 * @var array
	 */
	protected $listOrderingColumns = ['addTime'];

	/**
	 *
	 * {@inheritDoc}
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::initialize()
	 */
	protected function initialize()
	{
		parent::initialize();

		$this->actionsCfg['insert'] =    	[ 'checkSection' => false, 'checkOption' => false ];
		$this->actionsCfg['update'] =    	[ 'checkSection' => false, 'checkOption' => false ];
		$this->actionsCfg['delete'] =    	[ 'checkSection' => false, 'checkOption' => false ];
		$this->actionsCfg['activate'] = 	[];
		$this->actionsCfg['deactivate'] =	[];
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionDefineParams()
	 */
	protected function optionDefineParams(\App\Mvc\View\Utils\RowOptions\Option\Option $option, $selection)
	{
		switch($option->getId()){
			case 'insert':
				break;

 			case 'clone':
 				break;

			case 'update':
				foreach ($selection as $selectedItem) {
					$option->determineOperationAvailability(\Entity\QcRule::update($selectedItem));
				}
			break;

			case 'delete':
				foreach ($selection as $selectedItem) {
					if (!$option->determineOperationAvailability(\Entity\QcRule::delete($selectedItem))) {
						break;
					}
				}
			break;

			case 'activate':
				foreach ($selection as $selectedItem) {
					if (\Entity\QcRule::select($selectedItem)->active) {
						$option->setDisabled();
					}
				}
			break;

			case 'deactivate':
				foreach ($selection as $selectedItem) {
					if (!\Entity\QcRule::select($selectedItem)->active) {
						$option->setDisabled();
					}
				}
			break;



			default:
				return false;
		}

		return true;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionGetEntityName()
	 */
	protected function optionGetEntityName($id)
	{
		return \Entity\QcRule::select($id)->name;
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::insert_getDefaultFormData()
	 */
	protected function insert_getDefaultFormData($R)
	{

		if ($R['entityChanged']) {
			return $R;
		}
		elseif ($R['cloneFromQcRule']) {
			// prepopulate qcRule id
			return  $this->update_getDefaultFormData($R['cloneFromQcRule']);
		}

		// the default form data:
		$R['entity'] = 'Invoice';
		$R['active'] = true;

		return $R;
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::insert_createEntityObject()
	 */
	protected function insert_createEntityObject($formData)
	{

		$ruleClassName = "\App\QcRules\\{$formData['entity']}_Rule";
		$qcRuleObj = new $ruleClassName();

		// add filters
		if ($formData['filters']) {
			foreach($formData['filters'] as $field=>$filterDetails) {
				$qcFilterObj = $this->createQcRuleFilterFromRq($formData['entity'], $field, $filterDetails);
				if ($qcFilterObj) {
					$qcRuleObj->addFilter($qcFilterObj);
				}
			}
		}

		// add restrictions
		if ($formData['restrictions']) {
			foreach($formData['restrictions'] as $field=>$restrictionDetails) {
				$qcRestrictionObj = $this->createQcRuleFilterFromRq($formData['entity'], $field, $restrictionDetails);
				if ($qcRestrictionObj) {
					$qcRuleObj->addRestriction($qcRestrictionObj);
				}
			}
		}


		// CREATE THE ENTITY FOR THIS RULE (TO RETURN IT) /////////////////////////////////////////
		$qcRuleEnt = \Entity\QcRule::insert();

		$qcRuleEnt->entity =	$formData['entity'];
		$qcRuleEnt->name =		$formData['name'];
		$qcRuleEnt->active =	(Bool)$formData['active'];
		$qcRuleEnt->object =	$qcRuleObj;

		return $qcRuleEnt;
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::update_getDefaultFormData()
	 */
	protected function update_getDefaultFormData($idEntity)
	{
		// get qc rule details
		$qcRule = \Entity\QcRule::select($idEntity);
		// if no record - skip this step
		if (!$qcRule->recordExists()) {
			return null;
		}

		// populate general fields
		$formData['entity'] = $qcRule->entity;
		$formData['name'] = $qcRule->name;
		$formData['active'] = $qcRule->active;

		// populate filters and restrictions
		$ruleObj = $qcRule->object;
		// add filters
		foreach($ruleObj->getFilters() as $filter) {
			$filterDetails = $this->update_getDefaultFormData_addFilterFormData($qcRule->entity, $filter);
			$formData['filters'][$filter->getField()] = $filterDetails;
		}
		// add restrictions
		foreach($ruleObj->getRestrictions() as $restriction) {
			$restrictionDetails = $this->update_getDefaultFormData_addFilterFormData($qcRule->entity, $restriction);
			$formData['restrictions'][$restriction->getField()] = $restrictionDetails;
		}

		return $formData;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::update_createEntityObject()
	 * this method is also been used to duplicate a qcRule, using the insert method
	 */
	protected function update_createEntityObject($formData)
	{

		// inits + create the qc rules object
		$entity = \Entity\QcRule::select($this->updateIdRecord)->entity;
		$ruleClassName = "\App\QcRules\\{$entity}_Rule";
		$qcRuleObj = new $ruleClassName();

		// add filters
		if ($formData['filters']) {
			foreach($formData['filters'] as $field=>$filterDetails) {
				$qcFilterObj = $this->createQcRuleFilterFromRq($entity, $field, $filterDetails);
				if ($qcFilterObj) {
					$qcRuleObj->addFilter($qcFilterObj);
				}
			}
		}

		// add restrictions
		if ($formData['restrictions']) {
			foreach($formData['restrictions'] as $field=>$restrictionDetails) {
				$qcRestrictionObj = $this->createQcRuleFilterFromRq($entity, $field, $restrictionDetails);
				if ($qcRestrictionObj) {
					$qcRuleObj->addRestriction($qcRestrictionObj);
				}
			}
		}

		// CREATE THE ENTITY FOR THIS RULE (TO RETURN IT) /////////////////////////////////////////
		$qcRuleEnt = \Entity\QcRule::update($this->updateIdRecord);
		$qcRuleEnt->name = $formData['name'];
		$qcRuleEnt->active = (Bool)$formData['active'];
		$qcRuleEnt->object = $qcRuleObj;

		return $qcRuleEnt;

	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::delete_createEntityObject()
	 */
	protected function delete_createEntityObject($idRecord)
	{
		return \Entity\QcRule::delete($idRecord);
	}

	/**
	 * Populates the values for the corresponding form based on a filter object.
	 * @param String $entity
	 * @param \App\QcRules\FilterAbstract $filter
	 * @throws \Exception
	 * @return Array
	 */
	private function update_getDefaultFormData_addFilterFormData($entity, \App\QcRules\FilterAbstract $filter)
	{

		// INITIALIZATIONS ------------------------------------------------------------------------
		// get global cfgs
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();

		if (!$CFG['qcRules']['entities'][$entity]['filters'][$filter->getField()]) {
			throw new \Exception('Invalid filter field type; entity:'.$entity.'; filter:'.$filter->getField());
		}
		// get the field type from there
		$fieldType = $CFG['qcRules']['entities'][$entity]['filters'][$filter->getField()]['fieldType'];
		// the output of the function
		$return = [];

		// ATTACH OPERATION -----------------------------------------------------------------------
		$return['operation'] = $filter->operation;

		// ATTACH THE VALUE DEPENDING ON THE FIELD TYPE -------------------------------------------
		switch ($fieldType) {
			case 'currency': case 'corporateSegment': case 'customerSegment': case 'countryCriterion':
			case 'currencyType': case 'formOfPayment': case 'docSeries': case 'docType': case 'agencyBankAccount':
			case 'orderExtSystem': case 'offerFormOfPayment': case 'offerFormOfCashing': case 'offerCalculation': case 'orderServicesType': case 'orderType':
				$return['value'] = current($filter->values);
			break;

			case 'service': case 'orderCode':
				$return['value'] = $filter->values;
			break;

			case 'remark': case 'serviceRemark':
				$return['value'] = $filter->values;
			break;

			case 'corporates': case 'suppliers':
				$return['value'] = array_map(function($id) {
					return ['id'=>$id];
				}, $filter->values);
			break;

			case 'corporateTrust': case 'customer': case 'country':
			case 'user': case 'office': case 'department':
				$return['value'] = [ 'id'=>current($filter->values) ];
			break;

			case 'miceProjects':
				$return['value'] = [];
				foreach ($filter->values as $idMicePrj) {
					$return['value'][] = [ 'id'=>$idMicePrj ];
				}
			break;

			case 'text':
				$return['value'] = reset($filter->values);
			break;

			case null:
				$return['value'] = null;
			break;

			default: {
				throw new \Exception('Invalid filter field type - '.$fieldType);
			}
		}

		// ADD EXTRA FIELDS -----------------------------------------------------------------------
		if ($fieldType=='remark' or $fieldType=='serviceRemark') {
			$return['remarkVar'] = $filter->remarkVar;
			$return['validatorType'] = $filter->validatorType;
			$return['validatorLengthMin'] = $filter->validatorLengthMin;
			$return['validatorLengthMax'] = $filter->validatorLengthMax;
		}
		if ($fieldType=='serviceRemark') {
			$return['serviceCode'] = $filter->serviceCode;
		}

		return $return;

	}


	/**
	 * Creates a new QC filter object from RQ data.
	 * @param String $entity
	 * @param String $field - the filed which is filtered
	 * @param Array $filterDetails
	 * @return \App\QcRules\FilterAbstract
	 */
	private function createQcRuleFilterFromRq($entity, $field, Array $filterDetails)
	{

		// global CFGs
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();

		// if the operation was set
		if ($filterDetails['operation']) {

			$values = null;

			// get filter type
			if (!$CFG['qcRules']['entities'][$entity]['filters'][$field]) {
				throw new \Exception("Invalid QC rule filter: field={$field}; entity={$entity}.");
			}
			$filterType = $CFG['qcRules']['entities'][$entity]['filters'][$field]['fieldType'];

			// get the filter value
			switch ($filterType) {
				case 'corporateSegment': case 'customerSegment': case 'currency': case 'countryCriterion':
				case 'currencyType': case 'formOfPayment': case 'docSeries': case 'docType': case 'agencyBankAccount':
				case 'orderExtSystem': case 'offerFormOfPayment': case 'offerFormOfCashing': case 'offerCalculation': case 'orderServicesType': case 'orderType': case 'orderCode':
					if (strlen($filterDetails['value'])) {
						$values = [ $filterDetails['value'] ];
					} else {
						$values = [];
					}
				break;

				case 'service':
					if (is_array($filterDetails['value'])) {
						$values = $filterDetails['value'];
					} else {
						$values = [];
					}
				break;

				case 'remark': case 'serviceRemark':
					$values = array_filter( array_values( (array)$filterDetails['value'] ), function($elem) { return strlen($elem); } );
				break;

				case 'corporates': case 'suppliers':
					$values = [];
					if ($filterDetails) {
						$values = array_values(array_filter(array_map(function($ac) {
							return $ac['id'];
						}, $filterDetails['value'])));
					}
				break;

				case 'corporateTrust': case 'customer':
				case 'user': case 'office': case 'department': case 'country':
					if ($filterDetails['value']['id']) {
						$values = [ $filterDetails['value']['id'] ];
					} else {
						$values = [];
					}
				break;

				case 'miceProjects':
					$values = [];
					if ($filterDetails['value']) {
						foreach ($filterDetails['value'] as $ent) {
							if ($ent['id']) {
								$values[] = $ent['id'];
							}
						}
					}
				break;

				case 'text':
					$values = [ $filterDetails['value'] ];
				break;

				case null:
					$values = [];
				break;

				default:
					throw new \Exception("Invalid QC rule filter type '{$filterType}' for '{$entity}' entity.");
			}

			// create the filter object
			$filterClassName = "\App\QcRules\\{$entity}_Filter_{$field}";
			$filterObj = new $filterClassName($filterDetails['operation']);
			// set the value (only one for now)
			$filterObj->values = $values;

			// attach extra info
			if ($filterType=='remark' or $filterType=='serviceRemark') {
				$filterObj->remarkVar = $filterDetails['remarkVar'];
				if ($filterDetails['operation']=='anyValue') {
					$filterObj->validatorType = $filterDetails['validatorType'];
					$filterObj->validatorLengthMin = $filterDetails['validatorLengthMin'];
					$filterObj->validatorLengthMax = $filterDetails['validatorLengthMax'];
				}
			}
			if ($filterType=='serviceRemark') {
				$filterObj->serviceCode = array_filter((array)$filterDetails['serviceCode']);
			}
			return $filterObj;

		}

		return null;

	}


	protected function bulkActionActivate(array $recordsIds, \App\MessagesCollector $msgs, array $R)
	{

		// loop selected records and block them
		foreach($recordsIds as $id) {
			$qcRuleEnt = \Entity\QcRule::update($id);
			$qcRuleEnt->active = 1;
			\App\Mvc\Controller\Helpers\EntityOperations::executeSave($qcRuleEnt, $msgs, $this->useSqlTransaction);
			$this->getListingSelection()->delete([$id]);
		}

	}

	protected function bulkActionDeactivate(array $recordsIds, \App\MessagesCollector $msgs, array $R)
	{

		// loop selected records and block them
		foreach($recordsIds as $id) {
			$qcRuleEnt = \Entity\QcRule::update($id);
			$qcRuleEnt->active = 0;
			\App\Mvc\Controller\Helpers\EntityOperations::executeSave($qcRuleEnt, $msgs, $this->useSqlTransaction);
			$this->getListingSelection()->delete([$id]);
		}

	}

}
