<?php
namespace App\Galileo\LineParser\Types;

/**
 * Blocks with constant values
 * @author Lucian Sirbu
 *
 */
class OrderedComposer extends \App\Utils\BaseParser\TextParser\BlockRegexpAbstract
{
	protected $cachedObjects = [];

	public function  __construct($options = [], $parent = null)
	{
		$regexpArr = [];
		foreach ($options['children'] as $child) {
			$regexp = "(__HEADER__(?P<__NAME__>__MATCHER____LENGTHS__))";
			if(!$child['req']) {
				$regexp.="?";
			}

			$replacements = [];

			$replacements['__HEADER__'] = 	preg_quote((string)$child['header'], "/");
			$replacements['__NAME__'] = 	preg_quote((string)$child['key'], "/");

			if (is_array($child['len']) && ($child['len'][0] || $child['len'][1])) {
				$replacements['__LENGTHS__'] = sprintf("{%d,%d}", (int)$child['len'][0], (int)$child['len'][1]);
			}
			elseif ($child['len']) {
				$replacements['__LENGTHS__'] = sprintf("{%d}", (int)$child['len']);
			}
			else {
				if($child['req']) {
					$replacements['__LENGTHS__'] = "+";
				}
				else {
					$replacements['__LENGTHS__'] = "*";
				}
			}

			switch($child['type']) {
				case 'Letters':
					$replacements['__MATCHER__'] = "[a-zA-Z\s]";
				break;
				case 'Integer':
					$replacements['__MATCHER__'] = "[0-9]";
				break;

				case 'Date':
					$replacements['__MATCHER__'] = "[0-9]{2}[A-Z]{3}[0-9]{2}";
					$replacements['__LENGTHS__'] = null;
				break;

				case 'Currency':
					$replacements['__MATCHER__'] = "[A-Z]{3}";
					$replacements['__LENGTHS__'] = null;
				break;


				case 'StringRaw':
				case 'StringTrim':
					$replacements['__MATCHER__'] = ".";
				break;

				case 'Tax':
					$possibleMatchesArr = [
						// fmt: '           ','000000000', match only spaces
						sprintf("([\s]%s)", $replacements['__LENGTHS__']),

						// fmt: 'EXEMPT   YQ'
						sprintf("(EXEMPT[\s]{%d}[A-Z0-9]{2})", ($child['len']?($child['len'] - 2 - strlen('EXEMPT')):'*')),

						// fmt: '      123YQ' & '    21.23YQ' & '0000021.23YQ'
						sprintf("((?=[\s0-9])[\s0-9\.]{%d}[A-Z0-9]{2})", ($child['len']?($child['len']-2):'*')),
						
						// fmt: '', match blank string, any length
						sprintf("([\s]{0,%s})", (int)$child['len']),
					];
					$replacements['__MATCHER__'] = "(" . implode("|", $possibleMatchesArr) . ")";
					$replacements['__LENGTHS__'] = null;
				break;

				default:
					$replacements['__MATCHER__'] = ".";
			}

			$reps = $child['rep'];
			if (!$reps) {
				$reps = [1, 1];
			}

			if ($reps[1]!==1) {
				$name = $replacements['__NAME__'];
				for ($i=0; $i<$reps[1]; $i++) {
					$replacements['__NAME__'] = sprintf("%s%02d", $name, $i+1);
					$regexpArr[] = str_replace(array_keys($replacements), array_values($replacements), $regexp);
				}
			}
			else {
				$regexpArr[] = str_replace(array_keys($replacements), array_values($replacements), $regexp);
			}
		}

		$this->extractRegexp = "/^".implode("", $regexpArr)."/";

		parent::__construct($options, $parent);
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Utils\BaseParser\TextParser\BlockRegexpAbstract::isValid()
	 */
	public function isValid()
	{
		return (bool)$this->rawData;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Utils\BaseParser\TextParser\BlockRegexpAbstract::_extract()
	 */
	protected function _extract(\App\Utils\BaseParser\TextParser\ExtractedBlock $ret, $originalRawData)
	{
		$m = $this->safeMatch($this->extractRegexp, $originalRawData);

		$matchedString = $m->matches[0];
		$extractedData = array_diff_key($m->matches, range(0, count($m->matches)));	// remove numeric keys
		// because of a PHP bug, preg_match will return inexistent keys, with a blank value. Remove them now
		$extractedData = array_filter($extractedData);

		foreach ($this->options['children'] as $child) {
			$k = $child['key'];

			if (array_key_exists($k, $extractedData)) {
				switch ($child['type']) {
					case 'Letters':
					case 'StringTrim':
						$extractedData[$k] = rtrim($extractedData[$k]);
					break;

					case 'Date':
						$m = $this->safeMatch("/^(?P<DD>[0-9]{2})(?P<MMM>[A-Z]{3})(?P<YY>[0-9]{2})$/", $extractedData[$k]);

						if (!$this->cachedObjects['Date']) {
							$this->cachedObjects['Date'] = new \App\Utils\BaseParser\TextParser\Types\Date(['fmt' => 'DDMMMYY']);
						}
						$extractedData[$k] = $this->cachedObjects['Date']->getDate($m->matches, ['fmt' => 'DDMMMYY'], null);
					break;

					case 'Integer':
						$extractedData[$k] = (int)ltrim($extractedData[$k], '0');
					break;

					case 'Tax':
						$tax = 		substr($extractedData[$k], -2);
						$amount = 	ltrim(rtrim(substr($extractedData[$k], 0, -2), ' '), '0');

						$extractedData[$k] = [];
						$extractedData[$k]['exempt'] = false;
						if ($amount=='EXEMPT') {
							$extractedData[$k]['amount'] = 0.0;
							$extractedData[$k]['exempt'] = true;
						}
						else {
							$extractedData[$k]['amount'] = (float)$amount;
						}
						$extractedData[$k]['tax'] = ltrim($tax);
					break;
				}
			}
		}
		$this->extractedData = 	$extractedData;
		$ret->extractedData = 	$extractedData;

		$ret->remainingGlobalData = substr($originalRawData, strlen($matchedString));

		\Engine\Debug\ParserCallTrace\ParserCallTrace::getInstance()->logInput([
			'regexp' => htmlentities($this->extractRegexp),
		], 'regexp');

		return $ret;
	}

}
