<?php
namespace Modules\Admin\ExportData\ClientInvoices;


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

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

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::initialize()
	 */
	protected function initialize()
	{
		parent::initialize();

		$this->actionsCfg['insert'] 	= ['checkOption' => false,];
		$this->actionsCfg['delete'] 	= ['checkOption' => false,];
		$this->actionsCfg['update'] 	= ['checkOption' => false,];
		$this->actionsCfg['simulate'] 	= ['checkOption' => false,];
		$this->actionsCfg['cloneBulk'] 	= ['checkOption' => false,];
		$this->actionsCfg['export']		= ['checkOption' => false,];
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionDefineParams()
	 */
	protected function optionDefineParams(\App\Mvc\View\Utils\RowOptions\Option\Option $option, $selection)
	{
		return true;
	}

	/**
	 *
	 * {@inheritDoc}
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionGetEntityName()
	 */
	protected function optionGetEntityName($id)
	{
		return '';
	}

	/**
	 * Extract entity data from the input ID
	 * @param string $id
	 * @return array
	 */
	private function extractDataFromId($id)
	{
		list($serviceCode, $location, $calculationType, $rowType, $clientType, $currency, $advanceInvoice, $field) = explode('##', $id);

		return [
			'serviceCode' => $serviceCode,
			'location' => $location,
			'calculationType' => $calculationType,
			'rowType' => 	$rowType,
			'clientType' => $clientType,
			'currency' => $currency,
			'advanceInvoice' => $advanceInvoice,
			'field' => $field,
		];
	}

	/**
	 *
	 * {@inheritDoc}
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::update_getDefaultFormData()
	 */
	protected function update_getDefaultFormData($R)
	{
		$formData = $this->extractDataFromId($R);
		$formData['servLocationCalculation'] = implode('|', [$formData['location'], $formData['calculationType']]);
		$formData['fields'][$formData['field']] = \App\Config\ExportData_Fields_ClientInvoice::getInstance()->getFieldValue($formData['field'], $formData['serviceCode'], $formData['location'], $formData['calculationType'], $formData['rowType'], $formData['clientType'], $formData['currency'], $formData['advanceInvoice']);

		//remove the location and calc key from the array as they are not needed in the form
		unset($formData['location']);
		unset($formData['calculationType']);

		return $formData;
	}

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

		if ($R['idClonedRule']) {
			$formData = $this->extractDataFromId($R['idClonedRule']);
			$formData['servLocationCalculation'] = implode('|', [$formData['location'], $formData['calculationType']]);
			$formData['fields'][$formData['field']] = \App\Config\ExportData_Fields_ClientInvoice::getInstance()->getFieldValue($formData['field'], $formData['serviceCode'], $formData['location'], $formData['calculationType'], $formData['rowType'], $formData['clientType'], $formData['currency'], $formData['advanceInvoice']);

			//remove the location and calc key from the array as they are not needed in the form
			unset($formData['location']);
			unset($formData['calculationType']);
		}

		if ($R['serviceChanged']) {
			$formData = $R;
			$formData['addNewRule'] = 1; // the checkbox is checked by default
		}
		return $formData;
	}

	/**
	 *
	 * {@inheritDoc}
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::update_doUpdate()
	 */
	protected function update_doUpdate($formData, \App\MessagesCollector $msgs)
	{
		$criteriaFields = $this->extractDataFromId($formData['id']);

		foreach ($criteriaFields as $code => $value) {
			$formData[$code] = $value;
		}

		if (strlen($formData['fields'][$criteriaFields['field']])==0) {
			$msgs->addError($this->lang['messages']['error']['fieldMandatory']);
		}

		if (!$msgs->hasErrorOrWarning()) {
			try {
				\DB::startTransaction();
				$expDataObj = \App\Config\ExportData_Fields_ClientInvoice::getAdmin();
				if (strlen($formData['fields'][$criteriaFields['field']])!=0) {
					$expDataObj->setValue($criteriaFields['field'], $criteriaFields['serviceCode'], $criteriaFields['location'], $criteriaFields['calculationType'], $criteriaFields['rowType'], $criteriaFields['clientType'], $criteriaFields['currency'], $criteriaFields['advanceInvoice'], $formData['fields'][$criteriaFields['field']]);
				}

				$expDataObj->save();
				$msgs->addSuccess($this->lang['update']['messages']['success']);
				$this->insertIdRecord = true;
				\DB::commitTransaction();
				return true;
			}
			catch (\App\Config\MessageException $e) {
				\DB::rollbackTransaction();
				$msgs->addError(sprintf($this->lang['update']['messages']['error'], $e->getMessage()));
				return false;
			}
		}

	}

	/**
	 * Sets the type of return response
	 * @param \App\Mvc\ViewAbstract $view
	 * @param array $formData
	 * @param boolean $modelOutput
	 * @param \App\MessagesCollector $msgs
	 * @return \Engine\Mvc\Response\Html
	 */
	protected function insert_returnResponse(\App\Mvc\ViewAbstract $view, array $formData, $modelOutput, \App\MessagesCollector $msgs)
	{
		// send data to the view
		if ($modelOutput) {
			if ($this->insertIdRecord && $formData['addNewRule']) {
				unset($formData['fields']);
			}

			if (!$formData['addNewRule']) {
				$view->setClosePopup(true);
			}
		}
		$view->addInput('formData', $formData);

		$view->getMessagesCollector()->appendMessages($msgs);
		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);
		$view->addInput('idRecord', $this->insertIdRecord);

		// render the view
		return new \Engine\Mvc\Response\Html($view->render());
	}

	/**
	 *
	 * {@inheritDoc}
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::insert_doInsert()
	 */
	protected function insert_doInsert($formData, \App\MessagesCollector $msgs)
	{
		if (!$formData['fields']) {
			$msgs->addError($this->lang['messages']['error']['fieldsNotDefined']);
		}

		if (!$formData['serviceCode']) {
			$msgs->addError($this->lang['messages']['error']['servCodeMandatory']);
		}
		else {
			if (!$formData['servLocationCalculation']) {
				$msgs->addError($this->lang['messages']['error']['servLocCalcMandatory']);
			}
			if (!$formData['rowType']) {
				$msgs->addError($this->lang['messages']['error']['rowTypeMandatory']);
			}
			if (!$formData['clientType']) {
				$msgs->addError($this->lang['messages']['error']['clientTypeMandatory']);
			}
			if (!$formData['currency']) {
				$msgs->addError($this->lang['messages']['error']['currencyMandatory']);
			}
			if (!isset($formData['advanceInvoice'])) {
				$msgs->addError($this->lang['messages']['error']['advanceMandatory']);
			}

			if ($formData['fields']) {
				$checkFieldValueSet = 0;
				foreach ($formData['fields'] as $fieldValue) {
					if (strlen($fieldValue)!=0) {
						$checkFieldValueSet = 1;
					}
				}
				if (!$checkFieldValueSet) {
					$msgs->addError($this->lang['messages']['error']['fieldsMandatory']);
				}
			}
		}

		if (!$msgs->hasErrorOrWarning()) {
			try {
				\DB::startTransaction();
				$expDataObj = \App\Config\ExportData_Fields_ClientInvoice::getAdmin();
				list($location, $calculation) = explode('|', $formData['servLocationCalculation']);
				foreach ($formData['fields'] as $fieldCode => $fieldValue) {
					if (strlen($fieldValue)!=0) {
						$expDataObj->setValue($fieldCode, $formData['serviceCode'], $location, $calculation, $formData['rowType'], $formData['clientType'], $formData['currency'], $formData['advanceInvoice'], $fieldValue);
					}
				}

				$expDataObj->save();
				$this->insertIdRecord = true;
				\DB::commitTransaction();
				$msgs->addSuccess($this->lang['insert']['messages']['success']);
				return true;
			} catch (\App\Config\MessageException $e) {
				\DB::rollbackTransaction();
				$msgs->addError(sprintf($this->lang['insert']['messages']['error'], $e->getMessage()));
				return false;
			}
		}

	}

	/**
	 *
	 * {@inheritDoc}
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::delete_doDelete()
	 */
	protected function delete_doDelete(array $recordsIds, \App\MessagesCollector $msgs, array $R)
	{
		try {
			\DB::startTransaction();
			$expDataObj = \App\Config\ExportData_Fields_ClientInvoice::getAdmin();
			foreach ($recordsIds as $id) {
				$fields = $this->extractDataFromId($id);
				$expDataObj->setValue($fields['field'], $fields['serviceCode'], $fields['location'], $fields['calculationType'], $fields['rowType'], $fields['clientType'], $fields['currency'], $fields['advanceInvoice'], null);
			}
			$expDataObj->save();
			\DB::commitTransaction();
			$this->getListingSelection()->clear();
		}
		catch (\App\Config\MessageException $ex) {
			\DB::rollbackTransaction();
			$msgs->addError($ex->getMessage());
		}
	}

	/**
	 * Simulates if a value exists for a combination of criteria and displays that value
	 * @param array $R
	 * @return \Engine\Mvc\Response\Html
	 */
	public function actionSimulate($R)
	{
		$msgs = \App\MessagesCollector::create();

		// get form data for this operation
		if (!$R[$this->formSubmitButtonName]) {
			//default form data for simulation
			$formData = [];

			if ($R['serviceChanged']) {
				$formData = $R;
			}
		} else {
			$formData = $R;
		}

		// execute the model (and collect the output)
		if ($R[$this->formSubmitButtonName]) {

			if (!$R['serviceCode']) {
				$msgs->addError($this->lang['messages']['error']['servCodeMandatory']);
			}
			else {
				if (!$R['rowType']) {
					$msgs->addError($this->lang['messages']['error']['rowTypeMandatory']);
				}
				if (!$R['servLocationCalculation']) {
					$msgs->addError($this->lang['messages']['error']['servLocCalcMandatory']);
				}
				if (!$R['clientType']) {
					$msgs->addError($this->lang['messages']['error']['clientTypeMandatory']);
				}
				if (!$R['currency']) {
					$msgs->addError($this->lang['messages']['error']['currencyMandatory']);
				}
				if (strlen($R['advanceInvoice'])==0) {
					$msgs->addError($this->lang['messages']['error']['advanceMandatory']);
				}
			}

			if (!$msgs->hasErrorOrWarning()) {
				list($location, $calculationType) = explode('|', $R['servLocationCalculation']);

				$expDataArr = [];
				$fields = \App\Config\ExportData_Fields::getInstance()->getFieldsAll('clientInvoices');
				foreach ($fields as $fieldCode => $fieldDetails) {
					$expDataArr[$fieldCode] = \App\Config\ExportData_Fields_ClientInvoice::getInstance()->getFieldValue($fieldCode, $R['serviceCode'], $location, $calculationType, $R['rowType'], $R['clientType'], $R['currency'], $R['advanceInvoice']);
				}

				if ($expDataArr) {
					$formData['fieldsValues'] = $expDataArr;
				}
			}
		}

		// create the view
		$view = new View_Simulate($this);

		// append messages
		$view->getMessagesCollector()->appendMessages($msgs);

		// add form data
		$view->addInput('formData', $formData);

		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);

		// render the view
		return new \Engine\Mvc\Response\Html($view->render());
	}

	/**
	 * Clones bulk the configurations of certain fields (selected in the form)
	 * @param array $R
	 * @return \Engine\Mvc\Response\Html
	 */
	public function actionCloneBulk($R)
	{
		$msgs = \App\MessagesCollector::create();

		// get form data for this operation
		if (!$R[$this->formSubmitButtonName]) {
			//default form data for cloning
			$formData = [];

			if ($R['filterServiceChanged'] or $R['newServiceChanged']) {
				$formData = $R;
			}
		} else {
			$formData = $R;
		}

		// execute the model (and collect the output)
		if ($R[$this->formSubmitButtonName]) {
			// filter mandatory
			if (!$formData['filterServiceCode']) {
				$msgs->addError($this->lang['messages']['error']['filterServCodeMandatory']);
			} else {
				if (!$formData['filterServLocationCalculation']) {
					$msgs->addError($this->lang['messages']['error']['filterServLocCalcMandatory']);
				}
			}

			// new rules criteria mandatory
			if (!$formData['newServiceCode']) {
				$msgs->addError($this->lang['messages']['error']['newServCodeMandatory']);
			} else {
				if (!$formData['newServLocationCalculation']) {
					$msgs->addError($this->lang['messages']['error']['newServLocCalcMandatory']);
				}
			}

			list($filterLocation, $filterCalculationType) = explode('|', $formData['filterServLocationCalculation']);
			list($newLocation, $newCalculationType) = explode('|', $formData['newServLocationCalculation']);

			try {
				\DB::startTransaction();
				$expDataRules = \App\Config\ExportData_Fields_ClientInvoice::getInstance()->getRules($formData['filterServiceCode'], $filterLocation, $filterCalculationType, array_keys((Array)$formData['fields']));

				$expDataObjAdmin = \App\Config\ExportData_Fields_ClientInvoice::getAdmin();
				foreach ($expDataRules as $expDataRule) {
					$expDataObjAdmin->setValue($expDataRule['field'], $formData['newServiceCode'], $newLocation, $newCalculationType, $expDataRule['rowType'], $expDataRule['clientType'], $expDataRule['currency'], $expDataRule['advanceInvoice'], $expDataRule['value']);
				}
				$expDataObjAdmin->save();
				\DB::commitTransaction();
				$msgs->addSuccess($this->lang['insert']['messages']['success']);
			}
			catch (\App\Config\MessageException $e) {
				\DB::rollbackTransaction();
				$msgs->addError(sprintf($this->lang['insert']['messages']['error'], $e->getMessage()));
			}
		}

		// create the view
		$view = new View_CloneBulk($this);

		// append messages
		$view->getMessagesCollector()->appendMessages($msgs);

		// add form data
		$view->addInput('formData', $formData);

		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);

		// render the view
		return new \Engine\Mvc\Response\Html($view->render());
	}

	/**
	 * Export the configurations of certain fields and criteria (selected in the form)
	 * @param array $R
	 * @return \Engine\Mvc\Response\Html
	 */
	public function actionExport($R)
	{
		set_time_limit(0);

		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();
		$msgs = \App\MessagesCollector::create();

		$response = null;

		// get form data for this operation
		if (!$R[$this->formSubmitButtonName]) {
			//default form data for export
			$formData = [];
			$activeFieldCodes = \App\Config\ExportData_Fields::getInstance()->getFieldsActive('clientInvoices');
			foreach ($activeFieldCodes as $fieldCode => $fieldName) {
				$formData['fields'][$fieldCode] = 1;
			}
		} else {
			$formData = $R;
		}

		// execute the model (and collect the output)
		if ($R[$this->formSubmitButtonName]) {
			try {
				if (!$R['fields']) {
					throw new \App\Config\MessageException($this->lang['messages']['error']['fieldsMandatory']);
				}

				$fileHeaderRow = [
					'serviceCode' => $this->lang['index']['listCols']['serviceCode'],
					'location' => $this->lang['index']['listCols']['location'],
					'calculationType' => $this->lang['index']['listCols']['calculationType'],
					'rowType' => $this->lang['index']['listCols']['rowType'],
					'clientType' => $this->lang['index']['listCols']['clientType'],
					'currency' => $this->lang['index']['listCols']['currency'],
					'advanceInvoice' => $this->lang['index']['listCols']['advanceInvoice'],
				];

				$selectedFieldsCodes = [];
				foreach ($formData['fields'] as $fieldCode => $selected) {
					$fileHeaderRow[] = \App\Config\ExportData_Fields::getInstance()->getFieldName('clientInvoices', $fieldCode);
					$selectedFieldsCodes[] = $fieldCode;
				}


				// add all combinations of configurations to output by applying the form filters
				$servicesObj = \App\Config\Services_Basic::getInstance();
				$serviceCodes = $R['serviceCode'] ? [$R['serviceCode'] => $servicesObj->getServiceName($R['serviceCode'])] : $servicesObj->getListLinear();
				$locations = $R['location'] ? [$R['location']] : $CFG['countriesCriteria'];
				$rowTypes = $R['rowType'] ? [$R['rowType']] : ['price', 'commission', 'discount', 'serviceFee', 'tax', 'advance', 'penalty'];
				$clientTypes = $R['clientType'] ? [$R['clientType']] : ['individual', 'legalEntity'];
				$currencies = $R['currency'] ? [$R['currency']] : \App\Config\Currencies::getInstance()->getSimple();
				$advanceInvoices = isset($R['advanceInvoice']) ? [$R['advanceInvoice']] : ['0', '1'];

				// add all data to the csv, download it, and delete it from server
				$fileName = sprintf("%s_%s.csv", $this->lang['export']['fileName']['export'], DATETIME);
				$filePath = $CFG['paths']['temporary'];

				$outputCsvFile = fopen($filePath.$fileName, "w");
				fputcsv($outputCsvFile, $fileHeaderRow, ",", "\"", "");

				$selectedFieldsCodesBlankArray = [];
				foreach ($selectedFieldsCodes as $fieldCode) {
					$selectedFieldsCodesBlankArray[$fieldCode] = '';
				}

				/**
				 * Optimisation documentation
				 * Below, there were 3 steps of exporting the csv:
				 * 1. loop thru the 5 variable arrays (serviceCodes, locations etc.) to get ALL
				 * existing combinations
				 * 2. call the model and get the data for each combination
				 * 3. send the data to the csv
				 */

				foreach ($serviceCodes  as $serviceCode => $serviceDetails) {
					// create the array that holds the csv `field`:`value` pairs
					$row = [];
					// add the serviceCode, this will get used in the end, to transmit it to the csv
					$row['serviceCode'] = $serviceCode;

					$serviceCodeName = $servicesObj->getServiceName($row['serviceCode']);

					foreach ($locations as $servLocation) {
						// add the location, this will get used in the end, to transmit it to the csv
						$row['location'] = $servLocation;

						foreach (\App\Config\Services_Calculations::getInstance()->getServiceLocationSimpleList($serviceCode, $servLocation, true) as $servCalcCode => $servCalcName) {
							// add the calculationType, this will get used in the end, to transmit it to the csv
							$row['calculationType'] = (String)$servCalcCode;

							$calculationName = \App\Config\Services_Calculations::getInstance()->getServiceLocationCalculationName($row['serviceCode'], $row['location'], $row['calculationType']);

							foreach ($rowTypes as $invRowType) {
								// add the rowType, this will get used in the end, to transmit it to the csv
								$row['rowType'] = $invRowType;

								foreach ($clientTypes as $clientType) {
									// add the clientType, this will get used in the end, to transmit it to the csv
									$row['clientType'] = $clientType;

									foreach ($currencies as $currency) {
										// add the currency, this will get used in the end, to transmit it to the csv
										$row['currency'] = $currency;

										foreach ($advanceInvoices as $advanceInvoice) {
											// add the invoiced in advance, this will get used in the end, to transmit it to the csv
											$row['advanceInvoice'] = $advanceInvoice;

											$row['fields'] = $selectedFieldsCodesBlankArray;

											// get the current value
											foreach ($selectedFieldsCodes as $fieldCode) {
												$row['fields'][$fieldCode] = \App\Config\ExportData_Fields_ClientInvoice::getInstance()->getFieldValue($fieldCode, $row['serviceCode'], $row['location'], $row['calculationType'], $row['rowType'], $row['clientType'], $row['currency'], $row['advanceInvoice']);
											}
										}

										$csvRow = [];
										$csvRow[] = $serviceCodeName;
										$csvRow[] = $this->globalLang['locations']['countriesCriteria']['long'][$row['location']];
										$csvRow[] = $calculationName;
										$csvRow[] = $this->lang['rowTypes'][$row['rowType']];
										$csvRow[] = $this->lang['clientTypes'][$row['clientType']];
										$csvRow[] = $row['currency'];
										$csvRow[] = $row['advanceInvoice'] ? $this->globalLang['yes'] : $this->globalLang['no'];
										foreach ($selectedFieldsCodes as $selectedFieldCode) {
											$csvRow[] = $row['fields'][$selectedFieldCode];
										}
										fputcsv($outputCsvFile, $csvRow, ",", "\"", "");
									}
								}
							}
						}
					}
				}


				fclose($outputCsvFile);

				$response = new \Engine\Mvc\Response\BigFileDownload($filePath.$fileName);
				$response->body->setOption('deleteAfterSend', true);
				$response->setFilename($fileName);

				$msgs->addSuccess($this->lang['export']['messages']['success']);

			} catch (\App\Config\MessageException $e) {
				$msgs->addError($e->getMessage());
			}
		}

		// create the view
		$view = new View_Export($this);

		// append messages
		$view->getMessagesCollector()->appendMessages($msgs);

		// add form data
		$view->addInput('formData', $formData);

		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);

		if	($response) {
			return $response;
		} else {
			// render the view
			return new \Engine\Mvc\Response\Html($view->render());
		}
	}
}