<?php
namespace App\Worldspan\StructureParser;

class Processor extends \App\Utils\BaseParser\Structure\StructureParser\Processor
{
	/**
	 * {@inheritDoc}
	 * @see \App\Utils\BaseParser\Structure\StructureParser\Processor::buildTransactionObj()
	 */
	protected function buildTransactionObj(?\App\Utils\BaseParser\Structure\StructureParser\Processor $processor=null, $transactionType=null, $transactionIndexes=null, $classType='Transaction')
	{
		if ($classType=='Transaction') {
			return new \App\Worldspan\StructureParser\Structures\Transaction($processor, $transactionType, $transactionIndexes);
		}
		elseif ($classType=='TransactionRefundDistribuited') {
			return new \App\Worldspan\StructureParser\Structures\TransactionRefundDistribuited($processor, $transactionType, $transactionIndexes);
		}
		else {
			throw new \Exception("Unknown class type used");
		}
	}

	protected function setupInternalAssociations($parsedStructure)
	{
		$internalAssociations = [];
		if ($parsedStructure['passenger']) {
			foreach ($parsedStructure['passenger'] as $paxIdx=>$pax) {
				if ($parsedStructure['segments']) {
					foreach ($parsedStructure['segments'] as $segIdx=>$seg) {
						$internalAssociations['segments->passenger'][$segIdx][]= $paxIdx;
						$internalAssociations['passenger->segments'][$paxIdx][]= $segIdx;
					}
				}

				if ($parsedStructure['EMD']) {
					foreach ($parsedStructure['EMD'] as $EIdx=>$E) {
						if ($pax['RA']['NameNumber']==$E['-E']['nameNumber']) {
							$internalAssociations['passenger->-E'][$paxIdx][]= $EIdx;
							$internalAssociations['-E->passenger'][$EIdx][]= $paxIdx;
						}
					}
				}

				if ($parsedStructure['MCO']) {
					foreach ($parsedStructure['MCO'] as $MCOIdx=>$MCO) {
						if ($pax['RA']['NameNumber']==$MCO['RO']['NameNumber']) {
							$internalAssociations['passenger->RO'][$paxIdx][]= $MCOIdx;
							$internalAssociations['RO->passenger'][$MCOIdx][]= $paxIdx;
						}
					}
				}
			}
		}

		$lastPricedPax = null;
		if ($parsedStructure['passenger']) {
			foreach (array_reverse($parsedStructure['passenger'], true) as $paxIdx=>$pax) {
				if ($pax['RG']) {
					$lastPricedPax = $paxIdx;
				}

				if ($lastPricedPax!==null) {
					$internalAssociations['passenger->passengerWithRG'][$paxIdx][]= $lastPricedPax;
					$internalAssociations['passengerWithRG->passenger'][$lastPricedPax][]= $paxIdx;
				}
			}
		}

		foreach ($internalAssociations as $k=>$v) {
			ksort($internalAssociations[$k]);
		}

		ksort($internalAssociations);
		return $internalAssociations;
	}

	protected function _getTransactions()
	{
		\Engine\Debug\ParserCallTrace\ParserCallTrace::getInstance()->logCallStart($this, __METHOD__, func_get_args());

		$transactions = [];

		$parsedStructure = 		$this->parsedStructure;
		$internalAssociations = $this->internalAssociations;

		$structureHandled = false;

		if ($parsedStructure['segments']) {
			// extract all ticketing segments
			$ticketingSegments = [];
			$nonTicketingSegments = [];
			foreach ($parsedStructure['segments'] as $segIdx=>$seg) {
				if ($seg['R01']) {
					$ticketingSegments[]= $segIdx;
				}
				else {
					$nonTicketingSegments[]= $segIdx;
				}
			}

			// handle ticketing operations separately from the others
			// loop through all accounting lines and generate ticketing operations
			if ($parsedStructure['passenger'] && $ticketingSegments) {
				foreach ($parsedStructure['passenger'] as $paxIdx=>$pax) {
					$structureHandled = false;
					if ($internalAssociations['passenger->segments'][$paxIdx]) {
						if ($parsedStructure['passenger'][$paxIdx]['RA']['DocumentNumber_']['docNumber']) {
							$loadPricesAsReissue = false;
							if (!$structureHandled && $parsedStructure['passenger'][$paxIdx]['RX']) {
								// handle reissue segments
								$transaction = $this->buildTransactionObj($this, "reissue", [
									'ticketingSegments' => 	$ticketingSegments,
									'paxIdx' => 			$paxIdx,
									'loadPricesAsReissue' => $loadPricesAsReissue,
								]);

								$transaction->setMessagesCollector(new \App\MessagesCollector());
								$structureHandled = true;
								$transactions[] = $transaction->getData();
							}

							if (!$structureHandled) {
								// handle ticketing segments
								$transaction = $this->buildTransactionObj($this, "ticketing", [
									'ticketingSegments' => 	$ticketingSegments,
									'paxIdx' => 			$paxIdx,
									'loadPricesAsReissue' => $loadPricesAsReissue,
								]);

								$transaction->setMessagesCollector(new \App\MessagesCollector());
								$structureHandled = true;
								$transactions[] = $transaction->getData();
							}
						}
					}
				}
			}
		}

		// MCO. These can come in the same file as ticketing operations
		foreach ($parsedStructure['MCO'] as $MCOIdx=>$X) {
			$transaction = $this->buildTransactionObj($this, "MCO", [
				'MCOIdx' =>		$MCOIdx,
				'paxIdx' =>		$internalAssociations['RO->passenger'][$MCOIdx][0],
			]);
			$transaction->setMessagesCollector(new \App\MessagesCollector());
			$structureHandled = true;
			$transactions[] = $transaction->getData();
		}

		if (!$structureHandled) {
			// no segments. It might be a void, or a refund... or an MCO, or an EMD
			if ($parsedStructure['passenger']) {
				foreach ($parsedStructure['passenger'] as $paxIdx=>$pax) {
					// EMD
					if ($internalAssociations['passenger->-E']) {
						foreach ($internalAssociations['passenger->-E'] as $paxIdx=>$EIdxs) {
							foreach ($EIdxs as $EIdx) {
								$transaction = $this->buildTransactionObj($this, "EMD", [
									'paxIdx' => 	$paxIdx,
									'EIdx' =>		$EIdx,
								]);
								$transaction->setMessagesCollector(new \App\MessagesCollector());
								$structureHandled = true;
								$transactions[] = $transaction->getData();
							}
						}
					}

					// VOID
					if ($pax['RA']['DocumentNumber_']['type']=='Void Document') {
						$transaction = $this->buildTransactionObj($this, "void", [
							'paxIdx' => 	$paxIdx,
						]);
						$transaction->setMessagesCollector(new \App\MessagesCollector());
						$structureHandled = true;
						$transactions[] = $transaction->getData();
					}

					// RFND
					if ($pax['RJ']) {
						list($structureHandled, $transactions) = $this->getTransactionFromRefundRaw($transactions, ['paxIdx' => 	$paxIdx,]);
					}
				}
			}
		}

		if (!$structureHandled) {
			// SPOIL
			if ($parsedStructure['-C']) {
				$transaction = $this->buildTransactionObj($this, "spoil", []);
				$transaction->setMessagesCollector(new \App\MessagesCollector());
				$structureHandled = true;
				$transactions[] = $transaction->getData();
			}
		}

		if (!$structureHandled) {
			throw new \App\Utils\BaseParser\TextParser\FileParser\Exception\UnhandledFileStructure("Don't know how to handle this file structure. Unknown file type");
		}

		\Engine\Debug\ParserCallTrace\ParserCallTrace::getInstance()->logOutput([
			'$transactions' => array_map(function($tr) {
				return sprintf("%s/%s", $tr->getType(), $tr->documents->docNumber);
			}, $transactions),
		]);

		// save the original components
		foreach ($transactions as $tr) {
			if ($tr->price) {
				$paxPrice = $tr->price;

				$paxPrice->originalPriceArr['supplier'] = 				$paxPrice->supplier;
				$paxPrice->originalPriceArr['supplierCurrency'] = 		$paxPrice->supplierCurrency;

				$paxPrice->originalPriceArr['tax'] = 					$paxPrice->tax->getAmount();
				$paxPrice->originalPriceArr['taxCurrency'] = 			$paxPrice->tax->getCurrency();

				$paxPrice->originalPriceArr['commission'] = 			$paxPrice->commission + $paxPrice->commissionVAT;
				$paxPrice->originalPriceArr['commissionCurrency'] = 	$paxPrice->commissionCurrency;
				$paxPrice->originalPriceArr['commissionComponents'] = 	array_map(function($c) {
					return [
						'IOSource' =>		'raw',			// technically we could add stuff from plugins in here when overriding amounts in IO, it's specific to IO
						'category' => 		$c->category,
						'source' => 		$c->source,
						'amount' => 		$c->amount,
						'VAT' => 			$c->VAT,
						'currency' => 		$c->currency,
						'code' => 			$c->code,
					];
				}, $paxPrice->components->getComponentsByCategory('commission'));
			}
		}

		\Engine\Plugins\Manager::getInstance()->executeEvent('Worldspan-getTransactions', ['this'=>$this, 'transactions'=>$transactions]);

		\Engine\Debug\ParserCallTrace\ParserCallTrace::getInstance()->logCallEnd();

		return array_values($transactions);
	}
}
