<?php

namespace App\Config;

class ServiceClassCodeRules extends XmlDynamicRecordsAbstract
{

	/**
	 * Stores the configuration file (relative to the "files/config/" dir). For config files stored
	 * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml).
	 * @var String
	 */
	protected $fileName = CONFIG_FILE_SERVICECLASSCODERULES;


	/**
	 * The attribute stores the standard classes list
	 * @var array
	 */
	protected $standardList = null;


	/**
	 * Get standard classes
	 * @return Array
	 */
	public function getStandardList()
	{
		// get the value
		$return = null;
		if ($this->constructType=='instance') {
			$data = $this->getAll_cachedData();
			if ($data['standardList']!==null) {  // file not exists
				$return = $data['standardList'];
			} else {
				$return = $this->standardList;
			}
		}
		elseif ($this->constructType=='admin') {
			$return = $this->standardList;
		}
		// return the value
		return $return;
	}


	/**
	 * Set standard classes
	 * @param Array $vars
	 * @throws \Exception
	 */
	public function setStandardList($vars)
	{
		// check constructor type
		if ($this->constructType!='admin') throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `admin`.");
		// check inputs
		if (!is_array($vars)) throw new \Exception("You did not setAll() a correct list of elements - the parameter is not an array.");

		// (re)set a list of keys
		$this->standardList=$vars;

		// update the changed flag
		$this->changedFlag=true;
	}


	protected function loadAdminData()
	{
		parent::loadAdminData();

		// loads standard classes
		if ($this->standardList===null) {
			$this->standardList = static::getInstance()->getStandardList();
		}
	}


	protected function constructAdmin()
	{

		parent::constructAdmin();

		global $S;
		$className=get_called_class();

		if (isset($S['admin']['configApp'][$className]['standardList'])) {
			$this->standardList = $S['admin']['configApp'][$className]['standardList'];
		}

		$S['admin']['configApp'][$className]['standardList'] = &$this->standardList;

	}


	protected function getAll_rawData_extractDataFromFile(\SimpleXMLElement $xml)
	{

		$return = parent::getAll_rawData_extractDataFromFile($xml);

		$return['standardList'] = $this->getAll_rawData_extractDataFromFile_standardList($xml);

		if (!is_array($return['standardList'])) throw new \Exception("The class ".get_called_class()." is not correctly defined - the method `getAll_rawData_extractDataFromFile_standardList` should return an array.");

		return $return;

	}

	protected function getAll_rawData_extractDataFromFile_standardList(\SimpleXMLElement $xml)
	{

		// store standard classes
		$return = [];
		if ($xml->standard->class) {
			foreach($xml->standard->class as $class) {
				$return[(String)$class['classCode']] = (String)$class['className'];
			}
		}

		return $return;

	}


	/**
	 * {@inheritDoc}
	 * @see \App\Config\XmlBasicAbstract::getAll_rawData_fileNotExists()
	 */
	protected function getAll_rawData_fileNotExists()
	{
		/**
		 * This is the old $CFG['amadeusTicketClass'], not sure how that got populated there, probably from RO/AMA
		 * These codes are specific to each airline according to Diana. The RU market might need these to be configurable per airline
		 * The code in the GDS systems are 2 letters, as in 'A ', 'B ', 'C', 'D ', but the below list is trimmed-down
		 * @var array
		 */
		$this->standardList = [
			'A' => 'first',
			'B' => 'economy',
			'C' => 'business',
			'D' => 'business',
			'E' => 'economy',
			'F' => 'first',
			'G' => 'economy',
			'H' => 'economy',
			'I' => 'business',
			'J' => 'business',
			'K' => 'economy',
			'L' => 'economy',
			'M' => 'economy',
			'N' => 'economy',
			'O' => 'economy',
			'P' => 'first',
			'Q' => 'economy',
			'R' => 'economy',
			'S' => 'economy',
			'T' => 'economy',
			'U' => 'economy',
			'V' => 'economy',
			'W' => 'economy',
			'X' => 'economy',
			'Y' => 'economy',
			'Z' => 'business',
		];

		// return exceptions (none)
		return [];
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlDynamicRecordsAbstract::getAll_rawData_extractDataFromFile_list()
	 */
	protected function getAll_rawData_extractDataFromFile_list(\SimpleXMLElement $xml)
	{
		// return exceptions
		$return=[];

		if ($xml->exceptions->exception) {
			foreach($xml->exceptions->exception  as $classCodeRule) {

				$return[(String)$classCodeRule['classCode']."_".(String)$classCodeRule['supplierCode']] = [
					"classCode"		=>	(String)$classCodeRule['classCode'],
					"supplierCode"	=>	(String)$classCodeRule['supplierCode'],
					"className"		=>	(String)$classCodeRule['className'],
				];

			}
		}

		return $return;
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlDynamicRecordsAbstract::getAll_rawData_extractDataFromFile_default()
	 */
	protected function getAll_rawData_extractDataFromFile_default(\SimpleXMLElement $xml)
	{
		return '';
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlDynamicRecordsAbstract::getAll_rawData_extractDataFromFile_mandatory()
	 */
	protected function getAll_rawData_extractDataFromFile_mandatory(\SimpleXMLElement $xml)
	{
		return true;
	}

	protected function itemCheck($code, $itemDetails)
	{
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();

		// check code
		if (!$code) $this->addErrorMessage('The identifier for class code was not defined.');

		// check if there are any details for the service class code
		if (!$itemDetails) $this->addErrorMessage('The service class code details was not defined.');

		// validate 'code'
		if (!$itemDetails['classCode']) $this->addErrorMessage('The class code was not defined.');

		if (mb_strlen($itemDetails['classCode'])>2) $this->addErrorMessage('The class code length must be smaller or equal to 2 characters.');

		// validate 'supplier'
		if (!$itemDetails['supplierCode']) $this->addErrorMessage('The supplier code does not exist.');

		if (!$itemDetails['className']) $this->addErrorMessage('The service class name was not defined.');

		// check for duplicates based on same code and supplier
		if (!in_array($itemDetails['className'], $CFG['travel']['transportSegmentClassNames'])) {
			$this->addErrorMessage('The service class name is an unconfigured travel value.');
		}

	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\BaseAbstract::save_check()
	 */
	protected function save_check()
	{
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();

        // validate standard classes
		if (count($this->standardList)!=26) {
			$this->addErrorMessage("Not all standard classes are configured.");
		}

		foreach ($this->standardList as $classCode=>$className) {
		    $matches = [];
		    preg_match("/^[A-Z]{1}$/", $classCode, $matches);
		    if (!$matches) {
				$this->addErrorMessage(sprintf("Class code `%s` is not a valid letter.", $classCode));
			}
			if (!in_array($className, $CFG['travel']['transportSegmentClassNames'])) {
				$this->addErrorMessage(sprintf("Class name `%s` is invalid.", $className));
			}
		}

	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlBasicAbstract::save_write_do_getXml()
	 */
	protected function save_write_do_getXml()
	{
		$xml=simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?><serviceClassCodeRules />');

		$standardXml = $xml->addChild('standard');
		if ($this->standardList) {
			foreach ($this->standardList as $classCode=>$className) {
				$thisCurrCodeXml = $standardXml->addChild('class', '');
				$thisCurrCodeXml['classCode'] = $classCode;
				$thisCurrCodeXml['className'] = $className;
			}
		}

		$exceptionsXml = $xml->addChild('exceptions');
		foreach ($this->itemsList as $currCode => $currCodeDetails) {
			$thisCurrCodeXml = $exceptionsXml->addChild('exception', '');
			$thisCurrCodeXml['className'] = $currCodeDetails['className'];
			$thisCurrCodeXml['supplierCode'] = $currCodeDetails['supplierCode'];
			$thisCurrCodeXml['classCode'] = $currCodeDetails['classCode'];
		}

		// return the xml content of the current object
		return $xml;

	}

	/**
	 * {@inheritDoc}
	 * @see \App\Config\XmlDynamicRecordsAbstract::reset()
	 */
	public function reset()
	{
		$this->standardList=null;
		parent::reset();
	}


	/**
	 * Convert the given class code to a string - searching first in exceptions and then in standard list
	 * @param string $classCode
	 * @param string $airlineCode
	 * @return string|NULL
	 */
	public function convertClassCodeToName($classCode, $airlineCode=null)
	{
		// check constructor type
		if ($this->constructType!='instance') throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `instance`.");

		$classCode = trim((string)$classCode);
		if (!$classCode) return null;

		if ($airlineCode) {
			$serviceRule = $this->get($classCode."_".$airlineCode);
			if ($serviceRule['className']) {
			    return $serviceRule['className'];
			}
		}

		// if the airline is not specified, or exception is not found, use the old logic
		$standardList = $this->getStandardList();
		return $standardList[$classCode];
	}



}
