<?php

namespace App\Config;

/**
 * The class is used for managing the list of cashing documents.
 * @author Gabriel Grosu
 */
class CashingDocuments 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_CASHING_DOCUMENTS_LIST;


	/**
	 * The root tag of the XML.
	 * @var string
	 */
	protected $xmlRootTagName = 'cashingDocuments';


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlBasicAbstract::getAll_rawData_fileNotExists()
	 */
	protected function getAll_rawData_fileNotExists()
	{
		return [];
	}


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

		// gets the final list of items to be returned
		$return = [];
		foreach ($xml->doc as $docXml) {
			$docTypeCode = (String)$docXml['code'];
			$return[$docTypeCode] = [
				'name'					=> (String)$docXml->name,
				'active'				=> (Int)$docXml['active'],
				'number'				=> (String)$docXml->number,
				'sign'					=> (Int)$docXml->sign,
				'bankAccount'			=> (String)$docXml->bankAccount,
				'explanations'			=> (String)$docXml->explanations,
				'comments'				=> (String)$docXml->comments,
			];
		}
		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)
	{

		$errorMessages = [];

		if (!mb_strlen($code)) {
			$errorMessages[] = 'No document code set';
		} elseif (mb_strlen($code)>25) {
			$errorMessages[] = 'The document code can have max 25 chars.';
		} elseif (!\Engine\Validator::set($code)->isAlnum()) {
			$errorMessages[] = 'The document code can only contain alphanumeric chars.';
		}
		// check name
		if (!$itemDetails['name']) {
			$errorMessages[] = 'No document name set';
		} elseif (mb_strlen($itemDetails['name'])>25) {
			$errorMessages[] = 'The document name can have max 25 chars.';
		} else {
			// check that the name is unique
			$docsList = $this->getList();
			unset($docsList[$code]); // to correctly work with update as well as insert operation
			$cleanDocsList = array_map('mb_strtolower', $docsList);
			if ( in_array( mb_strtolower($itemDetails['name']), $cleanDocsList) ) {
				$errorMessages[] = 'The document name already exists.';
			}
		}

		// check sign
		if (!is_numeric($itemDetails['sign']) or !in_array($itemDetails['sign'], [-1, 0, 1])) {
			$errorMessages[] = 'The doc sign is not valid - it must be set as -1, 0 or 1.';
		}

		// check number
		if (!in_array($itemDetails['number'], ['hidden', 'optional', 'mandatory', 'series'])) {
			$errorMessages[] = 'The doc number type is not set/valid.';
		}

		// check fields visibility
		$validVisibilities = ['hidden', 'optional', 'mandatory'];
		if (!in_array($itemDetails['bankAccount'], $validVisibilities)) {
			$errorMessages[] = 'The bank account visibility is not set/valid.';
		}
		if (!in_array($itemDetails['explanations'], $validVisibilities)) {
			$errorMessages[] = 'The explanations visibility is not set/valid.';
		}
		if (!in_array($itemDetails['comments'], $validVisibilities)) {
			$errorMessages[] = 'The comments visibility is not set/valid.';
		}

		// throw new messages
		if ($errorMessages) {
			$this->addErrorMessage(implode(' ', $errorMessages));
		}

	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Config\BaseAbstract::save_check()
	 */
	protected function save_check()
	{
		// check that all previous document types still exist
		foreach(self::getInstance()->getAll() as $prevDocTypeCode=>$nada) {
			if (!$this->itemsList[$prevDocTypeCode]) {
				$this->addErrorMessage(sprintf('The doc type `%s` must not be deleted.', $prevDocTypeCode));
			}
		}
	}


	/**
	 * (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"?><'.$this->xmlRootTagName.' />');
		foreach ($this->itemsList as $docTypeCode=>$docTypeDet) {
			// add main info
			$thisDocTypeXml						= $xml->addChild('doc', '');
			$thisDocTypeXml['code']				= $docTypeCode;
			$thisDocTypeXml['active']			= (bool)$docTypeDet['active'];
			$thisDocTypeXml->name				= $docTypeDet['name'];
			$thisDocTypeXml->number				= $docTypeDet['number'];
			$thisDocTypeXml->sign				= $docTypeDet['sign'];
			$thisDocTypeXml->bankAccount		= $docTypeDet['bankAccount'];
			$thisDocTypeXml->explanations		= $docTypeDet['explanations'];
			$thisDocTypeXml->comments			= $docTypeDet['comments'];
		}

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

	}

	/**
	 * Returns simple assoc array of doc types (code=>name) only with active documents.
	 * @return array
	 */
	public function getList()
	{
		$return = [];
		foreach ($this->getAll() as $docTypeCode=>$docDetails) {
			if ($docDetails['active']) {
				$return[$docTypeCode] = $docDetails['name'];
			}
		}
		return $return;
	}


	/**
	 * Returns if the doc type exists.
	 * @param string $docType
	 * @return boolean
	 */
	public function exists($docType)
	{
		return $this->get($docType) ? true : false;
	}


	/**
	 * Returns the "active" status of a doc type.
	 * @param string $docType
	 */
	public function isActive($docType)
	{
		return (bool)$this->get($docType)['active'];
	}

	/**
	 * Returns the doc type name.
	 * @param string $docType
	 * @return string
	 */
	public function getName($docType)
	{
		return $this->get($docType)['name'];
	}

	/**
	 * Gets the number of a doc type.
	 * @param string $docType
	 * @return string - series, mandatory, optional, hidden
	 */
	public function getNumber($docType)
	{
		return $this->get($docType)['number'];
	}

	/**
	 * Gets the sign of a doc type.
	 * @param string $docType
	 * @return int : 1 (positive), -1 (negative), 0 (both)
	 */
	public function getSign($docType)
	{
		return $this->get($docType)['sign'];
	}

	/**
	 * Gets the bank account field status.
	 * @param string $docType
	 * @return string - hidden, optional, mandatory
	 */
	public function getBankAccount($docType)
	{
		return $this->get($docType)['bankAccount'];
	}

	/**
	 * Gets the explanations field status.
	 * @param string $docType
	 * @return string - hidden, optional, mandatory
	 */
	public function getExplanations($docType)
	{
		return $this->get($docType)['explanations'];
	}

	/**
	 * Gets the comments field status.
	 * @param string $docType
	 * @return string - hidden, optional, mandatory
	 */
	public function getComments($docType)
	{
		return $this->get($docType)['comments'];
	}

}