<?php
namespace App\Sabre\LineParser\Types\Line;

/**
 *
 * @author Lucian Sirbu
 */
class M2Var extends \App\Sabre\LineParser\Types\SabreBaseLine
{
	protected $extractRegexp = "/^(?P<rawData>.*)/s";

	/**
	 * The following are variable fields. These fields appear sequentially in the M2, and will contain a
	 * variable amount of data based on the number of items present in the various fields. Each item type is
	 * followed by a carriage return.
	 */

	/**
	 * Children elements
	 */
	protected $children = [
	    ['key'=>'IU2NM4',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2NM4'],    // M4 ENTITLEMENT ITEM NUMBERS
	    ['key'=>'IU2NM6',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2NM6'],    // M6 FARE CALCULATION ITEM NUMBERS
	    ['key'=>'IU2FOP',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2FOP'],    // FORM OF PAYMENT
	    ['key'=>'IU2ORG',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2ORG'],    // ORIGINAL ISSUE
	    ['key'=>'IU2IIE',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2IIE'],    // ISSUED IN EXCHANGE
	    ['key'=>'IU2END',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2END'],    // ENDORSEMENTS
	    ['key'=>'IU2JIC',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2JIC'],    // JOURNEY IDENTIFICATION CODE
	    ['key'=>'IU2NRT',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2NRT'],    // NET REMIT TICKETING
	    ['key'=>'IU2REA',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2REA'],    // REFUND AUTHORIZATION FOR ETR
	    ['key'=>'IU2DCD',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2DCD'],    // DISCOUNT CODE
	    ['key'=>'IU2SCN',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2SCN'],    // SCN for ATB

		// These fields will populate only when TJR indicator – INTERFACE CREDIT CARD HOLDER DATA SENT IN IUR M2 RECORD (W/CCIURM2‡*) is ON
	    #Array( 'key'=>'IU2CHN',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2CHN' ),    // Credit Card Holder Name
	    #Array( 'key'=>'IU2RM1',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2RM1' ),    // Credit Card Remark 1
	    #Array( 'key'=>'IU2RM2',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2RM2' ),    // Credit Card Remark 2
	    #Array( 'key'=>'IU2RM3',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2RM3' ),    // Credit Card Remark 3
	    #Array( 'key'=>'IU2EPT',    'type'=>'StringMultilineFixed', 'req'=>false,   'lines'=>1,     'label'=>'IU2EPT' ),    // Extended Payment
	];


	/**
	 * (non-PHPdoc)
	 * @see \App\Utils\BaseParser\TextParser\BlockAbstract::postExtract()
	 */
	protected function postExtract(\App\Utils\BaseParser\TextParser\ExtractedBlock $ret)
	{
		if ($ret->extractedData['IU2IIE']) {
			$children = [
		    	['key'=>'previous_airline',    'type'=>'StringRaw', 'req'=>true,   'len'=>3,],
		    	['key'=>'previous_ticket',     'type'=>'StringRaw', 'req'=>true,   'len'=>10,],
		    	['key'=>'unknown',            'type'=>'StringRaw', 'req'=>true,],
			];

			$ret2 = new \App\Utils\BaseParser\TextParser\ExtractedBlock();
			$ret->extractedData['IU2IIE'] = $this->_extract_children($ret2, $children, $ret->extractedData['IU2IIE'], [$this, "_extract_children_callback_associativeArray"])->extractedData;
		}

		if ($ret->extractedData['IU2END']) {
			$ret->extractedData['IU2END'] = array_filter(explode("/", $ret->extractedData['IU2END']));
		}

		if ($ret->extractedData['IU2ORG']) {
			$extracted = false;

			if (!$extracted) {
				$children = [
			    	['key'=>'original_airline',    'type'=>'StringRaw', 'req'=>true,   'len'=>3,],
			    	['key'=>'original_ticket',     'type'=>'StringRaw', 'req'=>true,   'len'=>10,],
					['key'=>'unknown01',           'type'=>'StringRaw', 'req'=>true,   'len'=>3,],
					['key'=>'original_ticketDate', 'type'=>'Date',      'req'=>true,   'len'=>5, 'fmt'=>'DDMMM', 'ref'=>'fileDate','onlyPast'=>true,],
					['key'=>'unknown',             'type'=>'StringRaw', 'req'=>true,],
				];

				$ret2 = new \App\Utils\BaseParser\TextParser\ExtractedBlock();

				try {
					$ret->extractedData['IU2ORG'] = $this->_extract_children($ret2, $children, $ret->extractedData['IU2ORG'], [$this, "_extract_children_callback_associativeArray"])->extractedData;
					$extracted = true;
				}
				catch (\App\Utils\BaseParser\TextParser\Exception\MissingRequiredElementException $ex) {
				}
			}

			if (!$extracted) {
				$children = [
					['key'=>'original_ticketDate', 'type'=>'Date',      'req'=>true,   'len'=>7, 'fmt'=>'DDMMMYY', 'ref'=>'fileDate','onlyPast'=>true,],
					['key'=>'unknown',             'type'=>'StringRaw', 'req'=>true,],
				];

				$ret2 = new \App\Utils\BaseParser\TextParser\ExtractedBlock();

				try {
					$ret->extractedData['IU2ORG'] = $this->_extract_children($ret2, $children, $ret->extractedData['IU2ORG'], [$this, "_extract_children_callback_associativeArray"])->extractedData;
					$extracted = true;
				}
				catch (\App\Utils\BaseParser\TextParser\Exception\MissingRequiredElementException $ex) {
				}
			}
		}

		if ($ret->extractedData['IU2IIE'] && $ret->extractedData['IU2ORG'] && is_array($ret->extractedData['IU2ORG'])) {
			if ($ret->extractedData['IU2IIE']['previous_ticket'] == $ret->extractedData['IU2ORG']['original_ticket']) {
				$ret->extractedData['IU2IIE']['previous_ticketDate'] = $ret->extractedData['IU2ORG']['original_ticketDate'];
			}
		}

		if ($ret->extractedData['IU2FOP']) {
			$ret->extractedData['IU2FOP_'] = $this->extractFOP($ret->extractedData['IU2FOP']);
		}

		if ($ret->extractedData['IU2NM4']) {
			$ret->extractedData['IU2NM4_'] = str_split(rtrim($ret->extractedData['IU2NM4']), 2);
		}

		return $ret;
	}

	/**
	 * Sabre-specific FOP extraction
	 * @param string $IU2FOP
	 */
	protected function extractFOP($IU2FOP)
	{
		$fopHelper = new \App\Utils\BaseParser\Utils\FormOfPaymentExtractor();
		$extractor = $this->getExtractor();

		$ret = [];

		/*
		 * Sabre's fop seem to look like:
		 * 	FOP1/amount1/FOP2/amount2 [space] old_FOP1_short_notation
		 * */
		$section = 'new';
		while ($IU2FOP) {
			$handled = false;

			// exotic FOP: EVV (Gift Voucher, used by SA/Kanoo)
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."EVV"
				."(\/(?P<amount>{$fopHelper->generateAmountRegexp()}))?"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 		$matches->getRawMatchedStrings(),
					'type' => 		'evv', 	'section' => $section,
					'amount' => 	$matches->getFloat('amount'),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// exotic FOP: AGT, used in conjunction with CC's, by SA/Kanoo
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."AGT (?!CC)"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 		$matches->getRawMatchedStrings(),
					'type' => 		'agency', 	'section' => $section,
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// exotic FOP: *, used in conjunction with CC's, by SA/Kanoo
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				.sprintf("\*(?=%s)", "CC|".$fopHelper->generateCCCompanyRegexp())
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 		$matches->getRawMatchedStrings(),
					'type' => 		'UATP', 	'section' => $section,
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// exotic FOP: GR (Goverment Request, used by SA/Fursan)
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."GR"
				."((\s|\/|@|)(?P<number>[0-9A-Z\s]+))?"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 		$matches->getRawMatchedStrings(),
					'type' => 		'government', 	'section' => $section,
					'number' => 	(trim(($matches->number??''))?:null),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// handle CC
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."(?P<pre3>CC[\s]*)?"
				."{$fopHelper->generateCCRegexp()}((\/|#){$fopHelper->generateCCExpiryDateRegexp()})?"
				."( TF[\s]+(?P<totalFare>{$fopHelper->generateAmountRegexp()})TAX[\s]+(?P<tax>{$fopHelper->generateAmountRegexp()}))?"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 		$matches->getRawMatchedStrings(),
					'type' => 		'CC', 	'section' => $section,
					'company' => 	$matches->ccCompany,
					'number' => 	$matches->ccNumber,
					'expiryDate' => ($matches->ccExpiryDate_Y && $matches->ccExpiryDate_m ? sprintf("%04d-%02d-01", 2000+$matches->ccExpiryDate_Y , $matches->ccExpiryDate_m):null),
					'totalFare' => 	$matches->getFloat('totalFare'),
					'tax' => 		$matches->getFloat('tax'),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// handle CC, for old tickets
			if (!$handled && $section=='old' && $matches = $extractor->findAndStore(sprintf("/^"
				."CC[\s]*"
				."((\/|#){$fopHelper->generateCCExpiryDateRegexp()})?"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 		$matches->getRawMatchedStrings(),
					'type' => 		'CC', 	'section' => $section,
					'expiryDate' => ($matches->ccExpiryDate_Y && $matches->ccExpiryDate_m ? sprintf("%04d-%02d-01", 2000+$matches->ccExpiryDate_Y , $matches->ccExpiryDate_m):null),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// handle cash
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."(?P<raw>{$fopHelper->generateCashRegexp('valid')})"
				."(\/(?P<amount>{$fopHelper->generateAmountRegexp()}))?"
				."( TF[\s]*(?P<totalFare>{$fopHelper->generateAmountRegexp()})TAX[\s]*(?P<tax>{$fopHelper->generateAmountRegexp()}))?"
				."(?=[^A-Z0-9]|$)"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 	$matches->getRawMatchedStrings(),
					'type' => 	'cash', 	'section' => $section,
					'amount' => 	$matches->getFloat('amount'),
					'totalFare' => 	$matches->getFloat('totalFare'),
					'tax' => 		$matches->getFloat('tax'),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// handle check
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."(?P<raw>{$fopHelper->generateCheckRegexp('valid')})"
				."(\/(?P<amount>{$fopHelper->generateAmountRegexp()}))?"
				."( TF[\s]*(?P<totalFare>{$fopHelper->generateAmountRegexp()})TAX[\s]*(?P<tax>{$fopHelper->generateAmountRegexp()}))?"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 	$matches->getRawMatchedStrings(),
					'type' => 	'check', 	'section' => $section,
					'amount' => 	$matches->getFloat('amount'),
					'totalFare' => 	$matches->getFloat('totalFare'),
					'tax' => 		$matches->getFloat('tax'),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// handle invoice
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."(?P<raw>{$fopHelper->generateInvoiceRegexp('valid')})"
				."(\/(?P<amount>{$fopHelper->generateAmountRegexp()}))?"
				."((\s|\/|@|)(?P<number>[0-9]+))?"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 	$matches->getRawMatchedStrings(),
					'type' => 	'invoice', 	'section' => $section,
					'number' => 	(trim(($matches->number??''))?:null),
					'amount' => 	$matches->getFloat('amount'),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}


			// misspellings
			// cash
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^"
				."(?P<raw>{$fopHelper->generateCashRegexp('invalid')})"
				."/"), $IU2FOP)) {
				$ret[]= [
					// 'raw' => 	$matches->getRawMatchedStrings(),
					'type' => 	'cash', 	'section' => $section,
					'amount' => 	$matches->getFloat('amount'),
					'totalFare' => 	$matches->getFloat('totalFare'),
					'tax' => 		$matches->getFloat('tax'),
				];

				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// separators
			// A/C is used by US/Downtown, doesn't seem to mean anything
			if (!$handled && $matches = $extractor->findAndStore(sprintf("/^(?P<pre1>(A\/C))/"), $IU2FOP)) {
				$handled = true;
				$IU2FOP = substr($IU2FOP, $matches->getMatchedLength());
			}

			// means 'another FOP'
			if (!$handled && $IU2FOP[0]=='/') {
				$IU2FOP = substr($IU2FOP, 1);	// ignore / characters at the beginning, they usually separate form of payments
				$handled = true;
			}

			// '/' handles new->old FOP boundary
			if (!$handled && $IU2FOP[0]==' ') {
				$IU2FOP = substr($IU2FOP, 1);	// ignore ' ' characters at the beginning, they usually separate nwe/old sections
				$handled = true;
				$section = 'old';
			}

			// line not handled
// 			if (!$handled) {
//				// stop with error
// 				throw new \Exception("Unknown form of payment: '{$IU2FOP}'");
// 			}

// 			if (!$handled) {
//				// return what we have until now
// 				return $ret;
// 			}


// 			if (!$handled) {
// 				// unknwon form of payment, mark the rest of the list as "unknown"
// 				$ret[]= [
// 					'type' => 'unknown', 	'section' => $section,
// 					'raw' => [
// 						$IU2FOP
// 					],
// 				];
// 				$handled = true;
// 				$IU2FOP = '';
// 			}

			if (!$handled) {
				// unknwon form of payment, try to ignore unknown sections and parse only known sections

				$lastFopIndex = count($ret)-1;
				if ($ret[$lastFopIndex]['type']=='unknown') {
					$ret[$lastFopIndex]['raw'].= $IU2FOP[0];
				}
				else {
					$lastFopIndex++;
					$ret[$lastFopIndex]= [
						'type' => 'unknown', 	'section' => $section,
					];
					$ret[$lastFopIndex]['raw'] = $IU2FOP[0];
				}

				$handled = true;
				$IU2FOP = substr($IU2FOP, 1);
			}

		}

		return $ret;
	}
}
