<?php
namespace Modules\Orders\ImportedOrders\ServicesList;

class Controller extends \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract
{
	/**
	 * The name of the button when importing a manual file containing an order.
	 * @var String
	 */
	protected $formSubmitButtonName = 'save';

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

		$this->actionsCfg['block'] = 			[ 'checkOption' => 'Modules/Orders/ImportedOrders/ServicesList-block', ];
		$this->actionsCfg['unblock'] = 			[ 'checkOption' => 'Modules/Orders/ImportedOrders/ServicesList-block', ];
		$this->actionsCfg['viewOrder'] = 		[];
		$this->actionsCfg['insert'] = 			[];
		$this->actionsCfg['downloadFile'] = 	[];
		$this->actionsCfg['orderDetails'] = 	[];
		$this->actionsCfg['ticketDetails'] = 	[ 'checkSection'=>false ];
	}

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

	/**
	 * Block a list of services
	 * @return string
	 */
	protected function actionBlock(array $R)
	{
		$msgs = \App\MessagesCollector::create();
		$this->setListingSelection($R['listing']['selection']);
		$recordsIds = $this->getListingSelection()->getList()?:[$R['id']];
		$formData = $R;
		$closePopup = false;

		// execute the model (and collect the output)
		if ($R[$this->formSubmitButtonName]) {
			\DB::startTransaction();
			try {
				foreach ($recordsIds as $id) {
					$impServ = \Entity\ImportedService::block($id);
					$impServ->blockedComments = $formData['blockedComments'];
					$impServ->save();
					$this->getListingSelection()->delete([$id]);
				}
				\DB::commitTransaction();

				// action was successful
				$msgs->addSuccess($this->lang['index']['msgs']['blockSuccess']);
				$closePopup = true;
			}
			catch (\App\Entity\Exception $e) {
				\DB::rollbackTransaction();
				$msgs->addError($e->getMessageBulk());
			}
		}

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

		// send data to the view
		$view->addInput('formData', $formData);
		if ($closePopup) {
			$view->setClosePopup($closePopup);
		}
		$view->getMessagesCollector()->appendMessages($msgs);
		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);

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

	/**
	 * Unblock a list of services
	 * @param Array $R
	 */
	protected function bulkActionUnblock(array $recordsIds, \App\MessagesCollector $msgs, array $R)
	{
		foreach ($recordsIds as $id) {
			try {
				\DB::startTransaction();

				$impServ = \Entity\ImportedService::unblock($id);
				$impServ->save();

				// remove this record from the internal list
				$this->getListingSelection()->delete([$id]);

				// commit the current transaction
				\DB::commitTransaction();
				foreach ($impServ->getMessages()->getMessages() as $msg) {
					$msgs->addMessage($msg);
				}
			}
			catch (\App\Entity\Exception $ex) {
				\DB::rollbackTransaction();
				$msgs->addMessage(new \App\Message('warning', $ex->getMessage()));
			}
		}
	}

	/**
	 * Action view order open new popup with informations about order
	 */
	protected function actionViewOrder($R)
	{

		// create model object
		$model = new Model();

		// create view object
		$view = new View_ViewOrder($this);

		// get object \App\ImportedOrder\Order;
		$importedOrderObj = $model->actionOrderInfos($R['idOrder']);

		// attach object \App\ImportedOrder\Order to view
		$view->addInput('importedOrderObj', $importedOrderObj);

		// attach id order
		$view->addInput('idOrder', $R['idOrder']);

		// extract files from \Entity\ImportedOrder
		$filesList = $model->getImportedOrderFiles($R['idOrder']);

		// extract importedServicesList
		$servicesList = \Entity\ImportedOrder::select($R['idOrder'])->importedServicesList;

		$importedServicesList = [];

		foreach ($servicesList as $serviceDetails) {
			$importedServicesList[$serviceDetails['idServiceExtSys']] = $serviceDetails;
		}

		// send to view imported services list
		$view->addInput('importedServicesList', $importedServicesList);

		// attach number of files to view for drawing number of buttons for downloading files
		$view->addInput('filesList', $filesList);

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


	/**
	 * Action download file
	 * @throws \Exception
	 */
	protected function actionDownloadFile($R)
	{

		// instantiate the model
		$model = new Model();

		// extract filesList
		$filesList = $model->getImportedOrderFiles($R['idOrder']);

		// extract informations for selected file
		$fileInfo = $this->searchByValue($R['file'], $filesList);

		if ($fileInfo and $fileInfo['fileExists']) {

			// create view object for this action
			$view = new View_DownloadFile($this);

			// determine the dwld file name
			if ($fileInfo['name']) {
				$filename = \Engine\File::getName($fileInfo['name']) . ' ['.str_replace(':', '.', $fileInfo['time']).'].' . \Engine\File::getExtension($fileInfo['name']);
			} else {
				$filename = $fileInfo['file'];
			}

			// send informations to view
			$view->addInput('fileInfo', $fileInfo);

			$response = new \Engine\Mvc\Response\FileDownload($view->render());
			$response->setFilename($filename);
			return $response;
		}
		else {
			throw new \Exception("Selected file is not in the list of files for current order");
		}
	}

	/**
	 * Search in associative array by value and return array
	 * @param String $needle
	 * @param array $haystack
	 * @return array
	 */
	private function searchByValue($needle, Array $haystack)
	{
		foreach ($haystack as $data) {
			if ($data['file'] === $needle) {
				return $data;
			}
		}
		return [];
	}


	/**
	 * Display all imported order details
	 */
	protected function actionOrderDetails($R)
	{
		// instantiate the model
		$model = new Model();

		// get object imported order
		$importedOrderObj = $model->actionOrderInfos($R['idOrder']);

		// create view object
		$view = new View_OrderDetails($this);

		// attach id order
		$view->addInput('idOrder', $R['idOrder']);

		// send to view importedOrderObject
		$view->addInput('importedOrderObj', $importedOrderObj);

		$view->setOutputVar('revealCcNumbers', $R['revealCcNumbers']);


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

	}

	protected function actionTicketDetails($R)
	{
		// create view object
		$view = new View_TicketDetails($this);

		if (!$R['idImportedService']) {
			if ($R['ticketNumber'] and $R['ticketDate']) {
				$matchedTickets = \Entity\ImportedService::getDetailsByTicketNumber($R['ticketNumber'], $R['ticketDate']);
				if ($matchedTickets and count($matchedTickets)==1) {
					$R['idImportedService'] = $matchedTickets[0]['id'];
				} else {
					\MessageStack::GetObject()->SetWarning($this->lang['ticketDetails']['noTicketFound']);
				}
			}
		}

		if ($R['idImportedService']) {
			$importedService = \Entity\ImportedService::select($R['idImportedService']);
			$importedServiceObj = $importedService->object;

			$view->addInput('importedService', $importedService);
			$view->addInput('importedServiceObj', $importedServiceObj);
			$view->addInput('passengers', (array)$importedServiceObj->passengers);
			if ($importedServiceObj->chosenOffer) {
				$view->addInput('tickets', (array)$importedServiceObj->chosenOffer->ticketNumbers);
				$view->addInput('itinerary', $importedServiceObj->chosenOffer->itinerary);
				$view->addInput('segments', ($importedServiceObj->chosenOffer->itinerary?$importedServiceObj->chosenOffer->itinerary->segments:[]));
				$view->addInput('taxCodes', (array)$importedServiceObj->chosenOffer->taxCodes);
			} else {
				\MessageStack::GetObject()->SetWarning($this->lang['ticketDetails']['noTicketToDisplay']);
			}
		}


		if (!$R['idImportedService'] and !$R['ticketNumber']) {
			\MessageStack::GetObject()->SetWarning($this->lang['ticketDetails']['noImpServ']);
		}

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

	}

	protected function actionInsert($R)
	{

		$msgs = \App\MessagesCollector::create();

		$idRecord = null;

		$modelOutput = null;

		// execute the model (and collect the output)
		if ($R[$this->formSubmitButtonName]) {
			$modelOutput = $this->insert_doInsert($msgs, $idRecord, $R['applyMode']);
		}

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

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

		// send data to the view
		$view->addInput('formData', $formData);
		if ($modelOutput) {
			$view->setClosePopup(true);
		}
		$view->getMessagesCollector()->appendMessages($msgs);
		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);
		$view->addInput('idRecord', $idRecord);

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

	/**
	 * (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': case 'viewOrder': case 'ticketDetails': case 'documentsBulkDownload':
			break;

			case 'block':
				foreach ($selection as $selectedItem) {
					if (!$option->determineOperationAvailability(\Entity\ImportedService::block($selectedItem))) {
						break;
					}
					if (\Entity\ImportedService::select($selectedItem)->processStatus=='blocked') {
						$option->setDisabled();
					}
				}
			break;

			case 'unblock':
				foreach ($selection as $selectedItem) {
					if (!$option->determineOperationAvailability(\Entity\ImportedService::unblock($selectedItem))) {
						break;
					}
					if (\Entity\ImportedService::select($selectedItem)->processStatus!='blocked') {
						$option->setDisabled();
					}
				}
			break;

			case 'issue':
				if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('importedServiceDocumentsManagement')) {
					$option->setDisabled()->addMessage('warning', $this->globalLang['noAccessToOption']);
				}
				elseif (!\App\Config\IssueDocuments::getInstance()->getImportedServiceDocsList()) {
					$option->setDisabled()->addMessage('info', $this->lang['index']['options']['reasons']['issue']['noActiveDocuments']);
				}


				foreach ($selection as $selectedItem) {
					// determine option icon
					$option->determineIconGeneratedDocuments($selectedItem);
				}

			break;

			case 'addServiceOnOrder':
				// get list with imported services ids which have been already added on current order
				$alreadyImportedService = \Modules\Orders\OrderForm\Model_Handler::getInstance()->getImportedServiceIds();
				foreach ($selection as $id) {
					// get imported service entity
					$importedServiceEnt = \Entity\ImportedService::select($id);

					if ($importedServiceEnt->processStatus != "new") {
						$option->setDisabled();
						$option->addMessage('warning', sprintf($this->lang['index']['options']['reasons']['addServiceOnOrder']['alreadyProcessed'], ($importedServiceEnt->offerExternalSystemReservationId?$importedServiceEnt->offerExternalSystemReservationId:$importedServiceEnt->idServiceExtSys)));
						break;
					}

					// check if service is not already imported
					if (in_array($id, $alreadyImportedService)) {
						$option->setDisabled();
						$option->addMessage('warning', sprintf($this->lang['index']['options']['reasons']['addServiceOnOrder']['alreadyImported'], ($importedServiceEnt->offerExternalSystemReservationId?$importedServiceEnt->offerExternalSystemReservationId:$importedServiceEnt->idServiceExtSys)));
						break;
					}

					if ($importedServiceEnt->isPackage) {
						if (count($selection)>1) {
							$option->setDisabled(); // only one package can be imported at a time
							$option->addMessage('info', $this->lang['index']['options']['reasons']['addServiceOnOrder']['onlyOnePackageCanBeImportedAtATime']);
							break;
						}

						foreach ($importedServiceEnt->packageSubservicesList as $subserviceDetails) {
							if ($subserviceDetails['processStatus'] != 'new') {
								$option->setDisabled();
								$option->addMessage('warning', sprintf($this->lang['index']['options']['reasons']['addServiceOnOrder']['subserviceAlreadyImported'], $subserviceDetails['idServiceTina']));
								break;
							}
						}
					}
				}
				break;

			case 'importedServiceCashBulk': case 'assocImportDoc':
				try {
					$distributeImpDocsBulk = new \Modules\Documents\ImportedDocuments\BulkDistributeImportedDocs\ImportedServiceModel($selection);
					$distributeImpDocsBulk->isAvailable(false);
				} catch (\App\MessagesException $e) {
					$option->setDisabled();
					$option->setDescription($e->getMessagesCollector()->getMessageBulk());
				}
			break;

			default:
				return false;
		}

		return true;
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionGetEntityName()
	 */
	protected function optionGetEntityName($id)
	{
		$service = \Entity\ImportedService::select($id);
		return sprintf("%s/%s", $service->system->name, $service->idServiceExtSys);
	}

	protected function insert_getDefaultFormData($R)
	{
		return [
			'applyMode' =>		'merge',
		];
	}

	protected function insert_doInsert(\App\MessagesCollector $msgs, $idRecord, $applyMode)
	{
		// CHECK INPUTS AND GENERATE THE IMPORTED ORDER OBJECT ////////////////////////////////////

		$OK = true;

		$uploadedFile = new \App\Form\UploadedFiles\File('file');

		// check the file upload
		if (!$uploadedFile->hasValidFile()) {
			$msgs->addWarning($this->lang['insert']['msgs']['invalidFile']);
			$OK = false;
		}

		// checks if the file is XML
		if ($OK) {
			$fileXml = @simplexml_load_string($uploadedFile->getContents());
			if (!$fileXml) {
				$msgs->addWarning($this->lang['insert']['msgs']['invalidFileNotXml']);
				$OK = false;
			}
		}

		// gets the imported order object from the XML
		if ($OK) {

			try {

				if ($fileXml->getName()=='reservation') {
					$newOrderParser = new \App\ImportedOrder\Parser\Xml($fileXml, '1.0');
					$importedOrderObj = $newOrderParser->getImportedOrder();
				} elseif ($fileXml->getName()=='order') {
					$newOrderParser = new \App\ImportedOrder\Parser\Xml($fileXml, '2.0');
					$importedOrderObj = $newOrderParser->getImportedOrder();
				} else {
					$msgs->addWarning($this->lang['insert']['msgs']['invalidFileXmlBadStruct']);
					$OK = false;
				}

			} catch (\App\MessagesException $e) {
				$msgs->appendMessages($e->getMessagesCollector());
				$OK = false;
			}

		}

		// CHECK AND IMPORT THE ORDER /////////////////////////////////////////////////////////////
		if ($OK) {

			try {
				\DB::startTransaction();

				$importedOrderEnt = \Entity\ImportedOrder::insert();
				$importedOrderEnt->order = $importedOrderObj;
				$importedOrderEnt->applyMode = $applyMode;
				$importedOrderEnt->originalFilesContent = [['content'=>$fileXml->asXml(), 'name'=>'importedOrder.xml']];
				$importedOrderEnt->save();

				\DB::commitTransaction();

				$msgs->addSuccess(sprintf($this->lang['insert']['msgs']['saveOk'], $importedOrderEnt->getId()));

				return true;

			} catch (\App\Entity\Exception $e) {
				\DB::rollbackTransaction();
				$msgs->appendMessages($e->getMessagesCollector());
				return false;
			}
		}

		return false;
	}
}
