<?php
namespace Modules\Orders\Amadeus\FluX;

class Controller extends \ModulesAbstract\FluxRest\ControllerUploaderAutoSaveFile
{
	/**
	 * (non-PHPdoc)
	 * @see \ModulesAbstract\FluxRest\ControllerAbstract::getBasePath()
	 */
	protected function getBasePath()
	{
		global $CFG;
		return $CFG['paths']['amadeus'];
	}

	/**
	 * (non-PHPdoc)
	 * @see \ModulesAbstract\FluxRest\ControllerAbstract::validateFluXSystem()
	 */
	protected function validateFluXSystem(\Entity\FluxInstance $fluxInstance)
	{
		return ($fluxInstance->assignedSystem=='amadeus');
	}

	/**
	 * {@inheritDoc}
	 * @see \ModulesAbstract\FluxRest\ControllerAbstract::handleSystemHealth()
	 */
	protected function handleSystemHealth($request, \ModulesAbstract\FluxRest\Response\Main $mainResponse, \Entity\FluxInstance $fluxInstance)
	{
		parent::handleSystemHealth($request, $mainResponse, $fluxInstance);

		if (!$mainResponse->hasOperation('Wait')) {
			// fmt: 'onSystemLoad:wait,onCronjobs:wait,onTablesBusy:wait'/
			$behaviourOnSystemLoad = [];
			foreach (explode(",", $fluxInstance->behaviourOnSystemLoad) as $behaviour) {
				list($k, $v) = explode(":", $behaviour);
				$behaviourOnSystemLoad[$k] = $v;
			}

			// check sensitive cronjobs, wait accordingly
			global $DBTImportedOrders_services, $DBTImportedOrders_tickets, $DBTImportedOrders_orders, $DBTAmadeusParsedFiles, $DBTAmadeusServices;

			$openTables = \DB::getOpenTables();
			$busyTables = array_intersect([$DBTImportedOrders_services, $DBTImportedOrders_tickets, $DBTImportedOrders_orders, $DBTAmadeusParsedFiles, $DBTAmadeusServices, ], $openTables);
			if ($busyTables) {
				$op = new \ModulesAbstract\FluxRest\Response\Operation\NotifyUserLog();
				$op->text = sprintf('Server busy, some database tables are in use (%s)', implode(", ", $busyTables));
				$mainResponse->appendOperation($op);

				$op = new \ModulesAbstract\FluxRest\Response\Operation\Wait();
				$op->timeout = count($busyTables)*2.5;	// sleep longer the more tables are in use
				$mainResponse->appendOperation($op);

				if ($behaviourOnSystemLoad['onTablesBusy']=='wait') {
	 				// stop here, do not parse the file
	 				throw new \Exception\IO\Base("System busy");	// text message isn't actually displayed anywhere
	 			}
	 			// else $behaviourOnSystemLoad['onTablesBusy']=='slowdown'
			}
		}
	}

	/**
	 * (non-PHPdoc)
	 * @see \ModulesAbstract\FluxRest\ControllerUploaderAutoSaveFile::parseFileOnDisk()
	 */
	protected function parseFileOnDisk($path, $originalFilename, \Entity\FluxInstance $fluxInstance, $rawRequest)
	{
		\DB::startTransaction();
		$transactionTimings = [
			'start' => null,
			'FileParser' => null,
			'Storage' => null,
			'CompatibilityWithImportedOrders' => null,
			'commit' => null,
		];
		try {
			// case encountered for SA/Zahid, on an IMR with 62 services, @see 201909/20190916 094354 18 05.FluX.AIRDC07739.AIR
			set_time_limit(600);

			$transactionTimings['start'] = microtime(true);
			// parse the file
			$parser = new \App\Amadeus\FileParser\ParsedFile($path);
			$parser->parse();

			// if we're still running, all went ok
			$parser->getStructure()->getStructure();
			$parser->getStats();

			$transactionTimings['FileParser'] = microtime(true);

			// use the processor to process the raw data
			$structureParser = new \App\Amadeus\StructureParser\Processor();
			$structureParser->setFile($path);
			$structureParser->setParser($parser);

			// store the parsed data
			$storage = new \App\Amadeus\Storage\StorageHandler();
			$storage->setProcessor($structureParser);
			$storage->setOption('source', 'FluX');
			$storage->setOption('IP', ($_SERVER['REMOTE_ADDR']?:''));

			$ret = $storage->execute();

			$transactionTimings['Storage'] = microtime(true);

			// determine what entities were inserted, reselect from DB, and insert them into ImportedOrders
			if ($ret) {
				$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();
				$convertor = new $CFG['amadeus']['CompatibilityWithImportedOrders']['Processor']['class']([]);
				$convertor->importFromStorageResult($ret);

				$order = $convertor->getConvertedOrder();

				$orders = $convertor->splitOrderIfNeeded($order);
				$insertedOrderIds = [];
				foreach ($orders as $order) {
					$orderInsert = \Entity\ImportedOrder::insert();
					$orderInsert->order = $order;

					$orderInsert->originalFilesWithPath = [$this->getFilePathRelativeToFilesRoot($path)];
					$orderInsert->save();
					$insertedOrderIds[]= $orderInsert->getId();
				}

				// collect a list of affected files, and update their `idImportedOrders` field with the current $insertedOrderId
				//  #1: collect affected entities, group them by idFile. I'd expect that only one file gets filled in here, but one never knows
				$affectedFiles = [];
				foreach ($convertor->getServices() as $ent) {
					$affectedFiles[$ent->idFile] = $ent->file;
				}

				//  #2: update their corresponding field
				foreach ($affectedFiles as $file) {
					$fileUpd = \Entity\AmadeusFile::update($file->getId());
					$idImportedOrders = $file->idImportedOrders;
					foreach ($insertedOrderIds as $insertedOrderId) {
						$idImportedOrders[] = $insertedOrderId;
					}
					$fileUpd->idImportedOrders = $idImportedOrders;
					$fileUpd->save();
				}

				$transactionTimings['CompatibilityWithImportedOrders'] = microtime(true);
			}

			$parser->destroyCCInformation();

			\DB::commitTransaction();
			$transactionTimings['commit'] = microtime(true);

			$this->queueSessionData[__FUNCTION__] = $transactionTimings;
		}
		catch(\Exception $ex) {
			\DB::rollbackTransaction();
			\App\Logger\FluxInstance::getInstance()->warning(sprintf("[%s] %s: %s", __METHOD__, get_class($ex), $ex->getMessage()), [
				'file' => new \Engine\Logger\Context\File([
					'name'=> $originalFilename,
					'content' => \Engine\File::getContents($path),
				]),
				'exception' => new \Engine\Logger\Context\ExceptionAsHtml($ex),
				'fluxInstance' => $fluxInstance,
			]);

			$hiddenExceptions = [
				'App\Amadeus\FileParser\ParserException',
				'App\Amadeus\StructureParser\StructureException',
				'App\Amadeus\Storage\Exception',
				'App\Amadeus\Storage\DuplicateTicketException',
				'App\Amadeus\Exception',
				'App\Utils\BaseParser\Structure\StructureParser\Types\Exception\Exception',	// price converter exception
			];

			if (in_array(get_class($ex), $hiddenExceptions)) {
				throw new \ModulesAbstract\FluxRest\ExceptionInvalidFile(sprintf("Invalid file %s. Error: %s", $originalFilename, $ex->getMessage()), null, $ex);
			}
			else {
				// throw new \Exception(null, null, $ex);	// this will re-thow ith stacktrace, but as a base exception
				throw $ex;	// re-throw
			}
		}
	}
}
