<?php
/**
 * Define a client.
 * @author Charles DUBOIS
 * @category Plugin
 * @license MIT
 */
class Client extends Entity{
	public $id;
	public $label; //Libellé (Texte)
	public $name; //Libellé (Texte)
	public $firstname; //Libellé (Texte)
	public $state; //Etat (Liste classique)
	public $pseudonym; //Pseudonyme, Acronyme... (Texte)
	public $code; //Code client (Texte)
	public $category; //Categorie client (Liste configurable)
	public $siret; //N° SIRET (Texte)
	public $comment; //Commentaire (Texte Long)
	public $slug; //Identifiant unique (Texte)
	public $type; //Type (Particulier ou Entreprise) (Liste classique)
	public $condition; //Condition (prospect ou client) (Liste classique)
	public $parent; //Client parent (Entier)
	public $job; //Métier (Texte)
	public $meta; //Meta (JSON)
	public $firm; //Etablissement (Entier)

	protected $TABLE_NAME = 'client';
	public $entityLabel = 'Client';
	public $fields = array(
		'id' => array('type'=>'key', 'label' => 'Identifiant'),
		'label' => array('type'=>'text', 'label' => 'Libellé'),
		'name' => array('type'=>'text', 'label' => 'Nom'),
		'firstname' => array('type'=>'text', 'label' => 'Prénom'),
		'state' => array('type'=>'list', 'label' => 'Etat'),
		'pseudonym' => array('type'=>'text', 'label' => 'Pseudonyme'),
		'code' => array('type'=>'text', 'label' => 'Code client'),
		'category' => array('type'=>'dictionary', 'label' => 'Catégorie','link'=>'class/Dictionary.class.php'),
		'siret' => array('type'=>'text', 'label' => 'N° SIRET'),
		'comment' => array('type'=>'textarea', 'label' => 'Commentaire'),
		'slug' => array('type'=>'text', 'label' => 'Slug'),
		'type' => array('type'=>'list', 'label' => 'Type (Particulier ou Entreprise)'),
		'condition' => array('type'=>'list', 'label' => 'Condition (prospect ou client)'),
		'parent' => array('type'=>'int', 'label' => 'Id client parent','link'=>'plugin/client/Client.class.php'),
		'meta' => array('type'=>'textarea', 'label' => 'Meta'),
		'job' => array('type'=>'text', 'label' => 'Métier'),
		'firm' => array('type'=>'int', 'label' => 'Etablissement','link'=>'class/Firm.class.php')
	);



	//Colonnes indexées
	public $indexes = array('parent','category','type','firm');

	public function __construct(){
		parent::__construct();
		$this->state = self::ACTIVE;
	}

	public function save(){
		if(empty($this->slug)){
			$this->slug = slugify($this->label);
			for($i = 2;$i<1000;$i++){
				if(self::rowCount(array('slug'=>$this->slug)) == 0) break;
				$this->slug = slugify($this->label).'-'.$i;
			}
		}
		parent::save();
		if(empty($this->code)){
			$this->code = self::code($this);
			for($i = 2;$i<1000;$i++){
				if(self::rowCount(array('code'=>$this->code)) == 0) break;
				$this->code = self::code($this).'-'.$i;
			}
			$this->save();
		}
	}

	public function meta($key=null,$value=null){
		$meta = json_decode($this->meta,true);
		$meta = !$meta ? array(): $meta ;

		if(!isset($key) && !isset($value)) return $meta;
		if(!isset($value)) return isset($meta[$key])?$meta[$key]:'';
		$meta[$key] = $value;
		$this->meta = json_encode($meta);
	}

	public function condition(){
		return self::conditions($this->condition);
	}

	public function type(){
		return self::types($this->type);
	}


	public function dir(){
		return File::dir().'client'.SLASH.$this->id.SLASH;
	}

	public function logo($returnPath = false){
		$mask = $this->dir().'logo.*';
		$files = glob($mask);

		if($returnPath) return isset($files[0]) ? $files[0] : __DIR__.SLASH.'img'.SLASH.'default-logo.png';
		return isset($files[0]) ? 'action.php?action=client_assets_load&type=logo&client='.$this->id : 'action.php?action=client_assets_load&type=logo';
	}

	public function cover($returnPath = false){
		$mask = $this->dir().'cover.*';
		$files = glob($mask);
		if($returnPath) return isset($files[0]) ? $files[0] : __DIR__.SLASH.'img'.SLASH.'default-cover.jpg';
		return isset($files[0]) ? 'action.php?action=client_assets_load&type=cover&client='.$this->id : 'action.php?action=client_assets_load&type=cover';
	}

	//Vérification des doublons par libellés
	public static function check_duplicate($field,$label,$omitId = null){
		$rows = array();
		switch($field){
			case 'label':
				$query = 'SELECT * FROM {{table}} WHERE (soundex(?) = soundex(label) OR label=? OR label like ?)';
				$data = array($label,$label,$label);
				if(isset($omitId)){
					$query .= ' AND id!=?';
					$data[] = $omitId;
				}
				$regex = '/\s(d(es?|u)|l(a|es?)|une?|à)\s/i';
				$rows = self::staticQuery($query,$data,true);
				foreach ($rows as $key => $row) {
					$rows[$key] = $rows[$key]->toArray();
					//supression des articles définis/indefinis pour plus de pertinence
					$new = preg_replace($regex,' ',mb_strtolower($label));
					$existing =  preg_replace($regex,'',mb_strtolower($rows[$key]['label']));
					$rows[$key]['levenshtein'] =  levenshtein($existing,$new);
					if($rows[$key]['levenshtein']>3) unset($rows[$key]);
				}
				//tri par levenstein
				usort($rows,function($a,$b){
					return $a['levenshtein'] > $b['levenshtein'];
				});
			break;
			case 'mail':
			case 'phone':
				$type = $field == 'mail' ? Contact::PROFESSIONAL_MAIL : Contact::MOBILE;
				foreach(Contact::loadAll(array(
					'type' => $type,
					'state' => Contact::ACTIVE,
					'value' => trim($label),
					'scope' => 'client'
				)) as $item){
					$client = Client::getById($item->uid);
					$row = $client->toArray();
					$row['levenshtein'] = 1;
					$rows[] = $row;
				}
			break;

			case 'siret':
				foreach(Client::loadAll(array(
					'siret' => trim($label),
					'state' => Contact::ACTIVE
				)) as $item){
					$row = $item->toArray();
					$row['levenshtein'] = 1;
					$rows[] = $row;
				}
			break;
			default:
				return;
			break;
		}


		return $rows;
	}

	//Fusionne le client spécifié avec l'instance de client depuis lequel est appellé la méthode
	// le tableau keeping définis quel coté écrase l'autre dans le cas ou les deux clients sont renseignés (left = instance, right = parametre client)
	public function merge($client,$keeping = array()){

		$logs = array('Fusion du client '.$client->label().' (#'.$client->id.') sur '.$this->label().' (#'.$this->id.')  ');

		Plugin::callHook('client_merge',array($this,$client,&$logs));
		foreach ($keeping as $key => $value) {
			if(!empty($this->$key) && empty($client->$key)){
				$logs[] = $key.' origine : renseigné, fusionné : non renseigné';
				continue;
			}
			if($this->$key == $client->$key){
				$logs[] = $key.' origine et fusionné identiques';
				continue;
			}
			if(empty($this->$key) && !empty($client->$key)){
				$this->$key = $client->$key;
				$logs[] = $key.' origine : non renseigné, fusionné : renseigné';
				continue;
			}
			if(!empty($this->$key) && !empty($client->$key)){
				$logs[] = $key.' origine :  renseigné, fusionné : renseigné, utilisation du tableau d\'ecrasement';
				if($value == 'left') continue;
				if($value == 'right') $this->$key = $client->$key;
			}
		}
		$logs[] = 'Sauvegarde du client d\'origine';
		$this->save();
		$logs[] = 'Suppression du client fusionné';
		self::delete(array('id'=>$client->id));
		return $logs;
	}

	public static function conditions($key = null){
		global $conf;
		$conditions = array(
			'prospect' => array('label' =>'Prospect'),
			'client' => array('label' => ucFirst($conf->get('client_label_singular'))),
		);
		if(!isset($key)) return $conditions;
		return isset($conditions[$key]) ? $conditions[$key] : array('label' =>'Inconnu');
	}

	public static function types($key = null){
		$types = array(
			'individual' => array('label' =>'Personne'),
			'firm' => array('label' =>'Structure'),
		);
		if(!isset($key)) return $types;
		return isset($types[$key]) ? $types[$key] : array('label' =>'Inconnu');
	}

	public static function addressType($key = null){
		$types = array(
			'global' => array('label' =>'Général','icon'=>'far fa-building'),
			'invoice' => array('label' =>'Facturation','icon'=>'fas fa-file-invoice-dollar'),
			'shipping' => array('label' =>'Livraison','icon'=>'fas fa-shipping-fast')
		);
		Plugin::callHook('client_address_type',array($types) );
		if(!isset($key)) return $types;
		return isset($types[$key]) ? $types[$key] : array('label' =>'Inconnu');
	}

	public static function internals($key = null){
		$internals = array(
			'commercial' => array('label' =>'Commercial'),
			'technician' => array('label' =>'Technicien')
		);
		if(!isset($key)) return $internals;
		return isset($internals[$key]) ? $internals[$key] : array('label' =>'Inconnu');
	}

	public static function code($client){
		global $conf;

		$mask = empty($conf->get('client_code_mask')) ? '{{label[2]}}-{{Y}}{{M}}-{{id}}' : $conf->get('client_code_mask');
		$data = $client->toArray();

		$data['label'] = $client->label();

		$data['M'] = date('m');
		$data['m'] = date('m');
		$data['Y'] = date('Y');
		$data['y'] = date('y');

		$mask = preg_replace_callback('/{{label\[([0-9]*)\]}}/is', function($matches) use ($client){
			if(count($matches)>=1){
				return strlen($client->label>=$matches[1]) ? substr($client->label, 0,$matches[1]) : $client->label;
			}else{
				return $matches[0];
			}
		}, $mask);
		$mask = preg_replace_callback('/{{rand\(([0-9]*),([0-9]*)\)}}/is', function($matches){
			if(count($matches)>=2){
				return mt_rand($matches[1],$matches[2]);
			}else{
				return $matches[0];
			}
		}, $mask);

		$value = template($mask,$data,true);
		return strtoupper(slugify($value));
	}

	//Récupere les adresses du client, de son parent, de ses enfants et de ses frêres
	public function addresses($type = null,$order='zip',$limit = null, $parent = false, $siblings = false, $childs = false){
		$queryFilters = '';
		$data = array();

		if ($parent) {
			$queryFilters .= ' OR id=(SELECT parent FROM client WHERE id=?) ';
			$data[] = $this->id;
		}
		if ($siblings) {
			$queryFilters .= ' OR parent = (SELECT parent FROM client WHERE id=?) ';
			$data[] = $this->id;
		}
		if ($childs) {
			$queryFilters .= ' OR parent = ? ';
			$data[] = $this->id;
		}

		$query = 'SELECT address.*, client.label FROM `address`
				LEFT JOIN client ON address.uid = client.id
				WHERE uid IN (SELECT id FROM client WHERE id = ? '.$queryFilters.' ) AND scope="client" ';
		$data[] = $this->id;

		if(isset($type))
			$query.= ' AND address.type ="'.$type.'" ';

		if(isset($order))
			$query.= ' ORDER BY '.$order;

		if(isset($limit))
			$query.= ' LIMIT '.$limit;

		//todo gérer  + de 1 niveau
		$address = Address::staticQuery($query,$data,true);
		if (isset($order) && $order == 'fullname') {
			usort($address,function($a,$b){
				if($a->fullName() == $b->fullName()) return 0;
				return $a->fullName() > $b->fullName() ? 1 :-1 ;
			});
		}
		return $address;
	}

	public function contacts($key=null){
		$contacts = array();
		$filters = array('uid'=>$this->id,'scope'=>'client') ;
		if(isset($key)) $filters['type'] = $key;

		foreach(Contact::loadAll($filters) as $contact){
			$contacts[$contact->type] = $contact;
		}
		if(!isset($key)) return $contacts;
		return isset($contacts[$key]) ? $contacts[$key] : new Contact();
	}

	public function subsites(){
		return $this->id!=0 ? Client::loadAll(array('parent'=>$this->id)) : array();
	}

	public function holding(){
		return $this->id!=0 && $this->parent!=0 ? Client::getById($this->parent) : new Client();
	}

	public function label(){
		return $this->type=='individual' ? $this->firstname.' '.$this->name : $this->label;
	}

	public function remove($recursive = false){
		$this->state = Client::INACTIVE;
		$this->save();

		if($recursive){
			foreach(Client::loadAll(array('parent'=>$this->id,'state:!='=>Client::INACTIVE)) as $subclient){
				$subclient->remove();
			}
		}
		global $myFirm;
		//Gestion des champs dynamiques
		if($myFirm->has_plugin('fr.core.dynamicform')){
			Plugin::need('dynamicform/DynamicForm');
			Dynamicform::remove('client-sheet-custom',array(
				'scope'=>'client',
				'uid'=>$this->id
			));
		}

		ContactPerson::change(array('state'=>Client::INACTIVE),array('scope'=>'client','uid'=>$this->id));
		Address::delete(array('scope'=>'client','uid'=>$this->id));
	}
}
?>