<?php

namespace App\EntityMatch;

class Customer extends \App\EntityMatch\BaseAbstract
{

	/**
	 * The export fields for customers.
	 * @var array
	 */
	protected $exportFields = ['lastName', 'firstName', 'idCorporate', 'PNC', 'email', 'address'];

	/**
	 * Extra filters - deleted and duplicated customers are not allwed.
	 * @var String
	 */
	protected $matchingFilteringSQL = 'AND ent.deleted=0 AND ent.idRealCustomer=0';

	/**
	 * The class name which will instantiate the Entity - used for primaryKey search.
	 * @var String
	 */
	protected $entityClassName = '\Entity\Customer';

	/**
	 * The id corporate filter.
	 * @var Int
	 */
	private $idCorporateFilter;


	/**
	 * (non-PHPdoc)
	 * @see \App\EntityMatch\BaseAbstract::setTableName()
	 */
	protected function setTableName()
	{
		global $DBTCustomers;
		$this->tableName = $DBTCustomers;
	}

	/**
	 * Sets a search by customer PNC.
	 * @param String $value - the customer PNC.
	 */
	public function setPNC($value)
	{
		\Entity\Customer::loadCFG();
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();

		if ($value!=$CFG['globalEntity']['::Customer']['PNC']['notUniqueValue']) {
			$this->setSearchCriterion('PNC', $value, false);
		}
	}

	/**
	 * Set the name for the passenger. You can set if the names are searched using or not a wildcard
	 * and also you can choose to mix the names.
	 * @param String $lastName
	 * @param String $firstName
	 * @param Boolean $useWildcard
	 * @param Boolean $searchMixed
	 */
	public function setName($lastName, $firstName, $useWildcard=true, $searchMixed=true)
	{
		$this->setSearchCriterion('name', ['lastName'=>$lastName, 'firstName'=>$firstName], $useWildcard, ['searchMixed'=>$searchMixed]);
	}

	/**
	 * Sets a search by email.
	 * @param String $email
	 */
	public function setEmail($email)
	{
		$this->setSearchCriterion('email', $email, false);
	}

	/**
	 * Sets a search by telephone number and mobile.
	 * @param String $tel
	 */
	public function setTelephone($tel)
	{
		$this->setSearchCriterion('telephone', $tel, false);
		$this->setSearchCriterion('telephoneMobile', $tel, false);
	}


	/**
	 * Sets the filter by corporate.
	 */
	public function filterByIdCorporate($idCorporateFilter)
	{
		$this->idCorporateFilter = $idCorporateFilter;
	}


	/**
	 * This method does a special search for remarks (for the rest of the criteria, it uses the parent call.
	 * @see \App\EntityMatch\BaseAbstract::searchRecords()
	 */
	protected function dispatchSearchRecords($field, $value, $useWildcard, Array $options=[])
	{

		switch ($field)
		{
			case 'name':
				return $this->searchRecords_name($value, $useWildcard, $options);
			break;

			default:
				return parent::dispatchSearchRecords($field, $value, $useWildcard, $options);

		}

	}


	/**
	 * This method does the actual search in the database if the remark was set.
	 * @param String $value - the remark value
	 * @param Boolean $useWildcard - the value will have a right wildcard (%)
	 * @param array $options - array of extra options: remarkVar contains the name of the remark var.
	 * @return Array - the list of found customers (associative array by id)
	 */
	private function searchRecords_name($names, $useWildcard, Array $options=[])
	{

		global $CFG;

		// COMPOSE SQL ----------------------------------------------------------------------------

		// the cols list
		$colsSQL=$this->getSelectingFieldsSQL();

		// the search string
		$lastNameString = $names['lastName']; // lastName is matched exactly (no wildcard)
//		if ($useWildcard) $lastNameString .= '%';
		$firstNameString = $names['firstName'];
		if ($useWildcard) $firstNameString .= '%';

		// start the sql
		$searchSQL = "SELECT {$colsSQL} FROM `{$this->tableName}` AS ent WHERE 1 {$this->matchingFilteringSQL}";

		// add the field to be searched - if the name is duplicated
		if ($CFG['useAlternativeNames']['customers'])
		{
			$searchSQL .= " AND (ent.lastName LIKE ? OR ent.lastName2 LIKE ?) AND (ent.firstName LIKE ? OR ent.firstName2 LIKE ?)";
			$sqlVals= [$lastNameString, $lastNameString, $firstNameString, $firstNameString];
			$sqlValsMixed= [$firstNameString, $firstNameString, $lastNameString, $lastNameString];
		}
		// add the field to be searched - if the name is NOT duplicated
		else {
			$searchSQL .= " AND ent.lastName LIKE ? AND ent.firstName LIKE ?";
			$sqlVals= [$lastNameString, $firstNameString];
			$sqlValsMixed= [$firstNameString, $lastNameString];
		}

		// set the limit
		$searchSQL .= ' LIMIT '.$this->limitResultsPerCriterion;


		// RUN THE SQL(S) AND MERGE THE LISTS -----------------------------------------------------
		$list1 = $this->searchRecordsRunSQL($searchSQL, $sqlVals);
		if ($options['searchMixed']) {
			$list2 = $this->searchRecordsRunSQL($searchSQL, $sqlValsMixed);
		} else {
			$list2 = [];
		}

		return $list1 + $list2;

	}


	/**
	 * Filters by corporate id but also eliminates passengers matched by email/telephone with different names.
	 * @see \App\EntityMatch\BaseAbstract::cleanMatches()
	 */
	protected function cleanMatches()
	{

		// FILTER BULK MATCHES (by corporation) ---------------------------------------------------
		if ($this->idCorporateFilter) {
			foreach($this->bulkMatches as $idx=>$matchesList) {
				foreach($matchesList as $entCode=>$entDet) {
					if ($entDet['idCorporate']!=$this->idCorporateFilter) {
						unset($this->bulkMatches[$idx][$entCode]);
					}
				}
			}
		}

		// ELIMINATE CUSTOMERS MATCHED BY EMAIL/TELEPHONE WITH DIFFERENT NAME ---------------------

		// get first/last name from criteria
		$lastName = $firstName = '';
		foreach($this->criteriaList as $criterion) {
			if ($criterion['field']=='name') {
				$lastName = mb_strtoupper((string)$criterion['value']['lastName']);
				$firstName = mb_strtoupper((string)$criterion['value']['firstName']);
				break;
			}
		}

		// eliminate psgs matched by email/telephone but with different names
		if ($lastName and $firstName) {
			foreach($this->bulkMatches as $idx=>$matchesList) {
				foreach($matchesList as $entCode=>$entDet) {
					if (
						( $entDet['_matchedField']=='email' or $entDet['_matchedField']=='telephone' or $entDet['_matchedField']=='telephoneMobile' ) and
						( $lastName!=mb_strtoupper((string)$entDet['lastName']) or $firstName!=mb_strtoupper((string)$entDet['firstName']) )
					) {
						unset($this->bulkMatches[$idx][$entCode]);
					}
				}
			}
		}

		// ELIMINATE CUSTOMERS MATCHED BY NAME BUT WITH DIFFERENT PNC -----------------------------
		if ($this->bulkMatches) {
			// get PNCs from criteria list
			$PNCs = [];
			foreach($this->criteriaList as $criterion) {
				if ($criterion['field']=='PNC' and $criterion['value']) {
					$PNCs[] = $criterion['value'];
				}
			}
			// if at least one PNC was set to be matched
			if ($PNCs) {
				foreach($this->bulkMatches as $idx=>$matchesList) {
					foreach($matchesList as $entCode=>$entDet) {
						if ( $entDet['_matchedField']=='name' and  $entDet['PNC'] and !in_array($entDet['PNC'], $PNCs)) {
							unset($this->bulkMatches[$idx][$entCode]);
						}
					}
				}
			}
		}

		// ELIMINATE CUSTOMERS MATCHED BY NAME BUT WITH DIFFERENT EMAIL ---------------------------
		if ($this->bulkMatches) {
			// get emails from criteria list
			$emails = [];
			foreach($this->criteriaList as $criterion) {
				if ($criterion['field']=='email' and $criterion['value']) {
					$emails[] = mb_strtoupper($criterion['value']);
				}
			}
			// if at least one email was set to be matched
			if ($emails) {
				foreach($this->bulkMatches as $idx=>$matchesList) {
					foreach($matchesList as $entCode=>$entDet) {
						if ( $entDet['_matchedField']=='name' and  $entDet['email'] and !in_array(mb_strtoupper($entDet['email']), $emails)) {
							unset($this->bulkMatches[$idx][$entCode]);
						}
					}
				}
			}
		}

		$bulkMatches = $this->bulkMatches;

		// allow plugins to affect the cleaning process even more
		\Engine\Plugins\Manager::getInstance()->executeEvent('App/EntityMatch/Customer-cleanMatches', ['object' => $this, 'bulkMatches'=>&$bulkMatches]);

		// eliminate empty values
		$this->bulkMatches = array_filter($bulkMatches);

	}


}

