<?php
/**
 * Define a address.
 * @author Valentin CARRUESCO
 * @category Plugin
 * @license MIT
 */
class Address extends Entity{
	public $id,$uid,$scope,$label,$type,$street,$complement,$city,$zip,$country,$state;

	const INVOICE  = 'invoice';
	const SHIPPING = 'shipping';
	const MAIN = 'global';
	public $entityLabel = 'Adresse';
	public $fields = array(
		'id' => array('label'=>'Identifiant','type'=>'key'),
		'uid' => array('label'=>'Identifiant de l\'Entité liée','type'=>'integer'),
		'scope' => array('label'=>'Périmetre de l\'entité liée','type'=>'text'),
		'label' => array('label'=>'Libellé','type'=>'text'),
		'type' => array('label'=>'Type','type'=>'text'),
		'street' => array('label'=>'Rue','type'=>'text'),
		'complement' => array('label'=>'Complément d\'adresse','type'=>'text'),
		'city' => array('label'=>'Ville','type'=>'text'),
		'zip' => array('label'=>'Code postal','type'=>'text'),
		'country' => array('label'=>'Pays','type'=>'text'),
		'state' => array('label'=>'Etat','type'=>'text')
	);

	public $indexes = array('uid','scope');

	public function mapUrl(){
		$encoded = urlencode($this->street).', '.urlencode($this->zip).' '.urlencode($this->city);
		return 'https://www.google.com/maps/place/'.$encoded;
	}

	//Surchage de toArray pour prendre en compte le fullName régulierement utilisé en toArray
    public function toArray($decoded=false) {
        $fields = parent::toArray($decoded);
        $fields['fullName'] = $this->fullName();

        if($decoded){
            $fields['fullName'] = html_entity_decode($fields['fullName']);
        }
        return $fields;
    }

	/**
	 * Permet de récupérer un tableau de
	 * données liées à l'adresse via l'API Here
	 *
	 * Détail des paramètres possibles : https://developer.here.com/documentation/geocoder/dev_guide/topics/resource-geocode.html
	 * Types de réponses : https://developer.here.com/documentation/geocoder/dev_guide/topics/resource-type-response-geocode.html
	 * Voir utilisation live ici : https://developer.here.com/documentation/examples/rest/geocoder/latitude-longitude-no-attributes
	 *
	 * @param $responseAttributes : Définit les attributs de réponse à récupérer, séparés par virgule (ps,mq,mt,mc,pr par défaut)
	 * Listes des possibilités:
	 *    - ps = performedSearch
	 *    - mq = matchQuality
	 *    - mt = matchType
	 *    - mc = matchCode
	 *    - pr = parsedRequest
	 *    - none = aucun attribut
	 *
	 * @param $locationAttributes : Définit les attributs de réponse à récupérer, séparés par virgule
	 * Listes des possibilités:
	 *    - ar = address
	 *    - mr = mapReference
	 *    - mv = mapView
	 *    - dt = addresseDetails
	 *    - sd = streetDetails
	 *    - ad = additionalData
	 *    - ai = adminIds
	 *    - li = linkInfo
	 *    - in = adminInfo
	 *    - none = aucun attribut
	 */
	public function infos($responseAttributes='ps,mq,mt,mc,pr', $locationAttributes='ar,mr,mv,dt,sd,ad,ai,li,in', $maxResults=null){
		global $myUser, $conf;
		if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);

		$results = array();
		$appUrl = $conf->get('maps_api_geocode_url');
		$appId = $conf->get('maps_api_id');
		$appKey = $conf->get('maps_api_key');

		//On ne throw pas d'exception pour ne pas bloquer l'utilisation
		if(empty($appUrl) || empty($appId) || empty($appKey)) {
			Log::put('Erreur de paramétrage des configurations de l\'API. URL Geocode: '.$appUrl.', API ID: '.$appId.', Taille clé privée API: '.strlen($appKey) ,'Location API');
			return $results;
		}
		//Attributs response
		$responseAttr = explode(',', $responseAttributes);
		foreach($responseAttr as $i => $attr) {
			if(!in_array($attr, array('ps','mq','mt','mc','pr','none'))) {
				unset($responseAttr[$i]);
				continue;
			}
		}
		$responseAttributes = implode(',', $responseAttr);
		if(empty($responseAttributes)) $responseAttributes = 'ps,mq,mt,mc,pr';

		//Attributs location
		$locationAttr = explode(',', $responseAttributes);
		foreach($locationAttr as $i => $attr) {
			if(!in_array($attr, array('ar','mr','mv','dt','sd','ad','ai','li','in','none'))) {
				unset($locationAttr[$i]);
				continue;
			}
		}
		$locationAttributes = implode(',', $locationAttr);
		if(empty($locationAttributes)) $locationAttributes = 'ar,mr,mv,dt,sd,ad,ai,li,in';

		$params = array(
			'searchtext' => $this->street.(!empty($this->complement)?$this->complement:'').', '.$this->zip.' '.$this->city,
			'app_id' => $appId,
			'app_code' => $appKey,
			'responseattributes' => $responseAttributes,
			'locationattributes' => $locationAttributes,
		);
		if(isset($maxResults) && is_numeric($maxResults)) $params['maxresults'] = $maxResults;

		$curlOpt = array(
			CURLOPT_URL => sprintf("%s?%s", $appUrl, http_build_query($params)),
			CURLOPT_HTTPHEADER => array(
				'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0',
				'Content-Type: application/json',
			),
			CURLOPT_RETURNTRANSFER => 1,
			CURLOPT_HTTPAUTH => CURLAUTH_ANY,
			CURLOPT_SSL_VERIFYPEER => false,
			CURLOPT_SSL_VERIFYHOST => false,
		);
		$ch = curl_init();
		curl_setopt_array($ch, $curlOpt);

		$response = curl_exec($ch);
		if($response === false){
			Log::put("Erreur de récupération cURL : ".curl_error($ch),'Location API');
			return $results;
		}

		$results = json_decode($response);

		//Check si le retour n'est pas une erreur
		if(!isset($results->Response)){
			Log::put(mb_strtoupper('['.$results->type.']').' '.$results->subtype.': '.$results->Details,'Location API');
			return array();
		}

		//Contrôle sur la structure de l'objet de retour
		if(!isset($results->Response->View)){
			Log::put("La structure de retour de l'API Here a été modifiée. Se référer à la documentation pour modifier la structure en conséquence",'Location API');
			return array();
		}

		if(empty($results->Response->View)){
			Log::put("Aucun résultat trouvé pour la récupération des infos de l'adresse : ".$this->toText(),'Location API');
			$results = $results->Response->View;
			return $results;
		}

		if(!isset($results->Response->View[0]->Result)){
			Log::put("La structure de retour de l'API Here a été modifiée. Se référer à la documentation pour modifier la structure en conséquence",'Location API');
			return array();
		}

		Log::put("Récupération des informations de l'adresse : ".$this->toText(),'Location API');
		return $results->Response->View[0]->Result;
		// $infos = curl_getinfo($ch);
		// curl_close($ch);
	}

	//Permet de récupérer les coordonnées géographiques
	//d'une adresse en fonction de son libellé
	public function locationCoordinates(){
		//Récupération des informations en scopant sur Lat. + Long.
		$infos = $this->infos('none', 'none', 1);

		$coordinates = array(
			'latitude' => 0,
			'longitude' => 0,
		);
		if(empty($infos) || !isset($infos[0]->Location->DisplayPosition)) return $coordinates;

		$coordinates['latitude'] = $infos[0]->Location->DisplayPosition->Latitude;
		$coordinates['longitude'] = $infos[0]->Location->DisplayPosition->Longitude;

		return $coordinates;
	}


	//Retourne l'adresse sur une seule ligne
	//au format : street, complement, zip city country
	public function fullName(){
		$fullname = '';
		if(!empty($this->street)) $fullname .= $this->street;
		if(!empty($this->complement)) $fullname .= ', '.$this->complement;

		if($fullname!='') $fullname .= ', ';
		if(!empty($this->zip)) $fullname .= $this->zip;
		if(!empty($this->city)) $fullname .= ' '.$this->city;
		if(!empty($this->country)) $fullname .= ', '.$this->country;

		return $fullname;
	}

	//remplis un composant location à partir des infos de la classe courante
	public function toDataAttributes($plainText=true){
		$array = array();
		$plain = '';
		foreach (array('street','complement','city','zip','country') as $key) {
			$array[$key] = $this->$key;
			$plain .= ' data-'.$key.' = "'.(empty($this->$key) ? '' : $this->$key).'"';
		}
		return !$plainText ? $array : $plain;
	}


	public function getCoordinates(){
		return self::coordinates($this->fullName());
	}

	//Récupere des latitudes/ longitudes à partir d'une adresse
	public static function coordinates($address){
		$response = file_get_contents('https://api-adresse.data.gouv.fr/search/?q='.urlencode($address));
		$response = json_decode($response,true);
		if(!$response) $response = array();
		if(isset($response['features']) && isset($response['features'][0]) && isset($response['features'][0]['geometry']) && isset($response['features'][0]['geometry']['coordinates']))
			return array('latitude'=>$response['features'][0]['geometry']['coordinates'][0],'longitude'=>$response['features'][0]['geometry']['coordinates'][1]);
	}

	public static function types($key=null){
		$types = array(
			self::MAIN => array(
				'label' => "Adresse générale",
				'icon' => "fas fa-map-marker-alt",
				'color' => "#4dabf7",
			),
			self::INVOICE => array(
				'label' => "Adresse de facturation",
				'icon' => "fas fa-receipt",
				'color' => "#4dabf7",
			),
			self::SHIPPING => array(
				'label' => "Adresse de livraison",
				'icon' => "fas fa-shipping-fast",
				'color' => "#4dabf7",
			)

		);
		Plugin::callHook('address_types', array(&$types));
		if(!isset($key)) return $types;
		return isset($types[$key]) ? $types[$key] : array('label'=>'non définit','icon'=>'','color'=>'');
	}
}
?>
