<?php
namespace App\Amadeus\FileParser;

abstract class LineStaticCalls
{
	// @see http://www.airliners.net/aviation-forums/general_aviation/read.main/2062549/
	// @see http://www.amadeus.com/web/binaries/blobs/792/567/Amadeus%20Groups%20manual_v1,0.pdf, page 14
	// @see http://training.amadeusschweiz.com/en/documentation/usermanuals.html?file=assets/theme/content/docs/en/usermanuals/Amadeus_Passenger_Name_Record.pdf
	// @see http://www.airliners.net/forum/viewtopic.php?t=324595
	/**
	 * Used by U & H lines
	 * @var array
	 */
	static protected $STATUS = [
		"HK" => "Held Confirmed",
		"OK" => "OK",
		"SS" => "Seat Saved",
		"RQ" => "Waitlisted",
		"NN" => "Need/Need",
		"CV" => "Checked In/Virtual",
		"GK" => "Ghost(hold confirmed/booking beyond system range)",
		"GN" => "Ghost(holding need)",
		"GL" => "Ghost(waitlisted)",
		"PK" => "Passive(confirmed)",
		"PL" => "Passive(waitlisted)",
	];



	/**
	 * Converts from an Amadeus-style date to a mysql-style date
	 * @param String $dateStr
	 * @param String $format
	 * @return String
	 */
	public static function extractDate($dateStr, $format, $options = [])
	{
		$monthsAssoc = [
			"JAN"=>'01', "FEB"=>'02', "MAR"=>'03',
			"APR"=>'04', "MAY"=>'05', "JUN"=>'06',
			"JUL"=>'07', "AUG"=>'08', "SEP"=>'09',
			"OCT"=>'10', "NOV"=>'11', "DEC"=>'12',
		];

		// the constans here are used as an optimization
		$Y = TODAY_YEAR;
		$M = TODAY_MONTH;
		$d = TODAY_DAY;

		if ($options['referenceDate']??false) {
			$Y = (int)substr($options['referenceDate'], 0, 4);
			$M = (int)substr($options['referenceDate'], 5, 2);
			$d = (int)substr($options['referenceDate'], 8, 2);
		}

		if(!$dateStr){
			throw \App\Amadeus\FileParser\ParserException::internal("Function called without an actual date element");
		}

		switch ($format) {
			case 'YYYY-MM-DD':
				$return = substr($dateStr, 0, 4).'-'.substr($dateStr, 5, 2).'-'.substr($dateStr, 8, 2);
			break;

			case "YYMMDD":
				$return = "20".substr($dateStr, 0, 2).'-'.substr($dateStr, 2, 2).'-'.substr($dateStr, 4, 2);
			break;
			case "DDMMYY":
				$return = "20".substr($dateStr, 4, 2).'-'.substr($dateStr, 2, 2).'-'.substr($dateStr, 0, 2);
			break;

			case "DDMMMYY":
				$return = "20".substr($dateStr, 5, 2).'-'.($monthsAssoc[substr($dateStr, 2, 3)]??'???').'-'.substr($dateStr, 0, 2);
			break;

			case "YYYYMMDD":
				$return = substr($dateStr, 0, 4).'-'.substr($dateStr, 4, 2).'-'.substr($dateStr, 6, 2);
			break;

			case "DDMMMYYYY":
				$return = substr($dateStr, 5, 4).'-'.($monthsAssoc[substr($dateStr, 2, 3)]??'???').'-'.substr($dateStr, 0, 2);
			break;

			case "DDMMYYYY":
				$return = substr($dateStr, 4, 4).'-'.substr($dateStr, 2, 2).'-'.substr($dateStr, 0, 2);
			break;

			case "DDMMM":
				$return = $Y.'-'.($monthsAssoc[substr($dateStr,2,3)]??'???').'-'.substr($dateStr,0,2);
			break;

			case "DDMMM,DDMMMYYYY":
				if (strlen($dateStr)==9) {
					$return = substr($dateStr,5,4).'-'.($monthsAssoc[substr($dateStr,2,3)]??'???').'-'.substr($dateStr,0,2);
				}
				else {
					$return = $Y.'-'.($monthsAssoc[substr($dateStr,2,3)]??'???').'-'.substr($dateStr,0,2);
				}
			break;

			case "MMYY":	// used in the FP line
				$return = sprintf("20%02d-%02d-%02d", substr($dateStr, 2, 2), substr($dateStr, 0, 2), 1);
			break;

			case "DD.MM.YY":
				$return = "20".substr($dateStr, 6, 2).'-'.substr($dateStr, 3, 2).'-'.substr($dateStr, 0, 2);
			break;
			case "DD.MM.YYYY":
				$return = substr($dateStr, 6, 4).'-'.substr($dateStr, 3, 2).'-'.substr($dateStr, 0, 2);
			break;

			default:
				throw \App\Amadeus\FileParser\ParserException::internal("Unknown date format requested: {$format}");
			break;
		}

		// validate the return date
		#$dt = strtotime($return);
		#if(!$dt) $return = '';

		// slightly faster version
		if(!preg_match("/([0-9]{4})-([0-9]{2})-([0-9]{2})/", $return)) $return = '';

		if($return && ($options['onlyPast']??false)){
			while ($return>TODAY_ISO) {
				$dt = \Engine\DateTime::createFromIsoDate($return);
				$return = $dt->sub(new \DateInterval("P100Y"))->formatDateIso();
			}
		}

		return $return;
	}


	/**
	 * Extract the hour from an Amadeus-style hour string
	 * @param string $hourStr
	 * @param string $format
	 * @return string
	 */
	public static function extractHour($hourStr, $format = 'auto')
	{
		$hourStr = (string)$hourStr;
		$return  = '';
		switch($format){
			case 'hh.mm':
			case 'hh:mm':
				$h = substr($hourStr, 0, 2);
				$m = substr($hourStr, 3, 5);
				$s = '00';	// seconds, always 0, because Amadeus doesn't send them
				$return = sprintf("%02d:%02d:%02d", $h, $m, $s);
			break;

			case 'hhmm':
				$h = substr($hourStr, 0, 2);
				$m = substr($hourStr, 2, 3);
				$s = '00';	// seconds, always 0, because Amadeus doesn't send them
				$return = sprintf("%02d:%02d:%02d", $h, $m, $s);
				break;

			case 'auto':
				$h = substr($hourStr, 0, 2);
				$m = substr($hourStr, 2, 2);
				$s = '00';	// seconds, always 0, because Amadeus doesn't send them

				switch(strlen($hourStr)){
					case 5:
						$t_o_day = substr($hourStr, 4, 1);
						switch($t_o_day){
							case 'A':
								$return = sprintf("%02d:%02d:%02d", ($h==12?0:$h), $m, $s);
							break;

							case 'P':
								$return = sprintf("%02d:%02d:%02d", ($h<12?$h+12:$h), $m, $s);
							break;

							case 'N':
								if ("{$h}:{$m}:{$s}" == '12:00:00') {
									$return = sprintf("12:00:00");
								}
								else {
									throw \App\Amadeus\FileParser\ParserException::internal("Date has an unknown time-of-day '{$t_o_day}' with value '{$hourStr}'");
								}
							break;

							case 'M':
								if ("{$h}:{$m}:{$s}" == '12:00:00') {
									$return = sprintf("00:00:00");
								}
								else {
									throw \App\Amadeus\FileParser\ParserException::internal("Date has an unknown time-of-day '{$t_o_day}' with value '{$hourStr}'");
								}
							break;

							default:
								throw \App\Amadeus\FileParser\ParserException::internal("Date has an unknown time-of-day '{$t_o_day}' in '{$hourStr}'");
						}

						break;

					case 4:
						$return = sprintf("%02d:%02d:%02d", $h, $m, $s);
					break;

					case 0:
					default:
						$return = '';
					break;
				}
			break;

			default:
				throw \App\Amadeus\FileParser\ParserException::internal("Unknown hour format specified: '{$format}', hour: '{$hourStr}'");
			break;
		}

		return $return;
	}

	/**
	 * Given a list of hour formats, try to extract anything that matches
	 * @param string $hourStr
	 * @param array $formats
	 * @return string|null
	 */
	public static function extractHourFromFormats($hourStr, $formats = ['auto'])
	{
		foreach($formats as $format){
			$return = self::extractHour($hourStr, $format);
			if($return){
				return $return;
			}
		}

		return null;
	}

	/**
	 * Expand a string containing a list of conjunction tickets to an array
	 * @param string $tktNo
	 * @return multitype:string unknown
	 */
	public static function conjunctionTktToArr($tktNo)
	{
		$ret = [];
		$m = [];
		preg_match("/(?P<tktNo>[0-9]{10})(-(?P<tktNo_cnj>[0-9]{2}))?/", $tktNo, $m);

		if ($m['tktNo']??false) {
			if ($m['tktNo_cnj']??false) {
				$base = substr($m['tktNo'], 0, -strlen($m['tktNo_cnj']));
				$bs = 	substr($m['tktNo'], -strlen($m['tktNo_cnj']));
				$be = 	$m['tktNo_cnj'];

				$start = $base.$bs;
				$end = 	 $base.$be;

				// handle the case where start=99 and end=01...
				if($end<$start){
					$end+=100;
				}

				// loop between all records and add them to the array
				for($i=$start; $i<=$end; $i++){
					$ret[] = (string)$i;
				}
			}else{
				$ret[] = $m['tktNo'];
			}
		}

		return $ret;
	}


	/**
	 * PSGRNME_title
	 * MR/MRS/MS/ADT/CHD/INF/INS
	 */
	protected static $PSGRNME_title = [
		'MR' => 	'Mr',
		'MRS' => 	'Mrs',
		'MS' => 	'Ms',
		'MSTR' => 	'Mstr',
		'MISS' => 	'Miss',
	];

	protected static $PSGRNME_honorifics = [
		'PROF DR' =>'Prof Dr',
		'DR' => 	'Dr',
	];

	/**
	 * PSGRID translations
	 * @see http://www.sca.amadeus.com/apps/web/zone/OurOffering.nsf/4dc8501b274ac564c125738400461900/524666283e0b5967c12573df00527ede/$FILE/Amadeus%20All%20Fares%20-%20User%20Guide%20v6.1.pdf for details
	 * @see http://testws.galileo.com/gwssample/help/gwshelp/mergedprojects/xmlselectmainhelp/codes/passenger_type_codes_(ptc).htm
	 * @var array
	 */
	protected static $PSGRID = [
		 // commented out because of TD-4592: Ignore the contact details when importing tickets for infants and do not load their personal details to the adults as well [A]
		 // basically MIS was never encountered and it led to one test failing because if extracted MIS from the pax name
// 		'MIS' => Array( 'label' => 'Missionary',                                         'type'=>'adult', ),     // Missionary

		// commented out because of TD-6414: Midlle name of the passenger interpreted as PTC, for Amadeus file #39420
// 		'ANN' => Array( 'label' => 'Age Restricted Companion',                           'type'=>'adult', ),     // Age Restricted Companion
// 		'EMI' => Array( 'label' => 'Emigrant',                                           'type'=>'adult', ),     // Emigrant

		'ACC' => ['label' => 'Accompanied Passenger',                              'type'=>'adult',],     // Accompanied Passenger
		'ADT' => ['label' => 'Adult',                                              'type'=>'adult',],     // Adult
		'AGT' => ['label' => 'Agent',                                              'type'=>'adult',],     // Agent
		'ASB' => ['label' => 'Standby Passenger',                                  'type'=>'adult',],     // Standby Passenger
		'ASF' => ['label' => 'Air-sea Fare',                                       'type'=>'adult',],     // Air-sea Fare
		'AST' => ['label' => 'Airline Staff Standby',                              'type'=>'adult',],     // Airline Staff Standby
		'BLD' => ['label' => 'Blind Passenger',                                    'type'=>'adult',],     // Blind Passenger
		'BRV' => ['label' => 'Bereavement Passenger',                              'type'=>'adult',],     // Bereavement Passenger
		'BUD' => ['label' => 'Airline Buddy Standby',                              'type'=>'adult',],     // Airline Buddy Standby
		'CCM' => ['label' => 'Card Carrying Member',                               'type'=>'adult',],     // Card Carrying Member
		'CHD' => ['label' => 'Child',                                              'type'=>'child',],     // Child
		'CMA' => ['label' => 'Adult with Companion',                               'type'=>'adult',],     // Adult with Companion
		'CMM' => ['label' => 'Commuter',                                           'type'=>'adult',],     // Commuter
		'CMP' => ['label' => 'Companion',                                          'type'=>'adult',],     // Companion
		'CNN' => ['label' => 'Accompanied Child',                                  'type'=>'child',],     // Accompanied Child
		'CNV' => ['label' => 'Convention Passenger',                               'type'=>'adult',],     // Convention Passenger
		'CPN' => ['label' => 'Coupon Discount',                                    'type'=>'adult',],     // Coupon Discount
		'CSB' => ['label' => 'Child Standby',                                      'type'=>'adult',],     // Child Standby
		'DOD' => ['label' => 'Department of Defense Passenger',                    'type'=>'adult',],     // Department of Defense Passenger
		'ENF' => ['label' => 'Electronic Ticket discount Infant',                  'type'=>'adult',],     // Electronic Ticket discount Infant
		'FFY' => ['label' => 'Frequent Flyer',                                     'type'=>'adult',],     // Frequent Flyer
		'FIF' => ['label' => 'Family Intra-France',                                'type'=>'adult',],     // Family Intra-France
		'FNF' => ['label' => 'Family Plan Infant',                                 'type'=>'adult',],     // Family Plan Infant
		'FNN' => ['label' => 'Family Plan Child',                                  'type'=>'adult',],     // Family Plan Child
		'GCF' => ['label' => 'Government Contract Passenger',                      'type'=>'adult',],     // Government Contract Passenger
		'GCT' => ['label' => 'City/County Government Travel',                      'type'=>'adult',],     // City/County Government Travel
		'GDP' => ['label' => 'Government Employee Dependent',                      'type'=>'adult',],     // Government Employee Dependent
		'GEX' => ['label' => 'Government Exchange',                                'type'=>'adult',],     // Government Exchange
		'GST' => ['label' => 'State Government Passenger',                         'type'=>'adult',],     // State Government Passenger
		'GVT' => ['label' => 'Government Travel',                                  'type'=>'adult',],     // Government Travel
		'HNN' => ['label' => 'Charter Child Passenger',                            'type'=>'adult',],     // Charter Child Passenger
		'HOF' => ['label' => 'Head of Family',                                     'type'=>'adult',],     // Head of Family
		'ICP' => ['label' => 'Incentive Certificates',                             'type'=>'adult',],     // Incentive Certificates
		'IIT' => ['label' => 'Individual Inclusive Tour',                          'type'=>'adult',],     // Individual Inclusive Tour
		'INF' => ['label' => 'Infant (0-1)',                                       'type'=>'infant',],    // Infant (0-1)
		'INN' => ['label' => 'Individual Inclusive Tour Child',                    'type'=>'adult',],     // Individual Inclusive Tour Child
		'INS' => ['label' => 'Infant with a Seat',                                 'type'=>'infant',],    // Infant with a Seat
		'ITF' => ['label' => 'Inclusive Tour Infant without a Seat',               'type'=>'adult',],     // Inclusive Tour Infant without a Seat
		'ITS' => ['label' => 'Inclusive Tour Infant with a Seat',                  'type'=>'adult',],     // Inclusive Tour Infant with a Seat
		'ITY' => ['label' => 'Inclusive Tour Youth',                               'type'=>'adult',],     // Inclusive Tour Youth
		'JNF' => ['label' => 'Contract Bulk Infant without a Seat',                'type'=>'adult',],     // Contract Bulk Infant without a Seat
		'LBR' => ['label' => 'Laborer/Worker',                                     'type'=>'adult',],     // Laborer/Worker
		'LIF' => ['label' => 'Laborer/Worker Infant without a Seat',               'type'=>'adult',],     // Laborer/Worker Infant without a Seat
		'LNN' => ['label' => 'Laborer/Worker Child',                               'type'=>'adult',],     // Laborer/Worker Child
		'MBT' => ['label' => 'Military Basic Training Graduate',                   'type'=>'adult',],     // Military – Basic Training Graduate
		'MCR' => ['label' => 'Military Charter Passenger',                         'type'=>'adult',],     // Military Charter Passenger
		'MDP' => ['label' => 'Spouse/Dependent Children of Military Personnel',    'type'=>'adult',],     // Spouse/Dependent Children of Military Personnel
		'MED' => ['label' => 'Patients Travelling for Medical Treatment',          'type'=>'adult',],     // Patients Travelling for Medical Treatment
		'MIL' => ['label' => 'Military Confirmed',                                 'type'=>'adult',],     // Military Confirmed
		'MIR' => ['label' => 'Military Reserves on Active Duty',                   'type'=>'adult',],     // Military Reserves on Active Duty
		'MNN' => ['label' => 'Military Child',                                     'type'=>'adult',],     // Military Child
		'MPA' => ['label' => 'Military Parents/Parents In Law',                    'type'=>'adult',],     // Military Parents/Parents In Law
		'MRE' => ['label' => 'Retired Military/Military Dependent',                'type'=>'adult',],     // Retired Military/Military Dependent
		'MSB' => ['label' => 'Military Standby',                                   'type'=>'adult',],     // Military Standby
		'MSG' => ['label' => 'Multi State Government Passenger',                   'type'=>'adult',],     // Multi State Government Passenger
		'MUS' => ['label' => 'Military/DOD based in USA',                          'type'=>'adult',],     // Military/DOD based in USA
		'MXS' => ['label' => 'Military/DOD not based in USA',                      'type'=>'adult',],     // Military/DOD not based in USA
		'NAT' => ['label' => 'NATO Passenger',                                     'type'=>'adult',],     // NATO Passenger
		'NSB' => ['label' => 'Nonrevenue Standby',                                 'type'=>'adult',],     // Nonrevenue Standby
		'OTS' => ['label' => 'Passengers Occupying Two Seats',                     'type'=>'adult',],     // Passengers Occupying Two Seats
		'PCR' => ['label' => 'Charter Adult Passenger',                            'type'=>'adult',],     // Charter Adult Passenger
		'PIL' => ['label' => 'Pilgrim',                                            'type'=>'adult',],     // Pilgrim
		'REC' => ['label' => 'Military Recruit',                                   'type'=>'adult',],     // Military Recruit
		'REF' => ['label' => 'Refugee',                                            'type'=>'adult',],     // Refugee
		'SDB' => ['label' => 'Student Standby',                                    'type'=>'adult',],     // Student Standby
		'SEA' => ['label' => 'Seaman',                                             'type'=>'adult',],     // Seaman
		'SNN' => ['label' => 'Restricted Senior Citizen With Multiple Age Reqs',   'type'=>'adult',],     // Restricted Senior Citizen With Multiple Age Reqs
		'SPA' => ['label' => 'Accompanied Spouse',                                 'type'=>'adult',],     // Accompanied Spouse
		'SPH' => ['label' => 'Head of Family Spouse',                              'type'=>'adult',],     // Head of Family Spouse
		'SPS' => ['label' => 'Spouse',                                             'type'=>'adult',],     // Spouse
		'STR' => ['label' => 'State Resident',                                     'type'=>'adult',],     // State Resident
		'STU' => ['label' => 'Student',                                            'type'=>'adult',],     // Student
		'TNN' => ['label' => 'Frequent Flyer Child',                               'type'=>'adult',],     // Frequent Flyer Child
		'TUR' => ['label' => 'Tour Conductor',                                     'type'=>'adult',],     // Tour Conductor
		'UNN' => ['label' => 'Unaccompanied Child',                                'type'=>'adult',],     // Unaccompanied Child
		'UNV' => ['label' => 'University Employee',                                'type'=>'adult',],     // University Employee
		'VAC' => ['label' => 'Visit Another Country Adult',                        'type'=>'adult',],     // Visit Another Country Adult
		'VFR' => ['label' => 'Visit Friends/Relatives',                            'type'=>'adult',],     // Visit Friends/Relatives
		'VNN' => ['label' => 'Visit Another Country Child',                        'type'=>'adult',],     // Visit Another Country Child
		'WEB' => ['label' => 'Internet Fares',                                     'type'=>'adult',],     // Internet Fares
		'YCB' => ['label' => 'Senior Citizen Standby',                             'type'=>'adult',],     // Senior Citizen Standby
		'YCD' => ['label' => 'Senior Citizen',                                     'type'=>'adult',],     // Senior Citizen
		'YCL' => ['label' => 'Clergy',                                             'type'=>'adult',],     // Clergy
		'YCR' => ['label' => 'Charter Youth Passenger',                            'type'=>'adult',],     // Charter Youth Passenger
		'YSB' => ['label' => 'Youth Standby',                                      'type'=>'adult',],     // Youth Standby
		'YTH' => ['label' => 'Youth Confirmed',                                    'type'=>'adult',],     // Youth Confirmed
	];

	/**
	 * Extract the passenger name and other associated data
	 * @param string $passengerName
	 * @return array
	 */
	public static function extractPassengerName($passengerName)
	{
		$ret = [];
		$name = $passengerName;

		// IDNBR
		// (ID/DOB03JAN06)
		$regex = "/(?P<orig>.*)[\s]*\(ID\/(?P<IDNBR>[0-9A-Z]*)\)[\s]*$/";
		$m = [];
		if (preg_match($regex, $name, $m)) {
			$ret['IDNBR'] = 	$m['IDNBR'];
			$m1 = [];
			if (preg_match("/DOB(?P<PSGRNME_dateOfBirth>[0-9]{2}[A-Z]{3}[0-9]{2,4})/", $ret['IDNBR'], $m1)) {
				$ret['PSGRNME_dateOfBirth'] = $m1['PSGRNME_dateOfBirth'];
				$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);
			}

			$name = 			$m['orig'];
		}

		// this is important to be the 2'nd match, not the first, as it will swallow DOB-related matches
		// IDNBR
		// (ID*112B3C4D)
		// (ID:112B3C4D)
		// (ID-112B3C4D)
		// (ID112B3C4D)
		$regex = "/(?P<orig>.*)[\s]*\(ID([^0-9A-Z])?(?P<IDNBR>[0-9A-Z]*)\)[\s]*$/";
		if (preg_match($regex, $name, $m)) {
			$ret['IDNBR'] = 	$m['IDNBR'];
			$name = 			$m['orig'];
		}

		// IDNBR
		// (IDDOB13.12.10)
		$regex = "/(?P<orig>.*)[\s]*\(IDDOB(?P<PSGRNME_dateOfBirth>[0-9]{2}\.[0-9]{2}\.[0-9]{2,4})\)[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['PSGRNME_dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
			if (strlen($ret['PSGRNME_dateOfBirth'])==8) {
				$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DD.MM.YY', ['onlyPast'=>true]);
			}
			elseif (strlen($ret['PSGRNME_dateOfBirth'])==10) {
				$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DD.MM.YYYY', ['onlyPast'=>true]);
			}

			$name = 			$m['orig'];
		}

		// IDNBR
		// (IDDOB/27JUN36)
		$regex = "/(?P<orig>.*)[\s]*\((IDDOB|IDOB|ID\/DOB)\/(?P<PSGRNME_dateOfBirth>[0-9]{1,2}[A-Z]{3}[0-9]{2,4})\)[\s]*$/";
		if (preg_match($regex, $name, $m)) {
			$ret['PSGRNME_dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
			if (strlen($ret['PSGRNME_dateOfBirth'])==6) {
				$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate('0' . $ret['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);
			}
			elseif (strlen($ret['PSGRNME_dateOfBirth'])==7) {
				$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);
			}
			elseif (strlen($ret['PSGRNME_dateOfBirth'])==8) {
				$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate('0' . $ret['PSGRNME_dateOfBirth'], 'DDMMMYYYY', ['onlyPast'=>true]);
			}
			elseif(strlen($ret['PSGRNME_dateOfBirth'])==9) {
				$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DDMMMYYYY', ['onlyPast'=>true]);
			}

			$name = 			$m['orig'];
		}

		// IDNBR
		// (ID:112 B3C 4D)
		$regex = "/(?P<orig>.*)[\s]*\(ID(?P<IDNBR>[0-9A-Z\s]*)\)[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['IDNBR'] = 	trim($m['IDNBR']);
			$name = 			$m['orig'];
		}
		// look for PSGRID
		// (ADT)
		$regex = "/(?P<orig>.*)[\s]*\((?P<PSGRID>".implode("|", array_keys(self::$PSGRID)).")\)[\s]*$/";
		if(empty($ret['PSGRID']) && preg_match($regex, $name, $m)){
			$ret['PSGRID'] = 	$m['PSGRID'];
			$ret['PSGRID_'] = 	(empty($m['PSGRID'])?'':self::$PSGRID[$m['PSGRID']]);
			$name = 			$m['orig'];
		}

		// look for PSGRID
		// (INFILIE/GABRIEL/06JUL11)
		$regex = "/(?P<orig>.*)[\s]*\((?P<PSGRID>".implode("|", array_keys(self::$PSGRID)).")(?P<PSGRNME_responsible>[A-Z\s]+(\/[A-Z\s]+)?)\/(?P<PSGRNME_dateOfBirth>[0-9]{2}[A-Z]{3}[0-9]{2})\)[\s]*$/";
		if(preg_match($regex, $name, $m)){
			if(empty($ret['PSGRID'])) {	// if this pax has am infant with it, then we can assume it's an adult
				$ret['PSGRID_']['type'] = 	'adult';
			}

			$ret['attached'] = static::extractPassengerName($m['PSGRNME_responsible']);
			$ret['attached']['PSGRID'] = 	$m['PSGRID'];
			$ret['attached']['PSGRID_'] = 	(empty($m['PSGRID'])?'':self::$PSGRID[$m['PSGRID']]);
			$ret['attached']['dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
			$ret['attached']['dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($m['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);

			$name = 			$m['orig'];
		}

		// look for PSGRID
		// (YCD/16FEB29)
		$regex = "/(?P<orig>.*)[\s]*\((?P<PSGRID>".implode("|", array_keys(self::$PSGRID)).")\/(?P<PSGRNME_dateOfBirth>[0-9]{2}[A-Z]{3}[0-9]{2})\)[\s]*$/";
		if(empty($ret['PSGRID']) && preg_match($regex, $name, $m)){
			$ret['PSGRID'] = 	$m['PSGRID'];
			$ret['PSGRID_'] = 	(empty($m['PSGRID'])?'':self::$PSGRID[$m['PSGRID']]);

			$ret['PSGRNME_dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
			$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);

			$name = 			$m['orig'];
		}

		// look for PSGRID
		// (INF/SOFIA/24AUG11)
		$regex = "/(?P<orig>.*)[\s]*\((?P<PSGRID>".implode("|", array_keys(self::$PSGRID)).")\/(?P<PSGRNME_responsible>[A-Z\s]+(\/[A-Z\s]+)?)\/(?P<PSGRNME_dateOfBirth>[0-9]{2}[A-Z]{3}[0-9]{2})\)[\s]*$/";
		if(preg_match($regex, $name, $m)){
			if (empty($ret['PSGRID'])) {
				$ret['PSGRID_']['type'] = 	'adult';

				$ret['attached'] = static::extractPassengerName($m['PSGRNME_responsible']);
				$ret['attached']['PSGRID'] = 	$m['PSGRID'];
				$ret['attached']['PSGRID_'] = 	(empty($m['PSGRID'])?'':self::$PSGRID[$m['PSGRID']]);
				$ret['attached']['dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
				$ret['attached']['dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($m['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);


				$name = 			$m['orig'];
			}
			else {	// as seen on CH/Intertravel Putnik, we may have 2 PSGRID markers in the text... The INF-tag refers to the "owned infant" as opposed to the expected "owner parent" tag format
				// TRAILOVIC/TANJA MRS(INF/MLADEN/17MAY11)(ADT)
				$name = 			$m['orig'];
			}
		}

		// look for PSGRID
		// (INF/THERESANATALIE)
		$regex = "/(?P<orig>.*)[\s]*\((?P<PSGRID>".implode("|", array_keys(self::$PSGRID)).")\/(?P<PSGRNME_responsible>[A-Z\s]+(\/[A-Z\s]+)?)\)[\s]*$/";
		if(empty($ret['PSGRID']) && preg_match($regex, $name, $m)){
				$ret['PSGRID_']['type'] = 	'adult';

				$ret['attached'] = static::extractPassengerName($m['PSGRNME_responsible']);
				$ret['attached']['PSGRID'] = 	$m['PSGRID'];
				$ret['attached']['PSGRID_'] = 	(empty($m['PSGRID'])?'':self::$PSGRID[$m['PSGRID']]);

			$name = 			$m['orig'];
		}

		// TODO: drop it
		// look for PSGRID
		// [\s]ADT
		$regex = "/(?P<orig>.*)[\s]+(?P<PSGRID>".implode("|", array_keys(self::$PSGRID)).")[\s]*$/";
		if(empty($ret['PSGRID']) && preg_match($regex, $name, $m)){
			$ret['PSGRID'] = 	$m['PSGRID'];
			$ret['PSGRID_'] = 	(empty($m['PSGRID'])?'':self::$PSGRID[$m['PSGRID']]);
			$name = 			$m['orig'];
		}
		$regex = "/(?P<orig>.*)[\s]*\((?P<IDNBR>[0-9A-Z\s]*)\)[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['IDNBR'] = 	trim($m['IDNBR']);
			$name = 			$m['orig'];
		}

		// look for birthdate
		// 11APR09
		$regex = "/(?P<orig>.*)[\s]+(?P<PSGRNME_dateOfBirth>[0-9]{2}[A-Z]{3}[0-9]{2})[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['PSGRNME_dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
			$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);
			$name = 					$m['orig'];
		}

		// look for birthdate
		// 11APR2009
		$regex = "/(?P<orig>.*)[\s]+(?P<PSGRNME_dateOfBirth>[0-9]{2}[A-Z]{3}[0-9]{4})[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['PSGRNME_dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
			$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate($ret['PSGRNME_dateOfBirth'], 'DDMMMYYYY', ['onlyPast'=>true]);
			$name = 					$m['orig'];
		}

		// look for birthdate
		// 1APR09
		$regex = "/(?P<orig>.*)[\s]+(?P<PSGRNME_dateOfBirth>[0-9]{1}[A-Z]{3}[0-9]{2})[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['PSGRNME_dateOfBirth'] = $m['PSGRNME_dateOfBirth'];
			$ret['PSGRNME_dateOfBirth_'] =\App\Amadeus\FileParser\LineAbstract::extractDate("0".$ret['PSGRNME_dateOfBirth'], 'DDMMMYY', ['onlyPast'=>true]);
			$name = 					$m['orig'];
		}

		// look for passenger honorifics(DR, PROF)
		if (empty($ret['PSGRNME_honorifics'])) {
			// filter longer regexps first
			$regexps = array_map(function ($rx) {
					return "(".preg_quote($rx, '/').")";
				},
				array_keys(self::$PSGRNME_honorifics)
			);
			if ($regexps) {
				$regex = "/(?P<orig>.*?)[\s]*(?P<PSGRNME_honorifics>".implode("|", $regexps).")[\s]*$/";
				if(preg_match($regex, $name, $m)){
					$ret['PSGRNME_honorifics'] = 	$m['PSGRNME_honorifics'];
					$ret['PSGRNME_honorifics_'] =	self::$PSGRNME_honorifics[$ret['PSGRNME_honorifics']];
					$name = 					$m['orig'];
				}
			}
		}

		// look for passenger title(MR, MRS)
		if (empty($ret['PSGRNME_title'])) {
			// filter longer regexps first
			$regexps = array_map(function ($rx) {
					return "(".preg_quote($rx, '/').")";
				},
				array_keys(self::$PSGRNME_title)
			);
			if ($regexps) {
				$regex = "/(?P<orig>.*)[\s]*(?P<PSGRNME_title>".implode("|", $regexps).")[\s]*$/";
				if(preg_match($regex, $name, $m)){
					$ret['PSGRNME_title'] = 	$m['PSGRNME_title'];
					$ret['PSGRNME_title_'] =	self::$PSGRNME_title[$ret['PSGRNME_title']];
					$name = 					$m['orig'];
				}
			}
		}

		// "fuzzy" sex search, like the old parser did
		// TARLOVAS/VYTAUTAS MR AP
		// ignore AP at the end of the PSGRNME. This may happen because the AP element is the next element in the Amadeus interface, and it might get inserted by mistake by the user
		if (empty($ret['PSGRNME_title'])) {
			$regex = "/(?P<orig>.*)[\s]+(?P<PSGRNME_title>".implode("|", array_keys(self::$PSGRNME_title)).") AP$/";
			if(preg_match($regex, $name, $m)){
				$ret['PSGRNME_title'] = 	$m['PSGRNME_title'];
				$ret['PSGRNME_title_'] =	self::$PSGRNME_title[$ret['PSGRNME_title']];
				$name = 					$m['orig'];
			}
		}

		// split into first/last name
		// ALEX/CROSS
		// DE JESUS FERREIRA DE OLIVEIRA/LILIANA
		$regex = "/^(?P<lastName>([A-Z]+)" . str_repeat("(\s[A-Z]+)?", 10) . ")[\s]*\/[\s]*(?P<firstName>([A-Z]+)(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?)[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['PSGRNME'] = 			trim($name);
			$ret['PSGRNME_firstName'] = $m['firstName'];
			$ret['PSGRNME_lastName'] = 	$m['lastName'];

			$name = '';
		}

		// split into first/last name
		// SALAMEH NAWAF MR
		$regex = "/^(?P<lastName>([A-Z]+)(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?)[\s]+(?P<firstName>([A-Z]+)(\s[A-Z]+)?(\s[A-Z]+)?)[\s]*$/";
		if(preg_match($regex, $name, $m)){
			$ret['PSGRNME'] = 			trim($name);
			$ret['PSGRNME_firstName'] = $m['firstName'];
			$ret['PSGRNME_lastName'] = 	$m['lastName'];

			$name = '';
		}

		// MUNDALAPPA/MR seems to be a valid name for RO/AS:)
		$regex = "/^(?P<lastName>([A-Z]+)(\s[A-Z]+)?(\s[A-Z]+)?(\s[A-Z]+)?)(\/)?[\s]*$/";
		if(empty($ret['PSGRNME_firstName']) && empty($ret['PSGRNME_lastName']) && preg_match($regex, $name, $m)){
			$ret['PSGRNME'] = 			trim($name);
			$ret['PSGRNME_firstName'] = '';
			$ret['PSGRNME_lastName'] = 	$m['lastName'];

			$name = '';
		}


		return ($ret?$ret:null);
	}

	/**
	 * the most complete guide, seems to be the one on www.singaporeair.com
	 * 	@see www.singaporeair.com/pdf/taxes/airport-taxes.pdf
	 * 	@see http://www.flyertalk.com/forum/archive/t-292759.html
	 */
	static protected $TAXC = [
		'AB' => ['label' => 'Government Tax',],
		'AC' => ['label' => 'Value Added Tax',],
		'AE' => ['label' => 'Passenger Service Charge (International)',],
		'AF' => ['label' => 'Airport Departure Fee (Domestic/International)',],
		'AG' => ['label' => 'Ticket Tax',],
		'AH' => ['label' => 'Airport Tax',],
		'AI' => ['label' => 'Baggage Security Screening Fee',],
		'AJ' => ['label' => 'Airport Exit Tax (International)',],
		'AK' => ['label' => 'Airport Departure Tax (International)',],
		'AL' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'AM' => ['label' => 'Tax',],
		'AN' => ['label' => 'Airport Facility Charge (Domestic/International)',],
		'AO' => ['label' => 'Embarkation Tax (International)',],
		'AP' => ['label' => 'Security Charge (Domestic/International)',],
		'AR' => ['label' => 'Ticket Tax',],
		'AT' => ['label' => 'Passenger Security Charge(Domestic/International)',],
		'AU' => ['label' => 'Passenger Movement Charge',],
		'AV' => ['label' => 'Tourism Development Tax (International)',],
		'AW' => ['label' => 'Passenger Facility and Security Charge',],
		'AX' => ['label' => 'Passenger Service Charge (Domestic)',],
		'AY' => ['label' => 'Passenger Civil Aviation Security Service Fee (Domestic/International)',],
		'AZ' => ['label' => 'Departure Tax (International)',],
		'BA' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'BB' => ['label' => 'Value Added Tax',],
		'BC' => ['label' => 'Airport Security Charge -(Domestic/International)',],
		'BD' => ['label' => 'Embarkation Fee (Domestic/International)',],
		'BE' => ['label' => 'Passenger Service and Security Charge',],
		'BF' => ['label' => 'Fiscal Stamp / Security / Sales / Tourism Tax (Domestic/International)',],
		'BG' => ['label' => 'Passenger Charge (Domestic/International)',],
		'BH' => ['label' => 'Government Tax',],
		'BK' => ['label' => 'Airport Departure Fee (Domestic/International)',],
		'BL' => ['label' => 'Aviation Security Fee',],
		'BM' => ['label' => 'Government Passenger Tax',],
		'BN' => ['label' => 'Passenger Services Charge (International)',],
		'BO' => ['label' => 'Sales Tax (Domestic/International)',],
		'BP' => ['label' => 'PSC, Departure Tax and Contribution to International Poverty Eradication',],
		'BQ' => ['label' => 'Airport Fee',],
		'BR' => ['label' => 'Embarkation Tax (Domestic/International)',],
		'BS' => ['label' => 'Ticket Tax (International)',],
		'BU' => ['label' => 'Airport Development Fee',],
		'BW' => ['label' => 'Departure Tax(Domestic/International)',],
		'BX' => ['label' => 'Security Tax (Domestic/International)',],
		'BY' => ['label' => 'Sales Tax (International)',],
		'BZ' => ['label' => 'Ticket Tax',],
		'CA' => ['label' => 'Air Travellers Security Charge (Domestic/International)',],
		'CB' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'CC' => ['label' => 'Cocos Island Passenger Service Charge',],
		'CD' => ['label' => 'Embarkation / Sales / Tourism Tax (Domestic/International)',],
		'CE' => ['label' => 'Aviation Security Screening Levy (Domestic)',],
		'CF' => ['label' => 'Security Tax',],
		'CG' => ['label' => 'Sales / Security Tax (Domestic/International)',],
		'CH' => ['label' => 'Airport Passenger Security and Noise Charge (Domestic/International)',],
		'CI' => ['label' => 'Security / Tourism Tax (Domestic/International)',],
		'CJ' => ['label' => 'Security Service Charge (Domestic/International)',],
		'CL' => ['label' => 'Airport Facility Charge (Domestic)',],
		'CM' => ['label' => 'Tax on Value (Domestic/International)',],
		'CN' => ['label' => 'Airport Fee (Domestic/International)',],
		'CO' => ['label' => 'Airport Tax (Domestic/International)',],
		'CQ' => ['label' => 'Rehabilitation fund and care of handicapped person',],
		'CR' => ['label' => 'Transportation Tax',],
		'CT' => ['label' => 'Security Tax (Domestic/International)',],
		'CV' => ['label' => 'Airport Embarkation Tax (Domestic/International)',],
		'CW' => ['label' => 'Value Added Tax (Domestic)',],
		'CX' => ['label' => 'Christmas Island Passenger Service Charge (Domestic/International)',],
		'CY' => ['label' => 'Airport Service Charge (International)',],
		'CZ' => ['label' => 'Embarkation Tax (Domestic/International)',],
		'DA' => ['label' => 'Passenger Service Charge (Domestic)',],
		'DB' => ['label' => 'Airport Security Charge',],
		'DC' => ['label' => 'Security Charge (Domestic/International)',],
		'DD' => ['label' => 'Concourse Fee (Intl)',],
		'DE' => ['label' => 'Airport Security Charge (Domestic/International)',],
		'DF' => ['label' => 'Security Charge (Intl)',],
		'DG' => ['label' => 'Resident Exit Tax (Timbre)',],
		'DH' => ['label' => 'Passenger Facility Charge',],
		'DI' => ['label' => 'Airport Facilitation Fee (International)',],
		'DJ' => ['label' => 'Departure Tax',],
		'DL' => ['label' => 'Value Added Tax (Passengers)',],
		'DM' => ['label' => 'Transportation Tax (International)',],
		'DN' => ['label' => 'Value Added Tax (Excess Baggage)',],
		'DO' => ['label' => 'Transportation Tax (Domestic/International)',],
		'DP' => ['label' => 'Goods and Services Tax (GST), (Domestic/International)',],
		'DQ' => ['label' => 'Security Charge (Domestic/International)',],
		'DR' => ['label' => 'Airport Facility Charge (Domestic/International)',],
		'DS' => ['label' => 'Safety Fee (Intl)',],
		'DT' => ['label' => 'Transfer Passenger Fee (Domestic/International)',],
		'DW' => ['label' => 'Embarkation Tax (Domestic/International)',],
		'DX' => ['label' => 'Aeronautical Development Charge (Intl)',],
		'DY' => ['label' => 'Tourism Arrival Tax',],
		'DZ' => ['label' => 'Transportation / Fiscal / Airport Tax',],
		'EA' => ['label' => 'Passenger Departure Tax',],
		'EB' => ['label' => 'Passenger and Safety Charge (Domestic/International)',],
		'EC' => ['label' => 'Government Transportation Tax (Domestic/International)',],
		'ED' => ['label' => 'Tourism Fee (International)',],
		'EE' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'EF' => ['label' => 'Security Tax (Domestic/International)',],
		'EG' => ['label' => 'Transportation Tax',],
		'EI' => ['label' => 'VAT Adjustment Tax (Dom)',],
		'EJ' => ['label' => 'PTA surcharge (International)',],
		'EK' => ['label' => 'Passenger Service and Security Fee (Domestic/International)',],
		'EL' => ['label' => 'Airport Improvement Fee',],
		'EM' => ['label' => 'Airport Service Fee',],
		'EN' => ['label' => 'Passenger Facility Charge',],
		'EO' => ['label' => 'Airport Expansion Tax',],
		'EP' => ['label' => 'Development Tax (International)',],
		'EQ' => ['label' => 'Service Charge (Domestic/International)',],
		'ER' => ['label' => 'Sales Tax (Domestic/International)',],
		'ES' => ['label' => 'Value Added Tax (IVA)',],
		'ET' => ['label' => 'Stamp Duty, International/Domestic Air Travel',],
		'EU' => ['label' => 'INAC -Civil Aviation Services Improvement Fee (Domestic/International)',],
		'EV' => ['label' => 'Passenger Safety Charge (Domestic/International)',],
		'EW' => ['label' => 'Passenger Facility Fee',],
		'EX' => ['label' => 'Security Bag Charge (Domestic/International)',],
		'EY' => ['label' => 'Airport Departure Tax',],
		'EZ' => ['label' => 'Airport Security Charge',],
		'FA' => ['label' => 'Airport Development Charge',],
		'FB' => ['label' => 'Airport Enhancement Facilitation Fee (Domestic/International)',],
		'FC' => ['label' => 'Terminal Fee (International)',],
		'FD' => ['label' => 'Tourism Fee (International)',],
		'FE' => ['label' => 'Security Charge (Domestic/International)',],
		'FF' => ['label' => 'Baggage Screening Charge (International)',],
		'FG' => ['label' => 'Passenger Screening Fee (Domestic/International)',],
		'FH' => ['label' => 'Airport Departure Tax (SXM) (Domestic/International)',],
		'FI' => ['label' => 'Passenger Fee (International)',],
		'FJ' => ['label' => 'Value Added Tax',],
		'FL' => ['label' => 'Passenger Service Charge (Domestic)',],
		'FN' => ['label' => 'Value Added Tax on IT/EX/VT/HB (Dom)',],
		'FO' => ['label' => 'Departure Tax',],
		'FP' => ['label' => 'Security Control Fee',],
		'FQ' => ['label' => 'Abidjan Municipal Tax (Domestic/International)',],
		'FR' => ['label' => 'Airport Tax (Domestic/International)',],
		'FS' => ['label' => 'Common Area User Charge (Intl)',],
		'FU' => ['label' => 'Conservation Tax',],
		'FV' => ['label' => 'Passenger Service Fee',],
		'FW' => ['label' => 'Security Fee (International)',],
		'FX' => ['label' => 'Security Tax',],
		'FZ' => ['label' => 'Airport Departure Tax',],
		'GA' => ['label' => 'Airport Tax -(Domestic/International)',],
		'GB' => ['label' => 'Air Passenger Duty (APD) (Domestic/International)',],
		'GC' => ['label' => 'Terminal Facility Charge (Domestic/International)',],
		'GD' => ['label' => 'Government Ticket Tax',],
		'GE' => ['label' => 'Passenger Fee (Domestic/International)',],
		'GF' => ['label' => 'Embarkation Tax',],
		'GG' => ['label' => 'Airport Security Charge(Domestic/International)',],
		'GH' => ['label' => 'Passenger Service Charge (International)',],
		'GI' => ['label' => 'Passenger Service Charge',],
		'GJ' => ['label' => 'Airport Facility Fee (Domestic/International)',],
		'GK' => ['label' => 'Security Fee (Domestic/International)',],
		'GM' => ['label' => 'Government Sales Tax',],
		'GN' => ['label' => 'Service Charge (Domestic/International)',],
		'GO' => ['label' => 'Security Facility Maintenance Charge',],
		'GP' => ['label' => 'Embarkation / Departure Tax',],
		'GQ' => ['label' => 'Departure Tax (Domestic/International)',],
		'GR' => ['label' => 'Airport Development Charge(Domestic/International)',],
		'GU' => ['label' => 'Customs, Agriculture and Quarantine Inspection Services Charge',],
		'GV' => ['label' => 'Stamp Tax',],
		'GW' => ['label' => 'Embarkation / Security / Stamp Tax (Domestic/International)',],
		'GX' => ['label' => 'Terminal Fee (Domestic/International)',],
		'GY' => ['label' => 'Government Sales Tax',],
		'GZ' => ['label' => 'Airport Service Charge (International)',],
		'HA' => ['label' => 'Tirana Security Charge (International)',],
		'HB' => ['label' => 'Council City Tax (Domestic/International)',],
		'HC' => ['label' => 'Development Charge (Domestic/International)',],
		'HD' => ['label' => 'Safety Charge (Domestic/International)',],
		'HE' => ['label' => 'Airport Development Tax(Domestic/International)',],
		'HF' => ['label' => 'Value Added Tax',],
		'HG' => ['label' => 'Tourism Enhancement Fee (International)',],
		'HH' => ['label' => 'Passenger Fee (International)',],
		'HI' => ['label' => 'Immigration Processing Fee',],
		'HJ' => ['label' => 'Passenger Facility Charge (Domestic)',],
		'HK' => ['label' => 'Air Passenger Departure Tax',],
		'HL' => ['label' => 'Airport Development Charge (International)',],
		'HN' => ['label' => 'Transportation Tax (Domestic/International)',],
		'HO' => ['label' => 'Air Transportation Charge',],
		'HP' => ['label' => 'Infrastructure Development Charge (Domestic/International)',],
		'HQ' => ['label' => 'Embarkation Tax (International)',],
		'HR' => ['label' => 'Airport Tax (Domestic/International)',],
		'HS' => ['label' => 'Airport Charge (International)',],
		'HT' => ['label' => 'Transportation Tax (Domestic/International)',],
		'HU' => ['label' => 'Airport Departure Tax (Domestic/International)',],
		'HV' => ['label' => 'Passenger Tax (International)',],
		'HW' => ['label' => 'Airport Departure Tax (International)',],
		'HX' => ['label' => 'Safety and Security Fee (Domestic/International)',],
		'HY' => ['label' => 'Aviation Safety Fee (Domestic/International)',],
		'HZ' => ['label' => 'Solidarity Tax',],
		'IA' => ['label' => 'Passenger Security Charge (international)',],
		'IB' => ['label' => 'Airport Tax (Domestic/International)',],
		'IC' => ['label' => 'Development Charge (international)',],
		'ID' => ['label' => 'Value Added Tax (Domestic)',],
		'IF' => ['label' => 'Airport Departure Tax (international)',],
		'IG' => ['label' => 'Immigration Fee',],
		'IH' => ['label' => 'Airport Departure Tax (Domestic/International)',],
		'II' => ['label' => 'Facilitation Charge',],
		'IJ' => ['label' => 'Security Charge (International)',],
		'IK' => ['label' => 'Security Fee (International)',],
		'IL' => ['label' => 'Departure Passenger Airport Tax -(Intl.)',],
		'IM' => ['label' => 'Tourism Contribution Fee (International)',],
		'IN' => ['label' => 'User Development Fee(Domestic/International)',],
		'IP' => ['label' => 'Development Charge (Domestic/International)',],
		'IR' => ['label' => 'Airport Tax (International)',],
		'IS' => ['label' => 'Airport Service Charge (Domestic/International)',],
		'IT' => ['label' => 'Embarkation Tax(Domestic/International)',],
		'IU' => ['label' => 'Passenger Security Charge (International)',],
		'IV' => ['label' => 'Airport Infrastructure Improvement Fee (Domestic)',],
		'IW' => ['label' => 'Airport Improvement Fee (Domestic/International)',],
		'IX' => ['label' => 'Border Crossing Tax (International)',],
		'IY' => ['label' => 'Value Added Tax (Domestic) / Departure Tax (International)',],
		'IZ' => ['label' => 'Air Passenger Solidarity Tax (Domestic/International)',],
		'JA' => ['label' => 'Airport Passenger Security Fee (Domestic/International)',],
		'JB' => ['label' => 'IVA (VAT) ON THE AIRPORT DEPARTURE TAX',],
		'JC' => ['label' => 'Passenger Service Charge (International)',],
		'JD' => ['label' => 'Departure Charge (Domestic/International)',],
		'JE' => ['label' => 'Passenger Solidarity Fee (International)',],
		'JF' => ['label' => 'Concourse Fee (International)',],
		'JG' => ['label' => 'Passenger Service Charge (International)',],
		'JH' => ['label' => 'Security Fee (International)',],
		'JI' => ['label' => 'Air Passenger Service Charge (APSC) (Domestic/International)',],
		'JJ' => ['label' => 'Security fee',],
		'JK' => ['label' => 'Departure Fee',],
		'JL' => ['label' => 'Flight Security Tax',],
		'JM' => ['label' => 'Stamp Tax (Domestic/International)',],
		'JN' => ['label' => 'Service Tax on Premium class travel',],
		'JO' => ['label' => 'Ticket Sales Tax (International)',],
		'JP' => ['label' => 'Consumption Tax',],
		'JQ' => ['label' => 'Security Charge -International',],
		'JR' => ['label' => 'Solidarity Tax -(Domestic/International)',],
		'JS' => ['label' => 'Tourism Tax',],
		'JT' => ['label' => 'Promotion of Tourism Tax',],
		'JU' => ['label' => 'Air Passenger Solidarity Tax (International)',],
		'JV' => ['label' => 'Solidarity Tax (International)',],
		'JW' => ['label' => 'Security Tax (International)',],
		'JX' => ['label' => 'Passenger Service Charge (International)',],
		'JY' => ['label' => 'Value Added Tax (VAT)',],
		'JZ' => ['label' => 'Stamp Tax (Domestic/International)',],
		'KA' => ['label' => 'Flight Security Fee (International)',],
		'KB' => ['label' => 'Tourism Development Levy (International)',],
		'KC' => ['label' => 'Passenger Airport and Security Charge',],
		'KD' => ['label' => 'Infrastructure Charge',],
		'KE' => ['label' => 'Passenger Airport Service Charge (Domestic)',],
		'KF' => ['label' => 'Value Added Tax (International)',],
		'KJ' => ['label' => 'Civil Aviation Fee',],
		'KK' => ['label' => 'Passenger Service Charge (International)',],
		'KL' => ['label' => 'Value Added Tax',],
		'KM' => ['label' => 'Airport / Security / Stamp Tax (Domestic/International)',],
		'KN' => ['label' => 'Sales Tax (Domestic/International)',],
		'KO' => ['label' => 'Territorial Development Tax',],
		'KP' => ['label' => 'Passenger Service Charge (International)',],
		'KQ' => ['label' => 'Civil Aviation Charge',],
		'KS' => ['label' => 'Airport Service Charge (International)',],
		'KT' => ['label' => 'Passenger Service Charge (International)',],
		'KU' => ['label' => 'Municipality Tax',],
		'KV' => ['label' => 'Air Passenger Tax (Domestic/International)',],
		'KW' => ['label' => 'Airport Departure Tax',],
		'KX' => ['label' => 'Passenger Service Charge -Domestic',],
		'KY' => ['label' => 'Departure Tax (International)',],
		'KZ' => ['label' => 'Sales Tax (Domestic/International)',],
		'LA' => ['label' => 'Airport Passenger Service Charge -(Domestic/International)',],
		'LB' => ['label' => 'Beirut Airport Embarkation Tax (International)',],
		'LC' => ['label' => 'Travel Tax',],
		'LD' => ['label' => 'Passenger Service Charge(Domestic/International)',],
		'LE' => ['label' => 'Passenger Facility Charge',],
		'LF' => ['label' => 'Passenger Tax -(Domestic/International)',],
		'LG' => ['label' => 'Security Charge -(Domestic/International)',],
		'LH' => ['label' => 'Airport Departure Tax -International',],
		'LJ' => ['label' => 'CAA Regulation Tax',],
		'LK' => ['label' => 'Embarkation Tax (CMB)',],
		'LL' => ['label' => 'Security Tax',],
		'LM' => ['label' => 'Local Administration Tax',],
		'LN' => ['label' => 'Value Added Tax',],
		'LO' => ['label' => 'Hold Baggage Screening Fee',],
		'LQ' => ['label' => 'Air Travel Tax (Domestic/International)',],
		'LR' => ['label' => 'Ticket Tax',],
		'LT' => ['label' => 'Airport Tax (Domestic/International)',],
		'LU' => ['label' => 'Passenger Service Charge',],
		'LV' => ['label' => 'Passenger Departure and Security Tax (Domestic/International)',],
		'LY' => ['label' => 'Ticket Tax',],
		'MA' => ['label' => 'Airport Security / Equipment / Passenger Service / Ticket Stamp Tax',],
		'MD' => ['label' => 'Airport Development Tax',],
		'ME' => ['label' => 'Departure Tax (International)',],
		'MG' => ['label' => 'Passenger Tax (Domestic/International)',],
		'MJ' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'MK' => ['label' => 'Airport Service Tax(Domestic/International)',],
		'ML' => ['label' => 'Ticket Tax (Domestic/International)',],
		'MN' => ['label' => 'Passenger Service Charge',],
		'MO' => ['label' => 'Airport Security Tax',],
		'MQ' => ['label' => 'Embarkation Tax',],
		'MR' => ['label' => 'Embarkation / Fiscal Stamp / Security Tax',],
		'MT' => ['label' => 'Airport Tax',],
		'MU' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'MW' => ['label' => 'Surtax (Dom.)',],
		'MX' => ['label' => 'Transportation / Excess Baggage Ticket Tax',],
		'MY' => ['label' => 'Passenger Service and Security Charge (Domestic/International)',],
		'MZ' => ['label' => 'Value Added Tax (Domestic)',],
		'NA' => ['label' => 'Passenger Service Charge(Domestic/International)',],
		'NC' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'NE' => ['label' => 'Fiscal Stamp / Security / Transportation Tax',],
		'NF' => ['label' => 'Domestic (Australian) Passenger Service Charge',],
		'NG' => ['label' => 'Sales Tax (Domestic/International)',],
		'NI' => ['label' => 'Sales (Hacienda) Tax -(Domestic/International)',],
		'NP' => ['label' => 'Passenger Service Charge (International)',],
		'NQ' => ['label' => 'Tourism Service Fee (International)',],
		'NV' => ['label' => 'Value Added Tax (VAT) Dom.',],
		'NZ' => ['label' => 'Goods and Services Tax (GST) -Passengers',],
		'OA' => ['label' => 'Airline Booking Fees',],
		'OB' => ['label' => 'Airline Ticketing Fees',],
		'OC' => ['label' => 'Airline Service Fees',],
		'OI' => ['label' => 'Passenger Service and Security Charge (International)',],
		'OM' => ['label' => 'Airport Tax',],
		'OO' => ['label' => 'Passenger Security Service Charge',],
		'OP' => ['label' => 'Aviation Levy',],
		'OW' => ['label' => 'Excise Duty Tax',],
		'OY' => ['label' => 'Air Transport Tax',],
		'PA' => ['label' => 'Tourism Tax (Domestic/International)',],
		'PE' => ['label' => 'Sales Tax (Domestic/International)',],
		'PF' => ['label' => 'Departure Tax (Domestic/International)',],
		'PG' => ['label' => 'Departure Tax',],
		'PH' => ['label' => 'Travel / Non-Resident Head Tax',],
		'PI' => ['label' => 'test',],
		'PK' => ['label' => 'Excise Duty',],
		'PT' => ['label' => 'Security Tax (Domestic/International)',],
		'PV' => ['label' => 'Value Added Tax (VAT) Domestic',],
		'PY' => ['label' => 'Transportation Tax (International)',],
		'QA' => ['label' => 'Airport Fee (Intl)',],
		'QG' => ['label' => 'Value Added Tax (Commercial Entities)',],
		'QH' => ['label' => 'Embarkation Tax',],
		'QK' => ['label' => 'Noise Levy Tax (Domestic/International)',],
		'QL' => ['label' => 'Airport Service Charge -(Domestic/International)',],
		'QM' => ['label' => 'Service Charge (Domestic)',],
		'QN' => ['label' => 'Gross Receipts Tax (Domestic)',],
		'QO' => ['label' => 'Custom and Immigration Services Tax (International)',],
		'QR' => ['label' => 'Passenger Service Charge -Dom',],
		'QS' => ['label' => 'Passenger Facility Charge',],
		'QT' => ['label' => 'Airport Service Charge (Domestic/International)',],
		'QU' => ['label' => 'Passenger Fee (Domestic)',],
		'QV' => ['label' => 'Security Tax (Domestic/International)',],
		'QW' => ['label' => 'Passenger Service Charge -Dom',],
		'QX' => ['label' => 'Passenger Service Charge -Intl',],
		'QY' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'QZ' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'RA' => ['label' => 'Passenger Service Charge -Intl.',],
		'RB' => ['label' => 'Passenger Service Charge (International)',],
		'RC' => ['label' => 'Harmonized Sales Tax',],
		'RD' => ['label' => 'Passenger Service Charge -Dom.',],
		'RE' => ['label' => 'Embarkation Tax (Intl)',],
		'RG' => ['label' => 'Federal Excise Duty (FED)',],
		'RH' => ['label' => 'Service Charge (Domestic)',],
		'RI' => ['label' => 'Terminal Use Charge (International)',],
		'RJ' => ['label' => 'Passenger Service Charge(Domestic/International)',],
		'RK' => ['label' => 'Security Tax (Domestic/International)',],
		'RL' => ['label' => 'Embarkation Tax (International)',],
		'RN' => ['label' => 'Passenger Service Charge -(Domestic/International)',],
		'RO' => ['label' => 'Airport Departure Tax (Domestic/International)',],
		'RQ' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'RS' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'RT' => ['label' => 'Departure Tax (Regional)',],
		'RU' => ['label' => 'Sales Tax (Intl) -Russian airlines',],
		'RV' => ['label' => 'Value Added Tax',],
		'RW' => ['label' => 'Passenger Service Fee (Domestic/International)',],
		'RX' => ['label' => 'Tourism Tax',],
		'RZ' => ['label' => 'Stamp Tax (Domestic/International)',],
		'SB' => ['label' => 'Government Ticket Sales Tax (Domestic/International)',],
		'SC' => ['label' => 'Goods and Services Tax (Domestic/International)',],
		'SD' => ['label' => 'Stamp Tax (Domestic/International)',],
		'SG' => ['label' => 'Passenger Service Charge',],
		'SI' => ['label' => 'Passenger Service Charge',],
		'SK' => ['label' => 'Embarkation Tax (Domestic/International)',],
		'SL' => ['label' => 'Foreign Travel Tax',],
		'SN' => ['label' => 'Fiscal Stamp Tax (Domestic/International)',],
		'SP' => ['label' => 'Embarkation Fee (Domestic/International)',],
		'SQ' => ['label' => 'Airport Improvement Fee (AIF), (Domestic/International)',],
		'SR' => ['label' => 'Airport Facility Charge (International)',],
		'ST' => ['label' => 'Public Assistance / Stamp Tax (Domestic/International)',],
		'SU' => ['label' => 'Security Tax (Domestic/International)',],
		'SV' => ['label' => 'Value Added Tax (Individuals)',],
		'SW' => ['label' => 'Passenger Service Facilities Charge (International)',],
		'SX' => ['label' => 'Passenger Service Charge (International)',],
		'SY' => ['label' => 'Stamp Tax (Domestic/International)',],
		'TA' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'TB' => ['label' => 'Goods and Services Tax(Domestic/International)',],
		'TC' => ['label' => 'Passenger Tax / Security Charge',],
		'TD' => ['label' => 'Embarkation Tax (Domestic/International)',],
		'TG' => ['label' => 'Travel Tax',],
		'TI' => ['label' => 'Fiscal Stamp Tax (Domestic/International)',],
		'TM' => ['label' => 'International Passenger Airport Tax',],
		'TN' => ['label' => 'Fiscal Stamp Tax (Domestic/International)',],
		'TO' => ['label' => 'Security Levy and Airport Development Charge',],
		'TQ' => ['label' => 'Security Tax (Domestic/International)',],
		'TR' => ['label' => 'Airport Service Charge (International)',],
		'TS' => ['label' => 'Passenger Service Charge(Domestic/International)',],
		'TT' => ['label' => 'Value Added Tax',],
		'TU' => ['label' => 'Passenger Airport Service Charge (International)',],
		'TW' => ['label' => 'Airport Service Charge -Intl',],
		'TX' => ['label' => 'Tax for Multiple Purpose Document',],
		'TZ' => ['label' => 'Airport Tax (Domestic/International)',],
		'UA' => ['label' => 'Security Charge -(Domestic/International)',],
		'UB' => ['label' => 'Passenger Service Charge -(Domestic/International)',],
		'UD' => ['label' => 'State Charge -(Domestic/International)',],
		'UE' => ['label' => 'Value Added Tax -Domestic',],
		'UF' => ['label' => 'Passenger Service Charge -Intl',],
		'UG' => ['label' => 'Security Charge (Domestic/International)',],
		'UH' => ['label' => 'Security Charge (International)',],
		'UI' => ['label' => 'VAT Adjustment Tax',],
		'UJ' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'UK' => ['label' => 'Tourism Tax (Derecho No Inmigrante)',],
		'UL' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'UN' => ['label' => 'Goods and Services Tax (GST)',],
		'UO' => ['label' => 'Goods and Services Tax (GST)',],
		'UP' => ['label' => 'Passenger Charge (Domestic/International)',],
		'UQ' => ['label' => 'Pre-Inspection Charge',],
		'UR' => ['label' => 'Departure Fee (International)',],
		'US' => ['label' => 'Transportation Tax (Domestic/International)',],
		'UT' => ['label' => 'Foreign Air Travel Tax (FATT)',],
		'UU' => ['label' => 'Airport Tax (Domestic/International) BSL',],
		'UV' => ['label' => 'Airport Departure Tax (Domestic)',],
		'UW' => ['label' => 'Value Added Tax (Domestic)',],
		'UX' => ['label' => 'Airport Authority Fee',],
		'UY' => ['label' => 'Ticket Sales Tax',],
		'UZ' => ['label' => 'Airport Departure Tax (Domestic/International)',],
		'VB' => ['label' => 'Airport Infrastructure Fee',],
		'VC' => ['label' => 'Government Tax',],
		'VD' => ['label' => 'Airport Service Charge (Domestic/International)',],
		'VE' => ['label' => 'Tourist Contribution Tax -(Domestic/International)',],
		'VF' => ['label' => 'National Aid Tax (Domestic/International)',],
		'VG' => ['label' => 'Airport Development Fee -International',],
		'VH' => ['label' => 'Development Tax (Domestic/International)',],
		'VJ' => ['label' => 'Special Facility Charge',],
		'VL' => ['label' => 'Departure Tax',],
		'VM' => ['label' => 'Passenger Service Charge (International)',],
		'VN' => ['label' => 'Sales Tax',],
		'VO' => ['label' => 'Passenger Service Charge',],
		'VP' => ['label' => 'Tourist Tax',],
		'VQ' => ['label' => 'Airport Service Charge (Domestic)',],
		'VR' => ['label' => 'Passenger Service Charge (International)',],
		'VS' => ['label' => 'Security Tax (Domestic/International)',],
		'VT' => ['label' => 'Security Charge (Domestic/International)',],
		'VU' => ['label' => 'Departure Feeand Security Charge (International)',],
		'VV' => ['label' => 'Noise Isolation Charge (Domestic/International)',],
		'VW' => ['label' => 'Facilitation Charge (International)',],
		'VX' => ['label' => 'Safety Tax(Domestic/International)',],
		'VY' => ['label' => 'Development Tax (International)',],
		'VZ' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'WA' => ['label' => 'IVA -Value Added Tax',],
		'WB' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'WC' => ['label' => 'Air Passenger Tax',],
		'WD' => ['label' => 'Travel Tax (International)',],
		'WG' => ['label' => 'Safety and Security Charge (Domestic/International)',],
		'WH' => ['label' => 'Terminal Use Fee (International)',],
		'WI' => ['label' => 'Passenger Service Charge',],
		'WJ' => ['label' => 'Security Charge (International)',],
		'WK' => ['label' => 'Passenger Facility Charge (Intl)',],
		'WL' => ['label' => 'Passenger Fee (International Transit)',],
		'WM' => ['label' => 'Airport Departure Tax (International)',],
		'WN' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'WO' => ['label' => 'Passenger Service Fee (Domestic/International)',],
		'WP' => ['label' => 'Passenger Terminal Facilities Charge (Domestic/International)',],
		'WQ' => ['label' => 'Passenger Security Charge(Domestic/International)',],
		'WS' => ['label' => 'Value Added Tax',],
		'WT' => ['label' => 'Security Fee (Domestic/International)',],
		'WU' => ['label' => 'Departure Tax (International)',],
		'WV' => ['label' => 'Airport Departure Tax (Domestic/International)',],
		'WW' => ['label' => 'Passenger Service Charge (International)',],
		'WX' => ['label' => 'Passenger Levy (Domestic)',],
		'WY' => ['label' => 'Passenger Services Charge -Intl',],
		'WZ' => ['label' => 'Safety Charge (International)',],
		'XA' => ['label' => 'APHIS User Fee -Passengers',],
		'XB' => ['label' => 'Value Added Tax (Domestic/International)',],
		'XC' => ['label' => 'Departure Tax (International)',],
		'XD' => ['label' => 'Airport Departure Tax -TUA (International)',],
		'XE' => ['label' => 'Airport Tax (International)',],
		'XF' => ['label' => 'Passenger Facility Charge',],	//  Capped at a maximum of $4.50 per departure, the Passenger Facility Charge is collected by and paid directly to the departure airport to fund FAA-approved airport projects that enhance safety, security, or capacity; reduce noise; or increase air carrier competition
		'XG' => ['label' => 'Goods and Services Tax (GST)',],
		'XH' => ['label' => 'Value Added Tax',],
		'XJ' => ['label' => 'Value Added Tax',],
		'XK' => ['label' => 'Ticket Issuance Fee',],
		'XL' => ['label' => 'Stamp Tax (Domestic/International/Excess Baggage)',],
		'XO' => ['label' => 'Transportation Tax -IVA (International)',],
		'XP' => ['label' => 'PTA Service Charge',],
		'XQ' => ['label' => 'Quebec Sales Tax',],
		'XR' => ['label' => 'Airport Tax (Domestic/International)',],
		'XS' => ['label' => 'Value Added Tax',],
		'XV' => ['label' => 'Airport Departure Tax -TUA (Domestic)',],
		'XW' => ['label' => 'Airport Tax (Domestic/International)',],
		'XX' => ['label' => 'Value Added Tax',],
		'XY' => ['label' => 'Immigration User Fee',],
		'YA' => ['label' => 'Passenger Charge(Domestic/International)',],
		'YB' => ['label' => 'Value Added Tax',],
		'YC' => ['label' => 'Customs User Fee',],
		'YE' => ['label' => 'Tourism Tax',],
		'YF' => ['label' => 'Value Added Tax',],
		'YG' => ['label' => 'Security Tax(Domestic/International)',],
		'YH' => ['label' => 'Embarkation Tax (TEBA)',],
		'YK' => ['label' => 'Airport Passenger Charge -(Domestic/International)',],
		'YL' => ['label' => 'Ticket IssuanceFee (Domestic/International)',],
		'YN' => ['label' => 'Luxury Tax (Domestic/International)',],
		'YO' => ['label' => 'Air Passenger Duty (APD), (Domestic/International)',],
		'YP' => ['label' => 'Passenger Service Charge -(Domestic/International)',],
		'YQ' => ['label' => 'Airline Fuel and Insurance Surcharge',],
		'YR' => ['label' => 'Airline Fuel and Insurance Surcharge',],
		'YS' => ['label' => 'Sales Tax (Domestic/International) = I.V.A.',],
		'ZA' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'ZB' => ['label' => 'Passenger Service Charge (International)',],
		'ZC' => ['label' => 'Passenger Service Charge (International)',],
		'ZD' => ['label' => 'Passenger Service Charge (International)',],
		'ZE' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'ZG' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'ZH' => ['label' => 'Passenger Service Charge (International)',],
		'ZI' => ['label' => 'Passenger Service Charge (International)',],
		'ZJ' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'ZL' => ['label' => 'Fiscal Stamp Tax (Domestic/International)',],
		'ZM' => ['label' => 'Sales Tax (Domestic)',],
		'ZN' => ['label' => 'Passenger Charge (Domestic/International)',],
		'ZO' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'ZP' => ['label' => 'Flight Segment Tax (Domestic)',],
		'ZQ' => ['label' => 'Airport Facility Charge (International)',],
		'ZS' => ['label' => 'Value Added Tax',],
		'ZT' => ['label' => 'Aeronautical Development Charge',],
		'ZU' => ['label' => 'Passenger Fee (Keflavik)',],
		'ZV' => ['label' => 'Value Added Tax',],
		'ZX' => ['label' => 'Passenger Fee (Transfer)',],
		'ZY' => ['label' => 'Passenger Service Charge (Domestic/International)',],
		'ZZ' => ['label' => 'Billing and Settlement Plan Pseudo Tax Code',],
	];

	/**
	 * Fill in the TAXC_ tag in the specified $TAXFLD field
	 * @param array $TAXFLD
	 * @return array
	 */
	static public function extractTaxNameFromCode($TAXFLD)
	{
		if($TAXFLD){
			foreach($TAXFLD as $idx=>$TAX){
				$TAX['TAXC'] = rtrim((string)$TAX['TAXC']);
				$TAXFLD[$idx]['TAXC_'] = self::$TAXC[$TAX['TAXC']];
			}
		}

		return $TAXFLD;
	}

	/**
	 * Fill in the TAXA_ tag in the specified $TAXFLD field
	 * @param array $TAXFLD
	 * @return array
	 */
	static public function fillTAXA($TAXFLD)
	{
		if ($TAXFLD) {
			foreach ($TAXFLD as $k=>$v) {
				/**
				 * in some cases, it seems like this could be a literal.
				 * @see UA/KY/2009-01-15_120710_192.168.93.5_1_@1500168.01
				 * @see TD-5680, PH/NorthStar PH/20190701 093211 01 01.FluX.AIR00943.Txt
				 */
				$a = trim($v['TAXA']);
				if (!is_numeric($a)) {
					$v['TAXA'] = null;
					$v['TAXA_'] = $a;
				}
				else {
					$v['TAXA'] = (float)$a;
				}
				$TAXFLD[$k] = $v;
			}
		}

		return $TAXFLD;
	}

	/**
	 * Process the AIRIATA fields
	 * @param Array $tree
	 * @param string $key
	 */
	static public function extractAIRIATA($tree, $key)
	{
		$v = rtrim($tree[$key]);
		$tree[$key] = 				$v;
		$tree["{$key}_IATA"] = 		(strlen($v)==8?$v:null);
		$tree["{$key}_airline"] = 	(strlen($v)==3?$v:null);

		return $tree;
	}


	/**
	 * Remove empty items from the array, positioned at the end of the array
	 * @param array $arr
	 * @return array
	 */
	public static function rtrimArr($arr)
	{
		if(!$arr){
			return $arr;
		}
		$rev = array_reverse($arr, true);
		$new = [];

		$limitFound = false;
		foreach($rev as $k=>$v){
			if($limitFound || $v){
				$new[$k] = $v;
				$limitFound = true;
			}
		}

		return array_reverse($new);
	}


	/**
	 * Remove empty items from the array, positioned at the end of the array, recursivelly
	 * @param array $arr
	 * @param int $checkDepth
	 * @return multitype:
	 */
	public static function rtrimArrDeep(array $arr, $checkDepth=PHP_INT_MAX)
	{
		if (!$arr) {
			return $arr;
		}

		$reversedArray = array_reverse($arr, true);
		$finalResult = [];

		$limitFound = false;
		foreach($reversedArray as $key=>$value){
			$hasData = self::arrayHasData_rec($value, $checkDepth);

			if($limitFound || $hasData){	// add this to the final array
				$finalResult[$key] = $value;
				$limitFound = true;
			}
		}

		return array_reverse($finalResult);
	}


	/**
	 * Internal call
	 * @return multitype:
	 */
	protected static function arrayHasData_rec($arr, $depth=2)
	{
		$hasData = false;
		if($arr){
			$hasData = true;

			if(is_array($arr)){
				$hasData = false;
				foreach($arr as $v){
					if($depth>0 && $v){
						$hasData = self::arrayHasData_rec($v, $depth-1);
					}

					if($hasData){
						return true;
					}
				}
			}
		}

		return $hasData;
	}
}
