<?php

namespace App\Config;

/**
 * The class is used for managing VAT details for invoice row types: 'price', 'commission', 'discount', 'serviceFee', 'tax', 'penalty', 'advance'
 * @static \App\Config\Services_Calculations_InvoiceVat getInstance()
 */
class Services_Calculations_InvoiceVat extends XmlBasicAbstract {

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


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlBasicAbstract::getAll_rawData_extractDataFromFile()
	 */
	protected function getAll_rawData_extractDataFromFile(\SimpleXMLElement $xml)
	{

		$return = [];

		// loop through each service
		foreach($xml->service as $serviceDetails) {

			// scan each calculation type
			foreach ($serviceDetails as $vatDetails) {

				$codeCalculation = (String)$serviceDetails['code'].'_'.(String)$vatDetails['location'].'_'.(string)$vatDetails['code'];
				$invoiceDetailsList = [];

				// scan each invoice row
				foreach ( ['price', 'commission', 'discount', 'serviceFee', 'tax', 'penalty', 'advance'] as $invoiceRowVat) {

					$componentVatDetails = $vatDetails->$invoiceRowVat;

					// write the details (vatPercent, vatText, vatRemark, hidden) about invoice row
					$invoiceDetailsList[$invoiceRowVat] = [
						'vatPercent' => (float)$componentVatDetails['vatPercent'],
						'vatText' => (string)$componentVatDetails['vatText'],
						'vatRemark' => (string)$componentVatDetails['vatRemark'],
						'hidden' => ((string)$componentVatDetails['hidden']=='yes')
					];
				}
				$return[$codeCalculation] = $invoiceDetailsList;
			}
		}

		// return linear list with  VAT percent and if this is included for every row type
		return $return;
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\BaseAbstract::save_check()
	 */
	protected function save_check()
	{

		global $_LANG;
		// scan each calculation type from the session
		foreach (Services_Calculations::getAdmin()->getAll() as $calculationCode => $calculationDetails) {

			// check for those calculation that are not removed
			if ( !$calculationDetails['deleted'] ) {

				$serviceCode=$calculationDetails['serviceCode'];

				// check tva value for price and tax to be -1 or [0,100]
				foreach (['price', 'tax'] as $invoiceRow) {
					$vatPercent = $this->itemsList[$calculationCode][$invoiceRow]['vatPercent'];
					if ( !( is_numeric($vatPercent) and ( $vatPercent==-1 or ($vatPercent>=0 and $vatPercent<=100) ) ) ) {
						$this->addErrorMessage(sprintf('When setting service invoice details, the vat percent value for the `%s` must be a value between 0 and 100  or -1 for calculation type `%s` in service `%s` at location `%s` ', $invoiceRow, $calculationDetails['name'], Services_Basic::getInstance()->getServiceName($serviceCode), $_LANG['locations']['countriesCriteria']['long'][$calculationDetails['location']]));
					}
				}

				// check vat percent value for the other rows of invoice to be between [0,100]
				foreach (['commission', 'discount', 'serviceFee', 'penalty', 'advance'] as $invoiceRowVat) {
					$vatPercent = $this->itemsList[$calculationCode][$invoiceRowVat]['vatPercent'];
					if (!is_numeric($vatPercent) or $vatPercent<0 or $vatPercent>100) {
						$this->addErrorMessage(sprintf('When setting service invoice details, the vat percent value for the `%s` must be a value between 0 and 100 for calculation type `%s` in service `%s` at location `%s` ', $invoiceRowVat, $calculationDetails['name'], Services_Basic::getInstance()->getServiceName($serviceCode), $_LANG['locations']['countriesCriteria']['long'][$calculationDetails['location']]));
					}
				}

				// check vat remark length
				foreach (['price', 'commission', 'discount', 'serviceFee', 'tax', 'penalty', 'advance'] as $component) {
					$vatRm = $this->itemsList[$calculationCode][$component]['vatRemark'];
					if (mb_strlen($vatRm)>300) {
						$this->addErrorMessage(sprintf('The invoice row VAT remarks must have less than 300 chars for calculation type `%s` in service `%s` at location `%s` ', $calculationDetails['name'], Services_Basic::getInstance()->getServiceName($serviceCode), $_LANG['locations']['countriesCriteria']['long'][$calculationDetails['location']]));
					}
				}

				// check allow hide and hidden for row price
				if ($this->itemsList[$calculationCode]['price']['hidden']) {
					$this->addErrorMessage(sprintf('When setting service invoice details, the price row must be visible for calculation type `%s` in service `%s` at location `%s` ', $calculationDetails['name'], Services_Basic::getInstance()->getServiceName($serviceCode), $_LANG['locations']['countriesCriteria']['long'][$calculationDetails['location']]));
				}

				// check allow hide and hidden for row commission
				if ($this->itemsList[$calculationCode]['commission']['hidden']) {
					$this->addErrorMessage(sprintf('When setting service invoice details, the commission row must be visible for calculation type `%s` in service `%s` at location `%s` ', $calculationDetails['name'], Services_Basic::getInstance()->getServiceName($serviceCode), $_LANG['locations']['countriesCriteria']['long'][$calculationDetails['location']]));
				}
			}
		}
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlBasicAbstract::save_write_do_getXml()
	 */
	protected function save_write_do_getXml()
	{

		// start composing the XML object
		$xml=simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?><invoiceDetails />');

		// scan each calculation type from the session
		foreach (Services_Calculations::getAdmin()->getExtendedList() as $serviceCode => $locationDetails) {

			// add the service obj
			$serviceObj=$xml->addChild('service');
			$serviceObj['code']=$serviceCode;

			// scan each location from this service
			foreach ($locationDetails as $locationCode => $calculationDetails) {

				// looop through each calculation type and add calculation type
				foreach ($calculationDetails as $calculationCode => $nothing) {

					// compose the calculation code
					$calcCode=$serviceCode.'_'.$locationCode.'_'.$calculationCode;

					// ADD THE CALCULATION TYPE
					$calcVatObj=$serviceObj->addChild('calculationType');

					// add the location
					$calcVatObj['location']=$locationCode;

					// add the calculation code
					$calcVatObj['code']=$calculationCode;

					// scan each active invoice row
					foreach (['price', 'commission', 'discount', 'serviceFee', 'tax', 'penalty', 'advance'] as $invoiceRowVat) {

						// add offer row vat details
						$invoiceDetailsObj = $calcVatObj->addChild($invoiceRowVat);


						// add vat percent
						$invoiceDetailsObj['vatPercent']=$this->itemsList[$calcCode][$invoiceRowVat]['vatPercent'];

						// add vat text
						if (strlen($this->itemsList[$calcCode][$invoiceRowVat]['vatText'])) {
							$invoiceDetailsObj['vatText']=$this->itemsList[$calcCode][$invoiceRowVat]['vatText'];
						}

						// add vatRemark
						if (strlen($this->itemsList[$calcCode][$invoiceRowVat]['vatRemark'])) {
							$invoiceDetailsObj['vatRemark']=$this->itemsList[$calcCode][$invoiceRowVat]['vatRemark'];
						}

						// default hidden
						if ($this->itemsList[$calcCode][$invoiceRowVat]['hidden']) {
							$invoiceDetailsObj['hidden']="yes";
						} else {
							$invoiceDetailsObj['hidden']="no";
						}

					}
				}
			}
		}

		// return the simplexml object
		return $xml;
	}



	/**
	 * Gets all the invoice VAT details of all calculations for a certain service (all locations).
	 * @param String $serviceCode
	 * @param Boolean $includeDeleted
	 * @throws \Exception - if service code or location not set
	 * @return Array - the list of locationa and calculations
	 */
	public function getCalculationDetails($serviceCode, $criterion, $calculation)
	{

		// if input is invalid - return an empty array
		if (!$serviceCode) throw new \Exception('The service code was not set.');
		if (!$criterion) throw new \Exception('The criterion code was not set.');
		if (!strlen($calculation)) throw new \Exception('The calculation code was not set.');

		$key=$serviceCode.'_'.$criterion.'_'.$calculation;

		// determine the list
		$allData=$this->getAll();

		return (Array)$allData[$key];

	}

	/**
	 * Sets all the elements
	 * @param String $serviceCode
	 * @param String $location
	 * @param Int $calculationType
	 */
	public function setCalculationDetails($serviceCode, $criterion, $calculation, array $details)
	{
		// if input is invalid - return an empty array
		if (!$serviceCode) throw new \Exception('The service code was not set.');
		if (!$criterion) throw new \Exception('The criterion code was not set.');
		if (!strlen($calculation)) throw new \Exception('The calculation code was not set.');
		if (!$details) throw new \Exception('The calculation details array was not set.');

		$keyValue = $serviceCode.'_'.$criterion.'_'.$calculation;

		$this->set($keyValue, $details);
	}

	/**
	 * Indicates if a certain service-criteria-calculation-rowType should be hidden by default or not.
	 * @param string $serviceCode
	 * @param string $criterion
	 * @param int $calculation
	 * @param string $rowType
	 * @return boolean
	 */
	public function getHidden($serviceCode, $criterion, $calculation, $rowType)
	{
		$key=$serviceCode.'_'.$criterion.'_'.$calculation;
		$details = $this->get($key);
		return $details[$rowType]['hidden'];
	}

}
