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

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, $rowType, $location, $vatType, $currency, $field) = explode('##', $id);

		return [
			'serviceCode' => $serviceCode,
			'rowType' => $rowType,
			'location' => $location,
			'vatType' => $vatType,
			'currency' => $currency,
			'field' => $field,
		];
	}

	/**
	 *
	 * {@inheritDoc}
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::update_getDefaultFormData()
	 */
	protected function update_getDefaultFormData($R)
	{
		$formData = $this->extractDataFromId($R);
		$formData['fields'][$formData['field']] = \App\Config\ExportData_Fields_SupplierInvoice::getInstance()->getFieldValue($formData['field'], $formData['serviceCode'], $formData['rowType'], $formData['location'], $formData['vatType'], $formData['currency']);
		$formData['serviceCode'] = ($formData['serviceCode'] == '') ? 'notApplicable' : $formData['serviceCode'];
		$formData['rowType'] = ($formData['rowType'] == '') ? 'notApplicable' : $formData['rowType'];
		$formData['location'] = ($formData['location'] == '') ? 'notApplicable' : $formData['location'];

		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['fields'][$formData['field']] = \App\Config\ExportData_Fields_SupplierInvoice::getInstance()->getFieldValue($formData['field'], $formData['serviceCode'], $formData['rowType'], $formData['location'], $formData['vatType'], $formData['currency']);
			$formData['serviceCode'] = ($formData['serviceCode'] == '') ? 'notApplicable' : $formData['serviceCode'];
			$formData['rowType'] = ($formData['rowType'] == '') ? 'notApplicable' : $formData['rowType'];
			$formData['location'] = ($formData['location'] == '') ? 'notApplicable' : $formData['location'];
		}

		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_SupplierInvoice::getAdmin();
				if (strlen($formData['fields'][$criteriaFields['field']])!=0) {
					$expDataObj->setValue($criteriaFields['field'], $criteriaFields['serviceCode'], $criteriaFields['rowType'], $criteriaFields['location'], $criteriaFields['vatType'], $criteriaFields['currency'], $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['rowType']) {
				$msgs->addError($this->lang['messages']['error']['rowTypeMandatory']);
			}
			if (!$formData['location']) {
				$msgs->addError($this->lang['messages']['error']['servLocationMandatory']);
			}
			if (!$formData['vatType']) {
				$msgs->addError($this->lang['messages']['error']['vatTypeMandatory']);
			}
			if (!$formData['currency']) {
				$msgs->addError($this->lang['messages']['error']['currencyMandatory']);
			}

			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_SupplierInvoice::getAdmin();
				foreach ($formData['fields'] as $fieldCode => $fieldValue) {
					if (strlen($fieldValue)!=0) {
						$expDataObj->setValue($fieldCode, ($formData['serviceCode'] == 'notApplicable') ? '' : $formData['serviceCode'], ($formData['rowType'] == 'notApplicable') ? '' : $formData['rowType'], ($formData['location'] == 'notApplicable') ? '' : $formData['location'], $formData['vatType'], $formData['currency'], $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_SupplierInvoice::getAdmin();
			foreach ($recordsIds as $id) {
				$fields = $this->extractDataFromId($id);
				$expDataObj->setValue($fields['field'], $fields['serviceCode'], $fields['rowType'], $fields['location'], $fields['vatType'], $fields['currency'], 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]) {

			$expDataArr = [];
			$fields = \App\Config\ExportData_Fields::getInstance()->getFieldsAll('supplierInvoices');
			foreach ($fields as $fieldCode => $fieldDetails) {
				$expDataArr[$fieldCode] = \App\Config\ExportData_Fields_SupplierInvoice::getInstance()->getFieldValue($fieldCode, ($R['serviceCode'] == 'notApplicable') ? '' : $R['serviceCode'], ($R['rowType'] == 'notApplicable') ? '' : $R['rowType'], ($R['location'] == 'notApplicable') ? '' : $R['location'], $R['vatType'], $R['currency']);
			}

			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 simulation
			$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['filterVatType']) {
					$msgs->addError($this->lang['messages']['error']['filterVatTypeMandatory']);
				}
			}

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

			try {
				\DB::startTransaction();
				$expDataRules = \App\Config\ExportData_Fields_SupplierInvoice::getInstance()->getRules(($R['filterServiceCode'] == 'notApplicable') ? '' : $R['filterServiceCode'], $R['filterVatType'], array_keys((Array)$R['fields']));

				$expDataObjAdmin = \App\Config\ExportData_Fields_SupplierInvoice::getAdmin();
				foreach ($expDataRules as $expDataRule) {
					$expDataObjAdmin->setValue($expDataRule['field'], ($R['newServiceCode'] == 'notApplicable') ? '' : $R['newServiceCode'], $expDataRule['rowType'], $expDataRule['location'], $R['newVatType'], $expDataRule['currency'], $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', $R);

		$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('supplierInvoices');
			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'],
					'rowType' => $this->lang['index']['listCols']['rowType'],
					'location' => $this->lang['index']['listCols']['location'],
					'vatType' => $this->lang['index']['listCols']['vatType'],
					'currency' => $this->lang['index']['listCols']['currency'],
				];

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


				// add all combinations of configurations to output by applying the form filters
				$servicesObj = \App\Config\Services_Basic::getInstance();
				if ($R['serviceCode']) {
					if ($R['serviceCode'] == 'notApplicable') {
						$serviceCodes = ['' => 'notApplicable'];
					} else {
						$serviceCodes = [$R['serviceCode'] => $servicesObj->getServiceName($R['serviceCode'])];
					}
				} else {
					$serviceCodes = array_merge(['' => 'notApplicable'], $servicesObj->getListLinear());
				}

				if ($R['rowType']) {
					if ($R['rowType'] == 'notApplicable') {
						$rowTypes = [''];
					} else {
						$rowTypes = [$R['rowType']];
					}
				} else {
					$rowTypes = ['', 'price', 'advance', 'discount', 'tax', 'penalty'];
				}

				if ($R['location']) {
					if ($R['location'] == 'notApplicable') {
						$locations = [''];
					} else {
						$locations = [$R['location']];
					}
				} else {
					$locations = array_merge([''], $CFG['countriesCriteria']);
				}


				$vatTypes = \App\Config\SupplierInvoice_Vats::getInstance()->getAll();
				$currencies = $R['currency'] ? [$R['currency']] : \App\Config\Currencies::getInstance()->getSimple();

				// 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']);

					$invoiceVats = $vatTypes[$serviceCode]['list'];
					if ($invoiceVats === null) {
						continue;
					}

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

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

							foreach ($invoiceVats as $vatName => $vatCalc) {
								// add the vatType, this will get used in the end, to transmit it to the csv
								$row['vatType'] = $vatName;

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

									$row['fields'] = $selectedFieldsCodesBlankArray;

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

									$csvRow = [];
									$csvRow[] = $row['serviceCode'] ? $serviceCodeName: $this->lang['notApplicable'];
									$csvRow[] = $row['rowType'] ? $this->lang['rowTypes'][$row['rowType']]: $this->lang['notApplicable'];
									$csvRow[] = $row['location'] ? $this->globalLang['locations']['countriesCriteria']['long'][$row['location']] : $this->lang['notApplicable'];
									$csvRow[] = $row['vatType'];
									$csvRow[] = $row['currency'];
									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());
		}
	}
}