<?php
namespace App\Apollo\FileParser;

class MIR extends \App\Utils\BaseParser\TextParser\FileParser\ParserForIndividualLines {
    protected $extractRegexp = "/^(?P<rawData>T5.+[\s])/";

    /**
     * The line structure.
     *
     */
    protected $children = [
            ['key' => 'header',  'startsWith' => 'Header_Line1', 'endsWith' => 'LineBlank', 'children' => [
                    ['key' => 'line1',  'type' => 'Header_Line1', 'req' => true],
                    ['key' => 'line2',  'type' => 'Header_Line2', 'req' => true],
                    ['key' => 'line3',  'type' => 'Header_Line3', 'req' => true],
                    ['key' => 'line4',  'type' => 'Header_Line4', 'req' => true],
                    ['key' => 'line5',  'type' => 'Header_Line5', 'req' => true],
			]],

    		['key'=>'A00',        'startsWith'=>'Data_A00', 'endsWith'=>'LineBlank', 'children'=> [
					['key'=>'A00',              'type'=>'Data_A00',],
					['key'=>'A00continuation',  'type'=>'StringRaw', 'rep'=> [0, 64],],
			]],

            ['key' => 'A02',        'startsWith' => 'Data_A02', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A02',            'type' => 'Data_A02'],
                    ['key' => 'A02Details',     'type' => 'Data_A02Details'],
			]],

            ['key' => 'A03',        'startsWith' => 'Data_A03', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A03',  'type' => 'Data_A03'],
			]],

            ['key' => 'A04',        'startsWith' => 'Data_A04', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A04',  'type' => 'Data_A04'],
			]],

    		['key' => 'A06',        'startsWith' => 'Data_A06', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A06',       'type' => 'Data_A06'],
                    ['key' => 'A06COG',    'type' => 'Data_A06COG'],
			]],

            ['key' => 'A07',        'startsWith' => 'Data_A07', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A07',           'type' => 'Data_A07'],
                    ['key' => 'A07Details',    'type' => 'Data_A07Details'],
			]],

            ['key' => 'A08',        'startsWith' => 'Data_A08', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A08',           'type' => 'Data_A08'],
			]],

            ['key' => 'A09',        'startsWith' => 'Data_A09', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A09',           'type' => 'Data_A09'],
                    ['key' => 'A09Details01',  'type' => 'Data_A09Details01'],
                    ['key' => 'A09Details02',  'type' => 'Data_A09Details02'],
                    ['key' => 'A09Details03',  'type' => 'Data_A09Details03'],
                    ['key' => 'A09Details04',  'type' => 'Data_A09Details04'],
            		['key' => 'A09Details05',  'type' => 'Data_A09Details05'],
			]],

            ['key' => 'A10',        'startsWith' => 'Data_A10', 'endsWith' => 'LineBlank', 'children' => [
                    ['key' => 'A10',           'type' => 'Data_A10'],
                    ['key' => 'A10Details01',  'type' => 'Data_A10Details01'],
                    ['key' => 'A10Details02',  'type' => 'Data_A10Details02'],
                    ['key' => 'A10Details03',  'type' => 'Data_A10Details03'],
			]],

            ['key' => 'A11',        'startsWith' => 'Data_A11', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A11',  'type' => 'Data_A11'],
			]],

            ['key' => 'A12',        'startsWith' => 'Data_A12', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A12',  'type' => 'Data_A12'],
			]],

            ['key' => 'A13',        'startsWith' => 'Data_A13', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A13',  'type' => 'Data_A13'],
			]],

            ['key' => 'A14',        'startsWith' => 'Data_A14', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A14',  'type' => 'Data_A14'],
			]],

            ['key' => 'A15',        'startsWith' => 'Data_A15', 'endsWith' => 'LineBlank', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A15',  'type' => 'Data_A15'],
			]],

            // A16 lines (services)

            // hotel

            // TUR?
            // A166 & A165 are identical, but i had to define them twice for the parser
            ['key' => 'A166',  'startsWith' => 'Data_A166', 'rep' => [0, 64], 'children' => [
                    ['key' => 'A166',      'type' => 'Data_A166'],
                    ['key' => 'A166OD',    'type' => 'Data_A166OD'],
                    ['key' => 'A166FF',    'type' => 'Data_A166FF'],
                    ['key' => 'A166CF',    'type' => 'Data_A166CF'],
                    ['key' => 'A166UI',    'type' => 'Data_A166UI', 'rep' => [0, 64],],
			]],

            /////////////////////////////

            ['key' => 'blank',    'type' => 'LineBlank',  'req' => false],

            ['key' => 'A19',        'startsWith' => 'Data_A19', 'endsWith' => 'LineBlank', 'children' => [
                    ['key' => 'A19',     'type' => 'Data_A19'],
                    ['key' => 'A19ST',   'type' => 'Data_A19ST'],
			]],

            ['key' => 'A20',        'startsWith' => 'Data_A20', 'rep' => [0, 64], 'endsWith' => 'LineBlank', 'children' => [
                ['key' => 'A20',     'type' => 'Data_A20'],
                ['key' => 'A20FT',   'type' => 'Data_A20FT'],
			]],

            ['key' => 'A23',  'startsWith' => 'Data_A23', 'endsWith' => 'LineBlank', 'children' => [
                    ['key' => 'A23',     'type' => 'Data_A23'],
                    ['key' => 'A23TI',   'type' => 'Data_A23TI'],
                    ['key' => 'A23BF',   'type' => 'Data_A23BF'],
            	    ['key' => 'A23XF',   'type' => 'Data_A23XF'],
                    ['key' => 'A23IT',   'type' => 'Data_A23IT'],
                    ['key' => 'A23AU',   'type' => 'Data_A23AU'],
                    ['key' => 'A23CR',   'type' => 'Data_A23CR'],
                    ['key' => 'A23PF',   'type' => 'Data_A23PF'],
                    ['key' => 'A23RA',   'type' => 'Data_A23RA'],
                    ['key' => 'A23FP1',  'type' => 'Data_A23FP1'],
                    ['key' => 'A23FP2',  'type' => 'Data_A23FP2'],
                    ['key' => 'A23FP3',  'type' => 'Data_A23FP3'],
			]],

            ['key' => 'blank',    'type' => 'LineBlank',  'req' => false],
            ['key' => 'blank',    'type' => 'LineBlank',  'req' => false],
	];

    /**
     * (non-PHPdoc).
     *
     * @see \App\Utils\BaseParser\TextParser\BlockAbstract::createObject()
     *
     * @param mixed $type
     * @param mixed $options
     * @param mixed $self
     */
    public function createObject($type, $options, $self) {
        $options['req'] = true;
        $obj = null;

        $class = sprintf("\App\Apollo\LineParser\Types\%s", $type);
        if (class_exists($class)) {
            $obj = new $class($options, $self);
        }

        if (!$obj) {
            $obj = parent::createObject($type, $options, $self);
        }

        $obj->setHelper($this->lineHelper);

        return $obj;
    }

    /**
     * Get the unique file id.
     *
     * @return string
     */
    public function getFileId() {
        $ID = sprintf('%s%05d%s',
            \Engine\DateTime::createFromIsoDate($this->extractedData['header']['line1']['T50CRE']['T50DTE'])->format('Ymd'),
            $this->extractedData['header']['line1']['T50SEQ'],
            $this->extractedData['header']['line2']['T50RCL']
        );

        return $ID;
    }

    /**
     * (non-PHPdoc).
     *
     * @see \App\Utils\BaseParser\TextParser\BlockAbstract::postExtract()
     */
    protected function postExtract(\App\Utils\BaseParser\TextParser\ExtractedBlock $ret) {
        // perform some post-parsing file validations
        if ($ret->extractedData['A02'] && $ret->extractedData['header']['line5']['T50PGN'] && $ret->extractedData['header']['line5']['T50PGN'] != count($ret->extractedData['A02'])) {
            $this->getMessagesCollector()->addWarning(sprintf("Invalid file. T50PGN doesn't match number of A02 lines, (%d vs %d)", $ret->extractedData['header']['line5']['T50PGN'], count($ret->extractedData['A02']))); // TODO: [cleanMsgs-transactionGDSs] refactor this from GDSs
        }

        if ($ret->extractedData['A07'] && $ret->extractedData['header']['line5']['T50FBN'] && $ret->extractedData['header']['line5']['T50FBN'] != count($ret->extractedData['A07'])) {
            throw new \App\Utils\BaseParser\TextParser\FileParser\Exception\General(sprintf("Invalid file. T50FBN doesn't match number of A07 lines, (%d vs %d)", $ret->extractedData['header']['line5']['T50FBN'], count($ret->extractedData['A07'])));
        }

    	if ($ret->extractedData['header']['line1']['T50SPC_']!='APOLLO') {
			throw new \App\Utils\BaseParser\TextParser\FileParser\Exception\General(sprintf("Invalid file. This is not an Apollo file"));
		}

        if ($ret->extractedData['A07']) {
            $T50CUR = $ret->extractedData['header']['line3']['T50CUR'];
            $totalEquivalentPrice = 0.0;
            $canValidate = true;

            foreach ($ret->extractedData['A02'] as $a02) {
                $a07 = null;
                foreach ($ret->extractedData['A07'] as $v) {
                    if ($a02['A02']['A02FIN'] == $v['A07']['A07FSI']) {
                        $a07 = $v;
                        break;
                    }
                }

                if ($a07) {
                    if ($T50CUR == $a07['A07']['A07CRE']) {
                        $totalEquivalentPrice += $a07['A07']['A07EQV'];
                    } elseif ($T50CUR == $a07['A07']['A07CRB']) {
                        $totalEquivalentPrice += $a07['A07']['A07TBF'];
                    } else {
                        $this->getMessagesCollector()->addWarning(sprintf('A07 contains lines with a different currency than the one specified in T50CUR. Cannot validate the total price for this file')); // TODO: [cleanMsgs-transactionGDSs] refactor this from GDSs
                        $canValidate = false;
                    }
                } else {
                    $this->getMessagesCollector()->addWarning(sprintf('A02 contains a passenger without a price line(A07) associated. Cannot validate prices in this file')); // TODO: [cleanMsgs-transactionGDSs] refactor this from GDSs
                    $canValidate = false;
                }
            }

            if ($canValidate && $ret->extractedData['header']['line3']['T50FAR_'] != $totalEquivalentPrice) {
                $this->getMessagesCollector()->addWarning(sprintf("Possible invalid file. T50FAR doesn't match the total amount of all passengers in this file(%.2f vs %.2f %s)", $ret->extractedData['header']['line3']['T50FAR_'], $totalEquivalentPrice, $T50CUR)); // TODO: [cleanMsgs-transactionGDSs] refactor this from GDSs
            }
        }

        return parent::postExtract($ret);
    }

    /**
	 * Destroy CC information from the current file
	 * Is can remove by doing str_replace over each encountered line
	 *
	 * @param array $regexpReplacements
	 * @return array
	 */
	public function destroyCCInformationAndWriteInto($filePath, ?\App\Utils\BaseParser\TextCleaner\TextCleaner $textCleaner = null)
	{
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();
		if (!$CFG['pciDss']['compliant']) {
			return [];
		}

		$hitLines = [];

		$contents = $this->rawData;
		$parsedStructure = $this->getExtractedData();
		$textCleaner = ($textCleaner?:new \App\Utils\BaseParser\TextCleaner\TextCleaner());

		// remove from associated I lines
		if ($parsedStructure['A11']) {
			foreach ($parsedStructure['A11'] as $A11) {
				if ($A11['A11']['A11TYP']=='CC' && $A11['A11']['A11CCC'] && $A11['A11']['A11CCN']) {
					$textCleaner->appendRule(new \App\Utils\BaseParser\TextCleaner\RuleLineRegexpAndTextReplacement(
						sprintf("^A11.*%s%s", preg_quote($A11['A11']['A11CCC'], '/'), preg_quote($A11['A11']['A11CCN'], '/')),
						sprintf("%s%s", $A11['A11']['A11CCC'], $A11['A11']['A11CCN']),
						sprintf("%s%s", $A11['A11']['A11CCC'], \App\Utils\CreditCard\NumberDetails::create((string)$A11['A11']['A11CCN'])->getMaskedNumber())
					));
				}
			}
		}

		if ($textCleaner->hasRules()) {
			$contentArr = explode("\n", $contents);
			$originalContentsArr = $contentArr;

			list($contentArr, , $hitLines) = $textCleaner->simplifyRules()->cleanupArrRaw($contentArr);

			// NOTE: we could make sure all regexps applied at least once. If not, then some CC's might have gotten skipped

			// write the file back to disk, if any differences were found. We might have just parsed a file that was already masked, so no real changes were done
			if ($contentArr!=$originalContentsArr) {
				\Engine\File::create($filePath, implode("\n", $contentArr));
			}
		}

		return array_keys($hitLines);
	}
}
