<?php
namespace Modules\Documents\Generate\GenerateDocument;

class Controller extends \App\Mvc\Controller\Form\WindowAbstract
{

	/**
	 * The id of the new inserting record.
	 * @var Int|String
	 */
	protected $insertIdRecord = null;

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

		$this->actionsCfg['index'] =     ['checkSection' => false, 'checkOption' => false,];
	}

	/**
	 * The main "save form" action.
	 * @return string
	 */
	protected function actionIndex($R)
	{

		// collects messages
		$msgs = \App\MessagesCollector::create();

		// get information from request
		$pivot = 					$R['pivot'];
		$idPivot = 					$R['idPivot'];

 		// validate the input
		if (!$pivot) {
			throw new \Engine\Mvc\ControllerException("The pivot is not valid");
		}

		// check pivot id
		if (!is_numeric($idPivot)) {
			throw new \Engine\Mvc\ControllerException("The id pivot is not valid");
		}

		// check if pivot is voided
		$documentPivotObject = new \Modules\Documents\Generate\DocumentPivot($pivot, $idPivot);
		if ($documentPivotObject->checkIfPivotIsVoided()) {
			$msgs->addInfo($this->lang['index']['messages']['voidedPivot']);
		}

		if ($R['postAction']) {
			$R[$this->formSubmitButtonName] = true;
		}

		$modelOutput = null;

		// get form data for this operation
		if (!$R[$this->formSubmitButtonName] ) {
			$formData = $this->getFormData($R);
		}
		else {
			$formData = array_merge($this->getFormData($R), $R);

			// SAVE THE FORM DATA /////////////////////////////////////////////////////////////////////
			$modelOutput = $this->processFormData($formData, $msgs);

			// PRINT DOCUMENT
			if ($modelOutput and $formData['postAction'] == 'print' ) {
				// redirect to print section
				$response = new \Engine\Mvc\Response\HtmlRedirect(\Engine\Mvc\Dispatcher::getInstance()->getAppUrl("Modules/Documents/Generate/OpenDocument", "print", [
					'idDocument' => $this->insertIdRecord,
				]));

				return $response;
			}
		}

		$formData['pivot'] = $pivot;
		$formData['idPivot'] = $idPivot;

		// instantiate the view
		$view = new View_Index($this);

		// send data to the view
		$view->addInput('formData', $formData);
		$view->getMessagesCollector()->appendMessages($msgs);
		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);
		$view->setOutputVar('pivot', $pivot);
		$view->setOutputVar('idPivot', $idPivot);

		// redirect to documents management if ok
		if ($modelOutput) {
			$response = new \Engine\Mvc\Response\HtmlRedirect(\Engine\Mvc\Dispatcher::getInstance()->getAppUrl("Modules/Documents/Generate", "index", [
				'idDocument' => 		$this->insertIdRecord,
				'pivot' =>				$pivot,
				'idPivot' => 			$idPivot,
				'parentPageRefresh' => 	true,
			]));

			return $response;
		}

		// do some more stuff (if needed)
		$this->preRenderOperations($view, $formData);

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

	}

	protected function getDefaultFormData($R)
	{
	}

	/**
	 * Returns an array of data which is sent to the form in an identical format as the $_REQUEST.
	 * Is is used to fill in the default (previous) values of the form's fields.
	 * @param Array $R
	 */
	protected function getFormData($R)
	{

		$formData = [];

		$model = new \Modules\Documents\Generate\GenerateDocument\Model();

		// extract details from request
		$pivot = 					$R['pivot'];
		$idPivot = 					$R['idPivot'];
		$documentType = 			$R['documentType'];
		$idDocumentTemplate = 		$R['idDocumentTemplate'];
		$comments =					$R['comments'];
		$idDocumentSeries =			$R['idDocumentSeries'];

		// INSTANTIATE THE MODEL
		$documentPivotObject = new \Modules\Documents\Generate\DocumentPivot($pivot, $idPivot);
		$docCategory = $documentPivotObject->getDocumentCategory();

		// get document types list
		$documentTypesList = $model->getDocumentTypesList($pivot, $docCategory, $idPivot);

		// select first document type
		if (!$documentType and count($documentTypesList) == 1) {
			reset($documentTypesList);
			$documentType = key($documentTypesList);
		}

		// get document templates list
		$documentTemplatesList = $model->getTemplatesList([$documentType]);

		// document series list
		$documentSeriesList = $model->getDocumentSeriesList([$documentType], CURRENT_ID_OFFICE, CURRENT_ID_USER, $idDocumentTemplate);

		// document configs object
		$docCfgObj = \App\Config\IssueDocuments::getInstance();

		// get id series
		if ($docCfgObj->getDocNumberType($documentType) == 'pivotSeries') {
			$idDocumentSeries = $documentPivotObject->getIdDocumentSeries();
		}

		if ($docCfgObj->getDocNumberType($documentType) == 'chooseSeries' and !$idDocumentSeries) {
			$var = 'defaultDocSeries_'.$documentType;
			$idDocumentSeries = \App\EntityPreference\User::getInstance()->$var;
		}

		// check if id document series is valid
		if ($idDocumentSeries and !array_key_exists($idDocumentSeries, $documentSeriesList) and $docCfgObj->getDocNumberType($documentType) == 'chooseSeries') {
			$idDocumentSeries = NULL;
		}

		// select first document template list
		if (!$idDocumentSeries and count($documentSeriesList) == 1 and $docCfgObj->getDocNumberType($documentType) == 'chooseSeries') {
			reset($documentSeriesList);
			$idDocumentSeries = key($documentSeriesList);
		}

		// get document number
		$documentNumber = null;
		if ($docCfgObj->getDocNumberType($documentType) == 'pivotNumber') {
			$documentNumber = $documentPivotObject->getDocumentNumber();
		}

		// get orders services list
		$orderServicesList = [];
		if ($pivot == 'order') {
			$orderServicesList = $documentPivotObject->getOrderServicesList();
			if ($R['servicesList']) {
				$formData['servicesList'] = array_keys($R['servicesList']);
			} else {
				$formData['servicesList'] = array_keys(array_filter($orderServicesList, function($srv){ return $srv['statusOp']!='XX'; }));
			}
		}

		// get client invoice client details
		$clientDetails = [];
		if ($pivot == 'invoice') {
			$clientDetails = $documentPivotObject->getInvoiceClient();

			if (!$idDocumentTemplate) {
				if ($clientDetails['type'] == 'corporate') {
					$var = 'defaultDocTpl_'.$documentType;
					$idDocumentTemplate = \App\EntityPreference\Corporate::getInstance($clientDetails['id'])->$var;
				}
			}
		}


		// get template from user profile
		if (!$idDocumentTemplate) {
			$var = 'defaultDocTpl_'.$documentType;
			$idDocumentTemplate = \App\EntityPreference\User::getInstance()->$var;
		}

		// check if document template exists
		if ($idDocumentTemplate and !array_key_exists($idDocumentTemplate, $documentTemplatesList)) {
			$idDocumentTemplate = NULL;
		}

		// select first document template list
		if (!$idDocumentTemplate and count($documentTemplatesList) == 1) {
			reset($documentTemplatesList);
			$idDocumentTemplate = key($documentTemplatesList);
		}


		// get document template fields details or custom fields
		$documentFieldDetails = [];
		$documentCustomFieldsDetails = [];
		$templateFieldsCfgObj = null;
		if ($idDocumentTemplate) {

			// get the last document of this type generated on this pivot on the same template - get defaul values of the fiedls from there
			$fieldsPreviousVals = [];
			foreach (array_reverse ($documentPivotObject->getDocumentsList(), true) as $documentDetails) {
				if ($documentDetails['docType'] == $documentType and $documentDetails['idTemplate'] == $idDocumentTemplate) {
					$fieldsPreviousVals = $documentDetails['fieldsDetails'];
					break;
				}
			}

			// the document template entity
			$documentTemplateEntity = \Entity\DocumentTemplate::select($idDocumentTemplate);

			// configs object
			$templateFieldsCfgObj = \App\GenDocument\Vars\PivotBuilderConfig::fromPivot($pivot);
			$templateFieldsObj =  	\App\GenDocument\Vars\PivotBuilderValues::fromPivot($pivot, $idPivot, $documentType);

			if ($pivot=='order') {
				$extraParams = [ 'servicesList' => $formData['servicesList'] ];
				$templateFieldsObj->setExtraParams($extraParams);
			}

			// get fiedls details
			$documentFieldDetails = 		$documentTemplateEntity->fieldsDetails;

			// get custom fields details
			$documentCustomFieldsDetails = 	$documentTemplateEntity->customFieldsDetails;

			// STANDARD FIELDS --------------------------------------------------------------------
			if ($documentFieldDetails) {
				foreach ($documentFieldDetails as $fieldCode => $fieldVisibility) {
					$fieldType = $templateFieldsCfgObj->getType($fieldCode);

					if ($fieldType != 'array' and $fieldType != 'object') {
						// default value on the first submit or always for disabled fields
						if (!$R['templateStandardFields'] or ($fieldVisibility == 'disabled' or !$R[$this->formSubmitButtonName]) ) {
							// get previously inputted values or the template default set value
							if ($fieldsPreviousVals[$fieldCode]) {
								$formData['templateStandardFields'][$fieldCode] = $fieldsPreviousVals[$fieldCode]['val'];
							}
							else {
								$formData['templateStandardFields'][$fieldCode] = $templateFieldsObj->getValue($fieldCode);
							}
						}
					}
				}
			}

			/// CUSTOM FIELDS ---------------------------------------------------------------------
			$formData['templateCustomFields'] = [];
			if ($documentCustomFieldsDetails) {
				foreach ($documentCustomFieldsDetails as $fieldCode => $fieldDetails) {
					if ( !$R['templateCustomFields'] or ($fieldDetails['type'] == 'disabled' or !$R[$this->formSubmitButtonName]) ) {
						// get previously inputted values or the template default set value
						if ($fieldsPreviousVals[$fieldCode]) {
							$formData['templateCustomFields'][$fieldCode] = $fieldsPreviousVals[$fieldCode]['val'];
						}
						else {
							$formData['templateCustomFields'][$fieldCode] = $fieldDetails['value'];
						}
					}
				}
			}
		}

		$formData['pivot'] 	=						$pivot;
		$formData['idPivot'] =						$idPivot;
		$formData['documentType'] =					$documentType;
		$formData['idDocumentSeries'] = 			$idDocumentSeries;
		$formData['idDocumentTemplate'] =			$idDocumentTemplate;
		$formData['documentNumber'] = 				$documentNumber;
		$formData['orderServicesList'] = 			$orderServicesList;
		$formData['clientDetails'] =				$clientDetails;
		$formData['documentFieldDetails'] = 		$documentFieldDetails;
		$formData['documentCustomFieldsDetails'] = 	$documentCustomFieldsDetails;
		$formData['templateFieldsCfgObj']	=		$templateFieldsCfgObj;
		$formData['comments'] = 					$comments;
		$formData['docCategory'] =					$docCategory;

		return $formData;
	}


	/**
	 * It uses the $formData (values collected form the form to attempt to save the info in the
	 * database/files (external storage).
	 * @param Array $formData
	 */
	protected function processFormData(Array $formData, \App\MessagesCollector $msgs)
	{

		//////////////////////// VALIDATE INPUT ///////////////////////////////////////////////////

		$pivot = 				$formData['pivot'];
		$idPivot = 				$formData['idPivot'];
		$documentType = 		$formData['documentType'];
		$idDocumentTemplate = 	$formData['idDocumentTemplate'];

		// check document type
		if (!$documentType) {
			$msgs->addWarning($this->lang['index']['messages']['noDocumentType']);
		}

		// check document template
		if (!$idDocumentTemplate) {
			$msgs->addWarning($this->lang['index']['messages']['noDocumentTemplate']);
		}

		$docCfgObj = \App\Config\IssueDocuments::getInstance();

		// check if document must be generated twice ('autoGenerateFirstCopy')
		$regenerateDocument = false;

		// INSTANTIATE THE MODEL
		$documentPivotObject = new \Modules\Documents\Generate\DocumentPivot($pivot, $idPivot);
		$documentsList = $documentPivotObject->getDocumentsList();

		if (!$msgs->hasErrorOrWarning() and $docCfgObj->get($documentType)['autoGenerateFirstCopy'] and $formData['postAction'] != 'preview') {
			// check if this is the first generation
			$regenerateDocument = true;
			// if any other documents of this type are already generated - do not regenerate the doc
			foreach ($documentsList as $document) {
				if ($document['docType'] == $documentType and !$document['preview']) {
					$regenerateDocument = false;
					break;
				}
			}
		}

		// the number of loops
		$loops = 1;
		if ($regenerateDocument) {
			$loops = 2;
		}

		// START GENERATING THE DOCUMENT(S) ///////////////////////////////////////////////////////
		if (!$msgs->hasErrorOrWarning()) {
			switch ($pivot) {
				case 'cashBookDoc':
					\Entity\Document::createMonthlyTables(\Entity\CashBookDocument::select($idPivot)->date);
				break;

				case 'importedService':
					\Entity\Document::createMonthlyTables(\Engine\DateTime::createFromIsoDatetime(\Entity\ImportedService::select($idPivot)->addTime)->formatDateIso());
				break;

				case 'importedDocument':
					\Entity\Document::createMonthlyTables(\Engine\DateTime::createFromIsoDatetime(\Entity\ImportedDocument::select($idPivot)->addTime)->formatDateIso());
				break;

				case 'order': case 'service': case 'invoice': case 'cashing': case 'balance': case 'payment':
					// these are already created in \Entity\Order or \Entity\SupplierInvoice
				break;

				default:
					throw new \Exception( sprintf("[%s] Don't know how to handle monthly table for pivot `%s`.", __METHOD__, $pivot) );
			};

			// sometimes FOP takes time to generate the document, 40s seems to be enough
			// sometimes PHPSpreadsheet take time to generate the document, set the timelimit to 120s
			set_time_limit(120);

			$return = true;
			for ($i = 0; $i < $loops; $i++) {
				// slepp for a second to make sure the doc is not re-written on disk
				if ($i > 0) {
					sleep(1);
				}

				// GENERATE THE DOCUMENT //////////////////////////////////////////////////////////
				try {
					\DB::startTransaction();

					$documentEntity = \Entity\Document::insert();

					$documentEntity->idPivot = 			$idPivot;
					$documentEntity->pivot = 			$pivot;
					$documentEntity->docType = 			$documentType;
					$documentEntity->generation = 		'auto';
					$documentEntity->idTemplate = 		$idDocumentTemplate;
					$documentEntity->idIssueUser = 		CURRENT_ID_USER;

					// document series and number
					if ($formData['idDocumentSeries']) {
						$documentEntity->idDocumentSeries = 	$formData['idDocumentSeries'];
					}
					if ($docCfgObj->getDocNumberType($documentType) == 'manualNumber') {
						$documentEntity->docNumber = $formData['documentNumber'];
					}

					// attach the document date - for 'manual' date
					if ($docCfgObj->getDocDate($documentType) == 'manual') {
						$documentEntity->docDate = $formData['documentDate'];
					}

					// attach standard fields
					if ($formData['templateStandardFields']) {
						$documentEntity->standardFieldsValues = $formData['templateStandardFields'];
					}
					// attach custom fields
					if ($formData['templateCustomFields']) {
						$documentEntity->customFieldsValues = $formData['templateCustomFields'];
					}

					// set the doc as 'preview'
					if ($formData['postAction'] == 'preview') {
						$documentEntity->preview = true;
					}

					// set the document comments
					$documentEntity->comments = $formData['comments'];

					// set the services list
					if ($pivot == 'order') {
						$documentEntity->servicesList = $formData['servicesList'];
					}

					$documentEntity->save();

					\DB::commitTransaction();

					foreach($documentEntity->getMessages()->getMessages() as $msg) {
						$msgs->addMessage($msg);
					}

					// select the first generated document (the original)
					if (!$i) {
						$this->insertIdRecord = $documentEntity->getId();
					}

				}
				catch (\Engine\GenDocument\Generator\Exception $e) {
					\DB::rollbackTransaction();
					$msgs->addWarning($e->getMessage());
					$return = false;
					break;
				}
				catch (\App\Entity\Exception $e) {
					\DB::rollbackTransaction();
					$msgs->addWarning($e->getMessagesCollector()->getMessageBulk());
					$return = false;
					break;
				}

			}

			return $return;

		}
	}

	/**
	 * {@inheritDoc}
	 * @see \App\Mvc\ControllerAbstract::verifyAccessToAction()
	 */
	protected function verifyAccessToAction($action, $R)
	{
		parent::verifyAccessToAction($action, $R);

		$pivotDocumentObject = new \Modules\Documents\Generate\DocumentPivot($R['pivot'], $R['idPivot']);
		if (!$pivotDocumentObject->userHasAccessToGenerate()) {
			throw new \Engine\Mvc\ControllerException(sprintf("You do not have access to the module '%s'", $this->module), "auth_noSectionAccess");
		}
	}
}