<?php

class RegleExpert {
	
	//********************************************************************************************
	//
	// VARIABLES
	// 
	//********************************************************************************************/
	
	
	// Oid de la règle
	private $oid;
	        
	// Oid du contrôle auquel appartient la règle
	private $controle_id;
	        
	// Conditions de sélection de la règle (Clause WHERE de la requête)
	private $sqlcmd_where;
	        
	// Liste de champs à retourner en guise de justificatif (séparée par une virgule, un espace, une barre verticale,...)
	private $sqlcmd_justificatif;
	        
	// Numéro d'ordre de la règle dans le contrôle
	private $numero;
	        
	// Oid de la table sur laquelle va être exécutée la règle
	private $table_id;
	        
	// Table sur laquelle va être exécutée la règle
	private $table;
	
	// Connexion à la base de données iCTI
	private $database;
	
	// Message d'erreur alimenté en cas d'erreur, justement
	private $error;
	
	// Tableau de résultats de la rèle (voir ControleExpert->aggregate_retults() pour détails)
	private $results;
	
	// Date de sortie des séjours à partir de laquelle on peut lancer les contrôles expert
	private $expert_date_debut;
	
	// Etat des dossiers ciblés 0:Tous, 1:Présents, 2:Non facturés, ...
	private $etat_cible;
	
	//********************************************************************************************
	//
	// PUBLIC FUNCTIONS
	// 
	//********************************************************************************************/
	
	function  __construct() {
		
		// Initialisation des paramètres
		$this->oid = -1;
		$this->controle_id = -1;
		$this->sqlcmd_where = '';
		$this->sqlcmd_justificatif = '';
		$this->numero = 0;
		$this->table_id = -1;
		$this->table = array();
		$this->database = null;
		$this->error = '';
		$this->results = array();
		$this->expert_date_debut = '';
		$this->etat_cible = array();
	}
	
	
	
	public function __set($property, $value) {
		if (property_exists($this, $property)) {
			$this->$property = $value;
		}
		return $this;
	}
	
	
	
	public function __get($property) {
		if (property_exists($this, $property)) {
			return $this->$property;
		}
    }
	
	
	
	/**
	 * Exécute la règle expert
	 * 
	 * Deux tableaux seront générés pour chaque ligne (séjour) retournée : un pour les informations fixes et un pour les
	 * justiicatigs de la règle. Ces tableaux sont ajoutés au tableau $results[sejour_id]
	 */
	public function run() {
	
		$succes = false;
		
		// Vérifie l'existance des justificatifs dans la table à interroger et ajoute les champs à sélectionner d'office
		$what = $this->what_to_select();
		// Met en forme le where de la requete de sélection
		$where_conditions = $this->which_conditions($this->table['fictive']);
		
		if (strlen($what) > 0 || $this->table['fictive'] == true) {
			
			// Construit et exécute prprement dit la requête de la règle
			if ($this->table['fictive'] == true) {
				$request = $this->sqlcmd_where . $where_conditions . ";";
			}
			else {
				$request = "SELECT " . $what . " FROM " . $this->table['from'] . $where_conditions . ";";
			}
			// file_put_contents('yep.txt', $request . PHP_EOL , FILE_APPEND);
			$result = $this->database->exec($request);
			if ($result === false) {
				// N'écrase pas une erreur déjà explicitée par les sous-fonctions
				if (strlen($this->error) == 0) {
					$this->error =  "Erreur pendant l'exécution de la règle n°" . $this->numero . " : requête erronée." . PHP_EOL;
				}
			}
			else {
				
				while ($row = pg_fetch_array($result)) {
				
					$i = pg_num_fields($result);
					// Tableau des justificatifs demandés
					$justificatifs = array();
					// Tableau des infos fixes
					$infos = array();
					
					for ($j = 0; $j < $i; $j++) {
						// Si le champ retourné fait partie des justificatifs, on le stocke daans le tableau $justificatifs
						// Si non dans le tablau des infos
						$field_name = pg_field_name($result, $j);
						if (stripos($this->sqlcmd_justificatif, $field_name) === false) {
							$infos[$field_name] = $row[$j];
						}
						else {
							$justificatifs[$field_name] = $row[$j];
						}
					}
					// Stocke les infos et les justificatifs dans les réultats du séjour
					$this->results[$row['sejour_id']]['infos'] = $infos;
					$this->results[$row['sejour_id']]['justificatifs'] = $justificatifs;
				}
				$succes = true;
			}
		}
		else {
			$this->error .=  "Règle" . $this->numero . " ignorée, justificatif non traité." . PHP_EOL;
		}
		return $succes;
	}
	
	
	
	//********************************************************************************************
	//
	// PRIVATE FUNCTIONS
	// 
	//********************************************************************************************/
	
	/**
	 * $this->sqlcmd_justificatif représente une suite de champs à retourner comme justificatif du contrôle.
	 * Ces champs peuvent être délimités par un espace (\s) ou les caractètres ,;:|
	 * 
	 * On cherche l'existance de chacun de ces champs dans la table $table sur laquelle est exécutée la règle et
	 * on les concatène dans une chaîne de caractère séparée par des virgules.
	 * Cette fonction permet donc de valider l'existance des champs à retourner et les met en forme
	 */
	private function what_to_select() {
	
		$rets = array();
		// Par défaut, on va toujours récupérer les chaps définis dans la variable $this->table['defaults']
		foreach($this->table['defaults'] as $default) {
			$rets[] = $default;
		}
		
		// Les champs de la variable $this->sqlcmd_justificati peuvent être séparés par un espace, une virgule, un point-virgule, deux-points ou une barre verticale
		$fields = preg_split("/[\s,;:\|]+/", $this->sqlcmd_justificatif);
		foreach($fields as $field) {
			// Si le champ à retourner existe ben en base (= dans la propritété 'fields' de $this->table), on l'ajoute à la liste des champs à retourner
			if (in_array($field, $this->table['fields'])) {
				$rets[] = $this->table['name'] . '.' . $field;
			}
		}
		return implode(', ', $rets);
	}
	
	
	
	/**
	 * Construit le filtre de la requête de sélection du contrôle expert
	 * Notez que les règles ne s'éxécutent pas sur les séjours prévus
	 */
	private function which_conditions($sql_brut=false) {
	
		$partie_fixe = " AND date_sortie >= '" . $this->expert_date_debut . "'::date " .
				$this->etat_cible['where'] .
				" AND code_prevu <> '1' " .
				" AND type_sejour <> '9' ";
		
		if (strlen($this->sqlcmd_where) == 0) {
			return '';
		}
		else if ($sql_brut == true) {
			return $partie_fixe;
		}
		else {
			return " WHERE 1=1 AND (" . $this->explicit_where($this->sqlcmd_where) . ") " . $partie_fixe;
		}
	}
	
	
	/**
	 * Analyse le WHERE de la requête de sélection de la règle et tente de remplacer les éventuels TAGS
	 *
	 * [LI:xxxx] : remplace ce tag par la liste des oids pointés par la liste xxxx
	 *
	 * @param	$where	Chaîne de caractère à analyser
	 */
	private function explicit_where($where) {
		
		// Recherche toutes les occurences du pattern suivant [LI:xxxx] où xxxx est le code de la liste concernée
		// Les résultats sont stockés dans le tableau $listes.
		// $listes
		//		[0] =>
		//				[0] => [LI:zzzz]
		//				[1] => zzzz
		//		[1] =>
		//				[0] => [LI:yyyy]
		//				[1] => yyyy
		// quelques tags intéressants pour les regexp : http://fr2.php.net/manual/fr/function.preg-match.php#105924
		$listes = array();
		
		if (preg_match_all('/\[LI:([^\]]*)\]/', $where, $listes, PREG_SET_ORDER) > 0) {
			foreach($listes as $liste) {
				$oids = ' (' . $this->get_liste_oids(trim($liste[1])) . ') ';
				$where = str_replace($liste[0], $oids, $where);
			}
		}
		return $where;
	}
	
	
	/**
	 * Cherche le contenu de la liste $liste et renvoie la liste des oids pointés par la liste de code $liste
	 *
	 * @param	$liste	Code de la liste dont il faut récupérer les oids
	 * @return	Chaîne de caractère des oids séparés par des virgules, exemple : 'oid1, oid2, oid3'
	 */
	private function get_liste_oids($liste) {
		
		$oids = array();
		
		$request = "SELECT to_id 
					FROM activite.t_listes JOIN activite.t_listes_contenu ON t_listes_contenu.liste_id = t_listes.oid 
					WHERE t_listes.code = '" . $liste. "' ;";
		$result = $this->database->exec($request);
		if ($result === false) {
			$this->error .= "Erreur pendant l'exécution de la règle n°" . $this->numero . " : Impossible de récupérer les données de la liste " . $liste . "." . PHP_EOL;
		}
		else {
			if (pg_num_rows($result) < 1) {
				$this->error .= "Erreur pendant l'exécution de la règle n°" . $this->numero . " : Liste '" . $liste . "' vide ou inexisante." . PHP_EOL;
			}
			while ($row = $this->database->nextRecord($result)) {
				$oids[] = $row[0];
			}
		}
		return implode(', ', $oids);
	}
}

?>