<?php

namespace App\Utils\InvoiceDueDate;


/**
 * Storage class for the full due date profile (one or more profile elements).
 * The full entity due date profile is composed of a list of elements of this type.
 * @author Gabriel Grosu
 */
class Profile
{

	/**
	 * The list of profile elements.
	 * @var \App\Utils\InvoiceDueDate\Element[]
	 */
	protected $elements = [];

	/**
	 * Adds a
	 * @param \App\Utils\InvoiceDueDate\Element $element
	 */
	public function addElement(\App\Utils\InvoiceDueDate\Element $element)
	{
		$this->elements[] = $element;
	}

	/**
	 * Returns the elements from the profile.
	 * @return \App\Utils\InvoiceDueDate\Element[]
	 */
	public function getElements()
	{
		return $this->elements;
	}

	/**
	 * Resets any profile elements already added.
	 */
	public function reset()
	{
		$this->elements = [];
	}


	/**
	 * Check that a profile (composed of multiple elements) is ok.
	 * @throws \RuntimeException
	 */
	public function check()
	{

		// at least one element must be defined
		if (!$this->elements) {
			throw new \RuntimeException('No elements defined this profile.');
		}

		$foundServiceCodes = [];
		$defaultServiceCode = false;

		foreach ($this->elements as $element) {

			// check each element one by one
			$element->check();

			// check default service code and duplicated service codes
			foreach ($element->getServiceCodes() as $sc) {
				if (!$sc) {
					$defaultServiceCode = true;
				}
				if ($foundServiceCodes[$sc]) {
					throw new \RuntimeException(sprintf('Multiple elements defined for service code: %s', $sc));
				}
				$foundServiceCodes[$sc] = true;
			}

		}

		// check default service code
		if (!$defaultServiceCode) {
			throw new \RuntimeException('You must include the default service code on a profile element.');
		}

	}

	/**
	 * Exports the whole profile as an array.
	 * @return array
	 */
	public function exportAsArray()
	{

		$this->check();

		$return = [];
		foreach ($this->elements as $element) {
			$return[] = $element->exportAsArray();
		}
		return $return;

	}

	/**
	 * Imports the profile from an array.
	 * @param Array $profile
	 */
	public function importFromArray(array $profile)
	{

		$this->reset();

		foreach ($profile as $elArr) {
			$elObj = new \App\Utils\InvoiceDueDate\Element();
			$elObj->importFromArray($elArr);
			$this->addElement($elObj);
		}

	}


	/**
	 * Calculates and returns the due date for a certain invoice date.
	 * @param String $invoiceDate - ISO date
	 * @param String $serviceCode - service code
	 * @return String
	 */
	public function calculateDueDate($invoiceDate, $serviceCode)
	{

		$elementByServiceCode = null;
		$elementDefault = null;
		foreach ($this->elements as $element) {
			// look for the actual service code in the elements
			if ($serviceCode and in_array($serviceCode, $element->getServiceCodes())) {
				$elementByServiceCode = $element;
			}
			// look for the default service code in the elements
			if (in_array('', $element->getServiceCodes())) {
				$elementDefault = $element;
			}

		}

		// get the element that will be used for profile
		$elementFinal = null;
		if ($elementByServiceCode) {
			$elementFinal = $elementByServiceCode;
		} elseif ($elementDefault) {
			$elementFinal = $elementDefault;
		} else {
			throw new \RuntimeException('Invalid due profile used - not even the default service code is found in the profile.');
		}

		return $elementFinal->calculateDueDate($invoiceDate);

	}


}
