<?php
namespace App\Sabre\StructureParser\Structures\Hotel;

class Price extends \App\Sabre\StructureParser\Structures\Base\Price
{
	protected function _getData()
	{
		list(, , $transactionIndexes, ) = $this->getTransactionDetails();

		$ret = null;
		if (in_array($transactionIndexes['source'], ['M3Hhl', 'M3Oths:HHL, M5->M3, M5->M1', 'M3Oths:HHL, M5->M3', ])) {
			$ret = $this->_getData_M3Hhl();
		}
		elseif (in_array($transactionIndexes['source'], ['M3Oths:HHT', 'M3Oths:HHT, M5->M3', 'M3Oths:HHT, M5->M3, M5->M1',])) {
			$ret = $this->_getData_M3Oths_HHL();
		}
		elseif (in_array($transactionIndexes['source'], ['M3Oths:HHX', 'M3Oths:HHX, M5->M3', 'M3Oths:HHX, M5->M3, M5->M1', ])) {
			$ret = $this->_getData_M3Oths_HHX();
		}
		else {
			throw new \Exception(sprintf("Don't know how to interpret source '%s'", $transactionIndexes['source']));
		}

		// DEBUG: enable these
		// echo "<div style='font-size: 1.5em; padding-top: 0.5em;'>{$this->transaction->getType()}, {$transactionIndexes['source']}</div>";
		// echo $ret->componentsDebug();
		// echo "</div>";

		return $ret;
	}

	private function _getData_M3Hhl()
	{
		list($parsedStructure, $transactionType, $transactionIndexes, $internalAssociations) = $this->getTransactionDetails();

		$item = new \App\Sabre\StructureParser\Types\Price();

		$loaded = false;

		list($_, $_, $M5s, $_, $M2, $_, $_, $_) = $this->determineM5M2($parsedStructure, $transactionType, $transactionIndexes, $internalAssociations);

		$M3 = $parsedStructure['M3'][$transactionIndexes['km3']];

		if (!$loaded && $M5s) {
			$loaded = $this->loadPricesFromM5($parsedStructure, $M5s, $M2, $M3, $item);
		}

		if (!$loaded && $M3['M3Hhl']['HTP']['approximateTotalPrice']) {
			$item->componentSet(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'supplier',
				'M3Hhl:HTP:approximateTotalPrice',
				$M3['M3Hhl']['HTP']['approximateTotalPrice'],
				null,
				$M3['M3Hhl']['HTP']['approximateTotalPriceCurrency']
			));
		}
		elseif (!$loaded && $M3['M3Hhl']['roomRate']['roomRate']) {
			$item->componentSet(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'supplier',
				'M3Hhl:roomRate*IU3OUT_',
				$M3['M3Hhl']['roomRate']['roomRate'] * $M3['M3Hhl']['IU3OUT_'],
				null,
				$M3['M3Hhl']['roomRate']['roomRateCurrency']
			));
		}
		else {
			$this->transaction->getMessagesCollector()->addWarning(sprintf("[%s] No price could be determined for this hotel. Please investigate this case", __METHOD__)); // TODO: [cleanMsgs-transactionGDSs] refactor this from GDSs
		}


		if (!$loaded && $M3['M3Hhl']['TTX']['TTX']) {
			$item->componentAdd(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'supplier',
				'M3Hhl:TTX',
				-1 * $M3['M3Hhl']['TTX']['TTX'],
				null,
				$item->supplierCurrency
			));

			$item->tax->add(new \App\Sabre\StructureParser\Types\PriceTaxComponent('TTX', $M3['M3Hhl']['TTX']['TTX'], $item->supplierCurrency));
		}

		if (!$loaded && $M3['M3Hhl']['TAC']['type_']=='percent') {
			$v = $this->floorToPrecision($item->supplier * $M3['M3Hhl']['TAC']['value_'] / 100, 2);

			$item->componentAdd(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'supplier',
				'M3Hhl:TAC',
				-1 * $v,
				null,
				$item->supplierCurrency
			));

			$item->componentSet(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'commission',
				'M3Hhl:TAC',
				$v,
				null,
				$item->supplierCurrency
			));
		}

		$item->componentSet(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
			'total',
			'sum',
			$item->supplier + $item->commission + $item->tax->amount,
			null,
			$item->supplierCurrency
		));

		// At this moment, I've only seen CC payments in this tag, so I'm not sure what other data can come here
		// this comment is also in App\Sabre\LineParser\Types\Line\M3Hhl.php
		if ($M3['M3Hhl']['G_']['type']=='CC') {
			$component = new \App\Sabre\StructureParser\Types\PriceFormOfPaymentComponent();
			$component->type = 'CC';
			$component->ccCompanyIndicator = $M3['M3Hhl']['G_']['companyIndicator'];
			$component->ccNumber = $M3['M3Hhl']['G_']['number'];
			$component->setCcExpiryDate($M3['M3Hhl']['G_']['expiryDate']);
			$item->formOfPayment->append($component);
		}

		$item = $this->internal_extract_serviceFee($item);
		$item = $this->internal_extract_discount($item);

		if (in_array(\App\Sabre\Config::getInstance()->get("importCommissionForService"), ['all', ])) {
			$item = $this->internal_extract_commission($item, [], []);
		}

		return $item;
	}

	private function _getData_M3Oths_HHL()
	{
		list($parsedStructure, $transactionType, $transactionIndexes, $internalAssociations) = $this->getTransactionDetails();

		$item = new \App\Sabre\StructureParser\Types\Price();

		$loaded = false;

		$M3 = $parsedStructure['M3'][$transactionIndexes['km3']];
		$processedRemarks = $this->transaction->remarks->getProcessedRemarks();

		if (!$loaded && $processedRemarks['TOTAL_CURRENCY'] && $processedRemarks['SUPPLIER_CURRENCY'] && $processedRemarks['TAX_CURRENCY']) {
			$item = $this->internal_extract_supplierPriceAndTax($item);
			$loaded = true;
		}

		if (!$loaded) {
			list($_, $_, $M5s, $km5s, $M2, $km2, $MAs, $kmas) = $this->determineM5M2($parsedStructure, $transactionType, $transactionIndexes, $internalAssociations);

			if ($M5s) {
				$currency = $this->determineCurrency($parsedStructure, $M5s, $M2, [], [$M3, ]);
				$item = $this->determineFormOfPayments($item, $M5s, null, [], $currency);
				$loaded = $this->loadPricesFromM5($parsedStructure, $M5s, $M2, $M3, $item);
			}
		}

		if (!$loaded && $M3['M3Oths']['IU3VR4_']['roomRate']) {
			$ddiff = new \App\Utils\BaseParser\Utils\DateDiff($this->transaction->itinerary->getDeparture()->date, $this->transaction->itinerary->getDestination()->date);
			$item->componentAddAndUpdateTotal(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'supplier',
				'M3Oths:IU3VR4_:roomRate',
				$M3['M3Oths']['IU3VR4_']['roomRate']['amount']*$ddiff->asNights(),
				null,
				$M3['M3Oths']['IU3VR4_']['roomRate']['currency']
			));

			$loaded = true;
		}

		$item = $this->internal_extract_serviceFee($item);
		$item = $this->internal_extract_discount($item);
		if (in_array(\App\Sabre\Config::getInstance()->get("importCommissionForService"), ['all', ])) {
			$item = $this->internal_extract_commission($item, $M5s, $M2);
		}

		$item->roundValues();

		if (!$loaded) {
			$this->transaction->getMessagesCollector()->addWarning(sprintf("[%s] No price could be determined for this hotel. Please investigate this case", __METHOD__)); // TODO: [cleanMsgs-transactionGDSs] refactor this from GDSs
		}

		return $item;
	}


	private function _getData_M3Oths_HHX()
	{
		list($parsedStructure, $transactionType, $transactionIndexes, $internalAssociations) = $this->getTransactionDetails();

		$item = new \App\Sabre\StructureParser\Types\Price();

		$loaded = false;

		list($_, $_, $M5s, $_, $M2, $_, $_, $_) = $this->determineM5M2($parsedStructure, $transactionType, $transactionIndexes, $internalAssociations);

		$M3 = $parsedStructure['M3'][$transactionIndexes['km3']];
		$processedRemarks = $this->transaction->remarks->getProcessedRemarks();

		if (!$loaded && $processedRemarks['TOTAL_CURRENCY'] && $processedRemarks['SUPPLIER_CURRENCY'] && $processedRemarks['TAX_CURRENCY']) {
			$item = $this->internal_extract_supplierPriceAndTax($item);
			$loaded = true;
		}

		if (!$loaded && $M5s) {
			$loaded = $this->loadPricesFromM5($parsedStructure, $M5s, $M2, $M3, $item);
		}

		if (!$loaded and $M3['M3Oths']['IU3VR4_']['RR']) {
			$loaded = true;
			$item->componentSetAndUpdateTotal(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'supplier',
				'M3Oths:IU3VR4_:RR',
				$M3['M3Oths']['IU3VR4_']['RR']['amount']*$M3['M3Oths']['IU3VR4_']['NT_']['duration'],
				null,
				$M3['M3Oths']['IU3VR4_']['RR']['currency']
			));

			$item->tax->append(new \App\Sabre\StructureParser\Types\PriceTaxComponent('TX1',
				$M3['M3Oths']['IU3VR4_']['TX1']['amount'],
				$item->supplierCurrency
			));

			if ($M3['M3Oths']['IU3VR4_']['TAC']['type_']=='percent') {
				$v = $this->roundToPrecision($item->supplier * $M3['M3Oths']['IU3VR4_']['TAC']['value_'] / 100, 2);
				$item->componentAdd(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
					'commission',
					'IU3VR4:TAC:percent',
					$v,
					null,
					$item->supplierCurrency
				));
				$item->componentAdd(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(	// TAC is included in the supplier price, substract it now
					'supplier',
					'IU3VR4:TAC:percent',
					-1 * $v,
					null,
					$item->supplierCurrency
				));
			}
			else {
				$v = $M3['M3Oths']['IU3VR4_']['TAC']['value_'];
				$item->componentAdd(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
					'commission',
					'IU3VR4:TAC:amount',
					$v,
					null,
					$item->supplierCurrency
				));
				$item->componentAdd(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(	// TAC is included in the supplier price, substract it now
					'supplier',
					'IU3VR4:TAC:amount',
					-1 * $v,
					null,
					$item->supplierCurrency
				));
			}

			$item->recalculateTotal();
		}

		$item = $this->internal_extract_serviceFee($item);
		$item = $this->internal_extract_discount($item);
		if (in_array(\App\Sabre\Config::getInstance()->get("importCommissionForService"), ['all', ])) {
			$item = $this->internal_extract_commission($item, [], []);
		}

		if ($transactionIndexes['km5s']) {
			$M5s = array_map(function($km5) use ($parsedStructure) {
				return $parsedStructure['M5'][$km5];
			}, $transactionIndexes['km5s']);
			$currency = $this->determineCurrency($parsedStructure, $M5s, null, [], [$M3, ]);
			$item = $this->determineFormOfPayments($item, $M5s, null, [], $currency);
		}

		if (!$loaded) {
			$this->transaction->getMessagesCollector()->addWarning(sprintf("[%s] No price could be determined for this hotel. Please investigate this case", __METHOD__)); // TODO: [cleanMsgs-transactionGDSs] refactor this from GDSs
		}

		return $item;
	}

	/**
	 * Load price information from M5 segments
	 * 
	 * @param array $parsedStructure The parsed structure containing all segments
	 * @param array $M5s Array of M5 segments
	 * @param array|null $M2 M2 segment data
	 * @param array|null $M3 M3 segment data
	 * @param \App\Sabre\StructureParser\Types\Price $item The price item to update
	 * @return bool True if prices were loaded, false otherwise
	 */
	private function loadPricesFromM5(array $parsedStructure, array $M5s, $M2, $M3, \App\Sabre\StructureParser\Types\Price $item)
	{
		$currency = $this->determineCurrency($parsedStructure, $M5s, $M2, [], [$M3]);

		$totalPassengers = count($this->transaction->passengers->passengers);

		// handle supplier price
		$supplierAmount = array_sum(array_map(function($M5) use ($totalPassengers) {
			$amount = $M5['baseFareAmount'] - $M5['commissionValue_'];
			if ($M5['priceType']=='PER') {
				return $totalPassengers * $amount;
			}
			return $amount;
		}, $M5s));
		$item->componentAddAndUpdateTotal(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
			'supplier',
			'M5:baseFareAmount-commissionValue_',
			$supplierAmount,
			null,
			$currency
		));

		// taxes
		$tax1Amount = array_sum(array_map(function($M5) use ($totalPassengers) {
			$amount = $M5['tax1Amount'];
			if ($M5['priceType']=='PER') {
				return $totalPassengers * $amount;
			}
			return $amount;
		}, $M5s));
		$item->tax->add(new \App\Sabre\StructureParser\Types\PriceTaxComponent(
			'tax1Amount',
			$tax1Amount,
			$currency
		));
		$item->addToTotal($tax1Amount, $currency, $this->transaction);

		// handle commission
		$commissionValue = array_sum(array_map(function($M5) use ($totalPassengers) {
			$amount = $M5['commissionValue_'];
			if ($M5['priceType']=='PER') {
				return $totalPassengers * $amount;
			}

			return $amount;
		}, $M5s));
		if ($commissionValue) {
			$item->componentAddAndUpdateTotal(new \App\Utils\BaseParser\Structure\StructureParser\Types\PriceComponent(
				'commission',
				'M5:commissionValue_',
				$commissionValue,
				null,
				$currency
			));
		}

		return true;
	}

}
