<?php

// TODO: script portare (se pare ca la furnizori, exista formatul "6" nu numai "+6" - ar trebui sa fim compatibili cu ambele formate

namespace App\Utils\InvoiceDueDate;

/**
 * Class for setting/getting entity (corporate/customer/supplier) profile. Works with the database,
 * stores using entityPreference classes and receives as input/output objects of type Profile.
 * @author Gabriel Grosu
 */
abstract class GeneralAbstract
{

	/**
	 * The entity (corporate/customer/supplier) id.
	 * @var Int
	 */
	protected $idEntity;

	/**
	 * The profile object for the current entity; can be set to "null" for the first time, false if the
	 * database was searched but nothing was found or an actual Profile object.
	 * @var Profile
	 */
	protected $profile = null;


	/**
	 * Sets the current entity id.
	 * @param Int $idEntity
	 */
	public function __construct($idEntity)
	{
		$this->idEntity = $idEntity;
 	}


 	/**
 	 * Returns the current entity profile object.
 	 * @return \App\Utils\InvoiceDueDate\Profile
 	 */
 	public function getProfile()
 	{
 		if ($this->profile===null) {
 			$this->profile = false;
 			$entPrefObj = $this->getEntityPreferenceObject();
 			$profileArrSer = $entPrefObj->invoiceDueDate;
 			if ($profileArrSer) {
 				// check if something is correctly serialized
 				$profileArr = unserialize($profileArrSer);
 				if (!$profileArr) {
 					throw new \RuntimeException(sprintf('Invalid entity preference for due date profile for `%s`.', get_called_class()));
 				}
 				// creates and populated the profile object
 				$this->profile = new \App\Utils\InvoiceDueDate\Profile();
 				$this->profile->importFromArray($profileArr); // also checks if the import is ok; otherwise throws \RuntimeException
 			}
 		}

 		// outputs the current entity profile
 		return $this->profile;

 	}

 	/**
 	 * Sets the new profile for the current entity (saves it in the db and updates internal cache).
 	 * @param \App\Utils\InvoiceDueDate\Profile $profile
 	 */
 	public function setProfile(\App\Utils\InvoiceDueDate\Profile $profile)
 	{
 		$profileArr = $profile->exportAsArray();
 		$entPrefObj = $this->getEntityPreferenceObject();
 		$entPrefObj->invoiceDueDate = serialize($profileArr);
 		// resets the internal cache
 		$this->profile = $profile;
 	}

 	/**
 	 * Resets the entity profile
 	 */
 	public function unsetProfile()
 	{
 		$entPrefObj = $this->getEntityPreferenceObject();
 		unset($entPrefObj->invoiceDueDate);
 		// resets the internal cache
 		$this->profile = false;
 	}

 	/**
 	 * Returns the min offset from the profile
 	 */
 	public function getMinimalDueDays()
 	{

 		$profile = $this->getProfile();
 		$minDueDays = NULL;

 		if ($this->getProfile()) {
 			$profile = $this->getProfile();
 		}
 		else {
 			$profile = $this->getDefaultProfile();
 		}

 		foreach ($profile->getElements() as $element) {
 			if ($element->getType() == 'intervals') {
 				foreach($element->getIntervals() as $interval) {
 					if (!$minDueDays or $minDueDays > $interval['offset']) {
 						$minDueDays = $interval['offset'];
 					}
 				}
 			}
 			elseif ($element->getType() == 'days') {
 				if (!$minDueDays or $minDueDays > $element->getOffset()) {
 					$minDueDays = $element->getOffset();
 				}
 			}
 		}

 		return $minDueDays;
 	}


 	/**
 	 * Returns the \App\EntityPreference instantiated object.
 	 * @return \App\EntityPreference\BaseAbstract
 	 */
 	abstract protected function getEntityPreferenceObject();

 //	abstract protected function setProfileDueDate();

 	/**
 	 * Returns the calculated due date based on the invoice date and the service code.
 	 * @param String $invoiceDate
 	 * @param String $serviceCode
 	 */
 	public function calculateDueDate($invoiceDate, $serviceCode)
 	{

 		// make sure that the profile is loaded from db (if it is set)
 		$profile = $this->getProfile();

 		// if no profile set, get a default profile from app defaults
 		if (!$profile) {
 			$profile = $this->getDefaultProfile();
 			if ($profile and get_class($profile)!='App\Utils\InvoiceDueDate\Profile') {
 				throw new \Exception('Invalid object outputted - the return of the getDefaultProfile() must be an object of type \App\Utils\InvoiceDueDate\Profile.');
 			}
 		}

 		// returns the calculated due date
 		if ($profile) {
 			return $profile->calculateDueDate($invoiceDate, $serviceCode);
 		}
 		else {
 			return null;
 		}
 	}

 	/**
 	 * Creates a Profile object with content from app default due date profile.
 	 * @return \App\Utils\InvoiceDueDate\Profile
 	 */
 	abstract protected function getDefaultProfile();

}

