<?php

namespace App\GenDocument\Vars;

/**
 * The class that manages the fields values for a certain pivot (type+id).
 * @author Gabriel Grosu
 */
abstract class ValuesAbstract implements ValuesInterface
{
	/**
	 * The pivot name
	 * @var string
	 */
	protected $pivot = null;

	/**
	 * The pivot id.
	 * @var Int
	 */
	protected $idPivot = 0;

	/**
	 * Stores the manually set values in an associative array.
	 * @var array
	 */
	protected $fieldManualValues = [];

	/**
	 * The currently generating document type.
	 * @var String
	 */
	protected $documentType = null;

	/**
	 * Extra params for generation
	 * @var array
	 */
	protected $extraParams = [];


	/**
	 * The constructor - assigns the id pivot.
	 * @param Int $idPivot
	 */
	final protected function __construct($idPivot) {
		// set the pivot id
		$this->idPivot = $idPivot;

		if (!$this->pivot){
			throw new \Exception("This object has been initialised without a pivot?? idPivot was '{$idPivot}'");
		}

		$this->checkPivot();
	}

	/**
	 * The singleton instance for this pivot.
	 * @var array
	 */
	static protected $instance=[];

	/**
	 * The singleton instantiation for this pivot.
	 * @param Int $idPivot
	 * @return self
	 */
	static public function getInstance($idPivot)
	{
		$key = get_called_class().".".$idPivot;
		if (!isset(static::$instance[$key])) {
			static::$instance[$key] = new static($idPivot);
		}
		return static::$instance[$key];
	}

	/**
	 * Checks the current pivot id.
	 * @return bool
	 */
	abstract protected function checkPivot() :void;

	/**
	 * Returns the pivot id.
	 * @return Int
	 */
	public function getIdPivot()
	{
		return $this->idPivot;
	}

	public function getConfig()
	{
		return PivotBuilderConfig::fromPivot($this->pivot);
	}

	/**
	 * Attach some of the values that are common for all pivots.
	 * @param String $field
	 * @return Mixed - a certain value or blank if the field is found here; null otherwise.
	 */
	public function getValue($field)
	{

		global $_LANG;

		// IF THE FIELD HAS BEEN MANUALLY SET - RETURN THIS VALUE /////////////////////////////////
		if (array_key_exists($field, $this->fieldManualValues)) {
			return $this->fieldManualValues[$field];
		}

		// the default value of the field
		$r=null;

		// checks if the field was found through these vars
		$fieldFound=true;

		// THE LIST OF AVAILABLE FIELDS (for all pivots) //////////////////////////////////////////
		switch ($field) {

			case 'compName': 						$r=trim(\App\Config\AgencyData::getInstance()->get('companyPrefix').' '.\App\Config\AgencyData::getInstance()->get('companyName').' '.\App\Config\AgencyData::getInstance()->get('companySuffix')); break;
			case 'compName2': 						$r=trim(\App\Config\AgencyData::getInstance()->get('companyPrefix2').' '.\App\Config\AgencyData::getInstance()->get('companyName2').' '.\App\Config\AgencyData::getInstance()->get('companySuffix2')); break;
			case 'compFiscalCode': 					$r=\App\Config\AgencyData::getInstance()->get('fiscalCode'); break;
			case 'compEuVatNumber': 				$r=\App\Config\AgencyData::getInstance()->get('vatNumber'); break;
			case 'compRegNo': 						$r=\App\Config\AgencyData::getInstance()->get('regNo'); break;
			case 'compRegistryAddress': 			$r=\App\Config\AgencyData::getInstance()->get('registryAddress'); break;
			case 'compRegistryAddress2': 			$r=\App\Config\AgencyData::getInstance()->get('registryAddress2'); break;
			case 'compLiablePerson': 				$r=\App\Config\AgencyData::getInstance()->get('liablePerson'); break;
			case 'compTravelLicenseNo': 			$r=\App\Config\AgencyData::getInstance()->get('travelLicenseNo'); break;
			case 'compRegCapital': 					$r=\App\Config\AgencyData::getInstance()->get('regCapital'); break;
			case 'compTelephone': 					$r=\App\Config\AgencyData::getInstance()->get('telephone'); break;
			case 'compEmail': 						$r=\App\Config\AgencyData::getInstance()->get('email'); break;
			case 'compFax': 						$r=\App\Config\AgencyData::getInstance()->get('fax'); break;

			case 'currUserId':						$r=CURRENT_ID_USER; break;
			case 'currUserName':					$r=\Entity\User::selectCurrent()->name; break;
			case 'currUserLastName':				$r=\Entity\User::selectCurrent()->lastName; break;
			case 'currUserFirstName':				$r=\Entity\User::selectCurrent()->firstName; break;
			case 'currUserIdSeries':				$r=\Entity\User::selectCurrent()->ID_series; break;
			case 'currUserIdNumber':				$r=\Entity\User::selectCurrent()->ID_number; break;
			case 'currUserIdReleaseBy':				$r=\Entity\User::selectCurrent()->ID_releaseBy; break;
			case 'currUserIdReleaseDateIso':		$r=\Entity\User::selectCurrent()->ID_releaseDate; break;
			case 'currUserIdReleaseDateStandard':	$r=\Engine\DateTime::isoToStd(\Entity\User::selectCurrent()->ID_releaseDate); break;
			case 'currUserPNC':						$r=\Entity\User::selectCurrent()->PNC; break;
			case 'currUserJob':						$r=\Entity\User::selectCurrent()->job; break;
			case 'currUserEmail':					$r=\Entity\User::selectCurrent()->email; break;
			case 'currUserEmailAlternative':		$r=\Entity\User::selectCurrent()->emailAlternative; break;
			case 'currUserTelephone':				$r=\Entity\User::selectCurrent()->telephone; break;
			case 'currUserFax':						$r=\Entity\User::selectCurrent()->fax; break;
			case 'currUserDeptName':				$r=\Entity\Department::current()->name; break;
			case 'currUserDeptCode':				$r=\Entity\Department::current()->code; break;

			case 'currOffName':						$r=\Entity\Office::current()->name; break;
			case 'currOffIataCode':					$r=\Entity\Office::current()->iataCode; break;
			case 'currOffAddress':					$r=\Entity\Office::current()->address; break;
			case 'currOffDeliveryAddress':			$r=\Entity\Office::current()->deliveryAddress; break;
			case 'currOffZipCode':					$r=\Entity\Office::current()->zipCode; break;
			case 'currOffCountry':					$r=\Entity\Office::current()->country->name; break;
			case 'currOffCity':						$r=\Entity\Office::current()->city->name; break;
			case 'currOffTelephone':				$r=\Entity\Office::current()->telephone; break;
			case 'currOffFax':						$r=\Entity\Office::current()->fax; break;
			case 'currOffEmail':					$r=\Entity\Office::current()->email; break;
			case 'currOffWeb':						$r=\Entity\Office::current()->web; break;

			case 'mainOffName':						$r=\Entity\Office::select(\Entity\Office::getDefaultId())->name; break;
			case 'mainOffIataCode':					$r=\Entity\Office::select(\Entity\Office::getDefaultId())->iataCode; break;
			case 'mainOffAddress':					$r=\Entity\Office::select(\Entity\Office::getDefaultId())->address; break;
			case 'mainOffDeliveryAddress':			$r=\Entity\Office::select(\Entity\Office::getDefaultId())->deliveryAddress; break;
			case 'mainOffZipCode':					$r=\Entity\Office::select(\Entity\Office::getDefaultId())->zipCode; break;
			case 'mainOffCountry':					$r=\Entity\Office::select(\Entity\Office::getDefaultId())->country->name; break;
			case 'mainOffCity':						$r=\Entity\Office::select(\Entity\Office::getDefaultId())->city->name; break;
			case 'mainOffTelephone':				$r=\Entity\Office::select(\Entity\Office::getDefaultId())->telephone; break;
			case 'mainOffFax':						$r=\Entity\Office::select(\Entity\Office::getDefaultId())->fax; break;
			case 'mainOffEmail':					$r=\Entity\Office::select(\Entity\Office::getDefaultId())->email; break;
			case 'mainOffWeb':						$r=\Entity\Office::select(\Entity\Office::getDefaultId())->web; break;

			case 'dateTimeTodayIso':				$r=TODAY_ISO; break;
			case 'dateTimeTodayStandard':			$r=\Engine\DateTime::isoToStd(TODAY_ISO); break;
			case 'dateTimeTodayYear':				$r=TODAY_YEAR; break;
			case 'dateTimeTodayMonth':				$r=TODAY_MONTH; break;
			case 'dateTimeTodayMonthNameLong':		$r=$_LANG['date']['month']['long'][(int)TODAY_MONTH]; break;
			case 'dateTimeTodayMonthNameShort':		$r=$_LANG['date']['month']['short'][(int)TODAY_MONTH]; break;
			case 'dateTimeTodayDay':				$r=TODAY_DAY; break;
			case 'dateTimeTimestamp':				$r=TIMESTAMP; break;
			case 'dateTimeHourMin':					$r=date("H:i"); break;
			case 'dateTimeHourMinSec':				$r=date("H:i:s"); break;
			case 'dateTimeWeekDayShort':			$r=$_LANG['date']['day']['short'][date("w")]; break;
			case 'dateTimeWeekDayLong':				$r=$_LANG['date']['day']['long'][date("w")]; break;
			case 'dateTimeWeekNumber':				$r=date("W"); break;

			// if none of the fields from above - set the fieldFound flag
			default: 								$fieldFound=false;
		}

		// IF THE FIELD WAS NOT YET FOUND - ATTEMPT TO GET IT FROM SPECIFIC PIVOT STRUCTURE ///////
		if (!$fieldFound) {
			$r=$this->getSpecificPivotValue($field);
			if ($r!==null) $fieldFound=true;
		}

		// CHECK IF THIS IS A FORCED FIELD ////////////////////////////////////////////////////////
		if (!$fieldFound) {

			// get all forced fields config
			$forcedFieldsCfg = PivotBuilderConfig::fromPivot($this->pivot)->getAllForced();

			// the current forced field config
			$fieldCfg=$forcedFieldsCfg[$field];
			// if this is truly a forced field
			if ($fieldCfg) {
				// the field was configured as 'forced' so it is "found"
				$fieldFound=true;
				// get the dependency field value
				$dependKey=$this->getValue($fieldCfg['key']);
				// if the dependency key value is okay and it is configured in the 'values' array
				if ($dependKey and $fieldCfg['values'][$dependKey]) {
					// get the real value for this current forced field
					$r=$this->getValue($fieldCfg['values'][$dependKey]);
				}
			}
		}

		$return = null;
		// check if a plugin might populate this field (or rewrite one value from above)
		\Engine\Plugins\Manager::getInstance()->executeEvent('documents-pivotFieldsValues-['.$this->pivot.']', ['pivotFieldsObj'=>$this, 'field'=>$field, 'return'=>&$return, 'currentValue'=>$r]);

		// if $r is NOT null, the field was found
		if ($return!==null) {
			$fieldFound = true;
			$r = $return;
		}

		// if the field was found but not set - rewrite it to blank '' (null is only used if the field is not from the above list)
		if ($fieldFound and $r===null) $r='';

		return $r;

	}


	/**
	 * Sets the extraParams array
	 * @param Array $extraParams
	 */
	public function setExtraParams($extraParams)
	{
		$this->extraParams = $extraParams;
	}

	/**
	 * Returns the extraParams array
	 * @return multitype:
	 */
	public function getExtraParams()
	{
		return $this->extraParams;
	}

	/**
	 * Sets the currently generated document type.
	 * @param String $documentType
	 */
	public function setDocumentType($documentType)
	{
		$this->documentType = $documentType;
	}

	/**
	 * Gets the currently generated document type.
	 * @param String $documentType
	 */
	public function getDocumentType()
	{
		return $this->documentType;
	}

	/**
	 * Returns true if the field exists, false otherwise
	 * @param String $field
	 * @return bool
	 */
	public function exists($field)
	{
		return PivotBuilderConfig::fromPivot($this->pivot)->exists($field) || isset($this->fieldManualValues[$field]);
	}

	/**
	 * Sets a manual value for a certain field.
	 * @param String $field
	 * @param Mixed $value
	 */
	public function setManualValue($field, $value)
	{
		// null cannot be set
		if ($value===null) $value='';
		// store the value
		$this->fieldManualValues[$field]=$value;
	}

	/**
	 * Eliminates all the manual values that were set before for this pivot.
	 */
	public function flushManualValues()
	{
		$this->fieldManualValues = [];
	}


	/**
	 * Returns the value of the field depending on the current pivot.
	 * @param String $field
	 */
	abstract protected function getSpecificPivotValue($field);

}
