<?php


namespace App\Form\Input;

class Autocomplete_Data_DocPivotEmail extends \Engine\Form\Input\Autocomplete_Data_GeneralAbstract
{


	/**
	 * The cache type (for the list of emails per doc pivot).
	 * @var String
	 */
	private $cacheType='disk';

	/**
	 * Cache the emails list for this number of seconds. If null is set - does not cache the results at all.
	 * @var Int
	 */
	private $cacheExpireTime=40;

	/**
	 * (non-PHPdoc)
	 * @see \Engine\Form\Input\Autocomplete_Data_GeneralAbstract::getPageResultsBulk()
	 */
	protected function getPageResultsBulk() :array
	{

		// cache key
		$cacheKey='Form_Input_Autocomplete_Data_DocPivotEmail_'.$this->filters['idDocument'].'_'.$this->filters['includeUsers'];


		// GET ALL EMAILS FROM CACHE/DB (FOR THIS PIVOT) //////////////////////////////////////////
		// NO CACHE SET ---------------------------------------------------------------------------
		if ($this->cacheExpireTime===null) {
			$fullList=$this->getPivotAllEmails();
		}
		// WITH ACTIVE CACHE ----------------------------------------------------------------------
		else {
			$fullList=\Engine\Cache\General::getInstance($this->cacheType)->get($cacheKey);
			// if results not cached - get them from db and
			if ($fullList===null) {
				$fullList=$this->getPivotAllEmails();
				\Engine\Cache\General::getInstance($this->cacheType)->set($cacheKey, $fullList, $this->cacheExpireTime);
			}
		}

		// FILTERING THE ADDRESSES BY THE SEARCH STRING ///////////////////////////////////////////
		$filteredList=$this->filterResults($fullList);

		// UPDATE THE TOTAL COUNT /////////////////////////////////////////////////////////////////
		$this->resultsCountTotal=count($filteredList);

		// SHOW THE CURRENT PAGE //////////////////////////////////////////////////////////////////
		$pageList=array_slice($filteredList, $this->offset, $this->resultsCountPage);

		return $pageList;

	}


	/**
	 * (non-PHPdoc)
	 * @see \Engine\Form\Input\Autocomplete_Data_GeneralAbstract::getPageResultsFormatted()
	 */
	protected function getPageResultsFormatted(Array $pageResults)
	{
		$list=[];
		foreach($pageResults as $row) {
			$list[]=$this->getCleanItem($row['email'], $row['email'], $row['name']);
		}
		return $list;
	}


	/**
	 * Returns a list of all emails from the current document.
	 * @return Array
	 */
	private function getPivotAllEmails()
	{

		// get document id
		$idDoc=$this->filters['idDocument'];
		$doc=\Entity\Document::select($idDoc);

		$list = [];

		// LOAD EMAILS BASED ON PIVOT TYPE ////////////////////////////////////////////////////////
		switch ($doc->pivotCode) {
			case 'invoice': {
				$list=$this->getPivotAllEmails_invoice($doc->idPivot);
				break;
			}
			case 'cashing': {
				$list=$this->getPivotAllEmails_invoice($doc->pivot->idInvoice);
				break;
			}
			case 'order': {
				$list=$this->getPivotAllEmails_order($doc->idPivot);
				break;
			}
			case 'service': {
				$list=$this->getPivotAllEmails_order($doc->pivot->idOrder);
				break;
			}
			case 'payment': {
				$list = $this->getPivotAllEmails_payment($doc->idPivot);
				break;
			}
		}

		// ATTACH USER EMAILS /////////////////////////////////////////////////////////////////////
		$list=array_merge($list, $this->getPivotAllEmails_users());

		// ORDER BY EMAIL ADDRESS /////////////////////////////////////////////////////////////////
		$list=array_orderBy($list, 'email', SORT_ASC);

		return $list;

	}


	/**
	 * Get the email addresses for an invoice.
	 * @param Int $idInvoice
	 * @return Array - the list of emails
	 */
	private function getPivotAllEmails_invoice($idInvoice)
	{

		$return=[];

		$inv=\Entity\Invoice::select($idInvoice);

		// ADD INVOICE CLIENT EMAIL ///////////////////////////////////////////////////////////////
		// CUSTOMER -------------------------------------------------------------------------------
		if ($inv->idCustomer) {
			$return=array_merge($return, $this->getPivotAllEmails_customer($inv->idCustomer));
		}
		// CORPORATE ------------------------------------------------------------------------------
		else {
			$return=array_merge($return, $this->getPivotAllEmails_corporate($inv->idCorporate));
		}

		return $return;

	}


	/**
	 * Get the email addresses for a customer.
	 * @param Int $idCustomer
	 * @return Array - the list of emails
	 */
	private function getPivotAllEmails_customer($idCustomer)
	{

		$return=[];

		// get and check customer
		$cust = \Entity\Customer::select($idCustomer);
		if (!$cust->recordExists()) {
			return [];
		}

		// attach customer email
		if ($cust->email) {
			$return[]= ['email'=>$cust->email, 'name'=>$cust->name];
		}

		return $return;

	}


	/**
	 * Get the email addresses for a corporation.
	 * @param Int $idCorporate
	 * @return Array - the list of emails
	 */
	private function getPivotAllEmails_corporate($idCorporate)
	{

		$return=[];

		// get and check corporate details
		$corp = \Entity\Corporate::select($idCorporate);
		if (!$corp->recordExists()) {
			return [];
		}

		// attach corporate email
		$e=$corp->email;
		if ($e) {
			$return[]= ['email'=>$e, 'name'=>$corp->alias];
		}

		// attach corporate offices email
		foreach($corp->officesList as $idOff=>$offDet) {
			$e=\Entity\CorporateOffice::select($idOff)->email;
			if ($e) {
				$return[]= ['email'=>$e, 'name'=>$corp->alias];
			}
		}

		// attach corporate contact persons
		foreach($corp->contactPersonsList as $ctcPers) {
			if ($ctcPers['email']) {
				$return[]= ['email'=>$ctcPers['email'], 'name'=>$ctcPers['lastName'].' '.$ctcPers['firstName']];
			}
		}

		return $return;

	}

	/**
	 * Get the email address for a supplier.
	 * @param Int $idSupplier
	 * @return Array - the list of emails
	 */
	private function getPivotAllEmails_supplier($idSupplier)
	{
		$return=[];

		// get and check supplier
		$supp=\Entity\Supplier::select($idSupplier);
		if (!$supp->recordExists()) {
			return [];
		}

		// attach supplier email
		$suppEmail = $supp->email;
		if ($suppEmail) {
			$return[]= ['email'=>$suppEmail, 'name'=>$supp->alias];
		}

		// attach supplier contact persons
		foreach ($supp->contactPersonsList as $ctcPers) {
			if ($ctcPers['email']) {
				$return[]= ['email'=>$ctcPers['email'], 'name'=>$ctcPers['lastName'].' '.$ctcPers['firstName']];
			}
		}
		return $return;
	}

	/**
	 * Get the email address for supplier product
	 * @param Int $idSupplierProduct
	 * @return Array
	 */
	private function getPivotAllEmails_supplierProduct($idSupplierProduct)
	{
		$return=[];

		// get and check supplier product
		$supplierProduct = \Entity\SupplierProduct::select($idSupplierProduct);
		if (!$supplierProduct->recordExists()) {
			return [];
		}

		// attach supplier product email
		if ($supplierProduct->email) {
			$return[]= ['email'=>$supplierProduct->email, 'name'=>$supplierProduct->productName];
		}

		return $return;
	}


	/**
	 * Get the email addresses for a reservation.
	 * @param Int $idReservation
	 * @return Array - the list of emails
	 */
	private function getPivotAllEmails_order($idReservation)
	{

		$return=[];

		$res=\Entity\Order::select($idReservation);

		// CUSTOMERS ------------------------------------------------------------------------------
		foreach($res->idCustomersList as $idCust) {
			$return=array_merge($return, $this->getPivotAllEmails_customer($idCust));
		}
		// CORPORATES -----------------------------------------------------------------------------
		foreach($res->idCorporatesList as $idCorp) {
			$return=array_merge($return, $this->getPivotAllEmails_corporate($idCorp));
		}
		// SERVICE OFFERS SUPPLIERS ---------------------------------------------------------------
		foreach($res->servicesList as $idServ=>$servDet) {
			$suppEntity = \Entity\Service::select($idServ);
			$idSupp	= $suppEntity->chosenOffer->idSupplier;
			$idSupplierProduct = $suppEntity->idSupplierProduct;

			// attach supplier email and supplier contact person email
			if ($idSupp) {
				$return=array_merge($return, $this->getPivotAllEmails_supplier($idSupp));
			}

			// attach supplier product email
			if ($idSupplierProduct)
			{
				$return=array_merge($return, $this->getPivotAllEmails_supplierProduct($idSupplierProduct));
			}
		}

		return $return;

	}

	/**
	 * Get the email addresses for a payment.
	 * @param Int $idReservation
	 * @return Array - the list of emails
	 */
	private function getPivotAllEmails_payment($idSupplierPayment)
	{

		$return = [];

		$supplierPaymentInvoiceEntity = \Entity\SupplierInvoicePayment::select($idSupplierPayment)->supplierInvoice;

		if ($supplierPaymentInvoiceEntity->idSupplier) {
			$return = array_merge($return, $this->getPivotAllEmails_supplier($supplierPaymentInvoiceEntity->idSupplier));
		}

		return $return;

	}


	/**
	 * Get the list of users with email attached (only if the users are not filtered out).
	 * @return Array - the list of emails
	 */
	private function getPivotAllEmails_users()
	{
		// if users must not be included - do not add them
		if (!$this->filters['includeUsers']) {
			return [];
		}

		$db=\DB::getInstance();
		global $DBTUsers;
		// get users with email
		$usersListSQL="SELECT lastName, firstName, email FROM `$DBTUsers` WHERE deleted=0 AND email!=''";
		$usersList=$db->GetAll($usersListSQL);
		// check sql
		if ($db->ErrorNo()) {
			\Log::getInstance()->dbError("Could not get users with emails");
			throw new \DBException('Could not get users with email addresses due to a technical problem.');
		}
		// attach users with email
		$return=[];
		foreach($usersList as $user) {
			$return[]= ['email'=>$user['email'], 'name'=>$user['lastName'].' '.$user['firstName']];
		}
		return $return;

	}


	/**
	 * Filters the results based on the search string (the search is done as a whole and both name
	 * and email address is searched.
	 * @param Array $list - the list of all the emails
	 * @return Array - the list of emails filtered by the search string.
	 */
	private function filterResults(Array $list)
	{

		// upper case for the search string
		$srcStr=mb_strtoupper($this->searchString);

		// look for the search string inside the email and the name for these addresses
		$return=[];

		// also eliminates duplicated addresses
		foreach($list as $addr) {
			if (!$srcStr or mb_strpos(mb_strtoupper($addr['email']), $srcStr)!==false or mb_strpos(mb_strtoupper($addr['name']), $srcStr)!==false) {
				$return[$addr['email']]=$addr;
			}
		}
		return array_values($return);

	}


}