<?php

/**
 * Fonctions pour le traitement par lot
 *
 * L'importation par lot des observations traite en entrée un fichier XML.
 * Plusieurs schémas sont supportés.
 * Dans un étape intermédiaire, ce fichier XML est transformé
 * en un fichier d'ordres logiques d'importation, lui même au format XML, via une
 * transformation XSL. Les ordres obtenus sont de deux types : des ordres de
 * création et des ordres de liaison.
 * Les ordres de création créent de nouvelles observations ou de nouvelles fiches
 * espèces. Les ordres de liaison établissent des liens entre les objets 
 * obsevation, fiche, auteur, ...
 * On trouve ici les différents traitements du fichier d'ordres logiques :
 * conversion en ordres SQL ou SPIP, contrôles et exécution des ordres obtenus.
 * Les transformations des fichiers XML initiaux en fichiers d'ordres logique
 * est à la charge des traitements des différents formulaires.
 *
 * @plugin     	Biodiv
 * @copyright  	2008-2025
 * @author     	Renaud LAURETTE
 * @licence    	GNU/GPL
 * @package    	SPIP\Biodiv\Fonctions
 * @formulaire	FORMULAIRE_ORDONNER_BIODIV
 * @since		2.23
 */


include_spip('base/abstract_sql');
include_spip('action/editer_objet');
include_spip('inc/invalideur');

/**
 * Ordre générique de liaison
 *
 * Une fonction plus spécialisée est appelée en fonction du type d'objet à lier.
 * Pour l'instant, seul le type 'observation' est considéré.
 * Si l'ordre utilise une référence 'self' au lieu d'un identifiant d'objet, le
 * 'self' est remplacé par l'identifiant fourni en paramètre.
 * Le paramètre $self n'est pas utilisé quand la liaison concerne un objet déjà
 * existant lors de l'export Freemind.
 *
 * @uses	ordreLierObservation()
 * @uses	executerUpdate()
 *
 * @param 	array 			$lier		Ordre logique de liaison
 * @param 	string|int|null $self		Identifiant à substituer
 * @return 	array						Ordre SQL exécuté
 */
function ordreLier($lier,$self=null)
{
	$ordre= null;
	foreach($lier->attributes() as $key => $value) { 
	  if($value == 'self') $lier[$key]=$self;
	}
	
	switch($lier['xObjet']) {
	case 'observation':
		$ordre = ordreLierObservation($lier);
		executerUpdate($ordre);
		break;
	default:
		break;
	}
	
	return $ordre;
}

/**
 * Préparation de l'ordre de liaison d'une observation
 *
 * Convertit un ordre logique de liaison en un ordre SQL concret qui sera exécuté
 * via `sql_updateq($ordre['table'],$ordre['values'],$ordre['where'])`.
 * L'ordre est valide si `$ordre['pret']=true`.
 * Sinon l'erreur est dans `$ordre['erreur']`.
 * La nature de la liaison à établir est définie par `$lier['xRelation']` ; elle
 * détermine le type d'objet auquel l'observation doit être liée.
 *
 * @uses	ordre_controlerLienObservation()
 * @uses	ordre_controlerId()
 * @uses 	ordre_controlerAuteurObservation()
 * @uses	ordre_retirerOperateurObservation()
 * @uses	trouver_taxon()
 *
 * @param 	array 	$lier	Ordre logique à préparer
 * @return 	array			Ordre SQL préparé
 */
function ordreLierObservation($lier)
{
	$ordre = array();
	$ordre['pret'] = false;
	$ordre['skip'] = false;
	$ordre['type'] = 'lier';
	
	if(	isset($lier['id_observation']) 
	    and isset($lier['xRelation'])
    	    ) {
    		// Pour que la liaison s'effectue, il est nécessaire que l'observation existe : on vérifie
    		if(sql_countsel('spip_biodiv_observations', 'id_observation='.intval((string)$lier['id_observation'])) != 0) {
    			// elle existe : on prépare les élément de la requete SQL
    			$ordre['table'] = 'spip_biodiv_observations';
    			$ordre['where'] = 'id_observation='.intval((string)$lier['id_observation']);
		
    			switch($lier['xRelation']) {
    			case 'observation.campagne':
    				// Lier une observation à une campagne
    				// Lien particulier passant par une table de liens
    				ordre_controlerLienObservation($ordre,$lier,$lier['id_observation'],'campagne','id_campagne','spip_biodiv_campagnes');
    				$ordre['invalideur'] = array(
    					"id='campagne/".$lier['id_campagne']."'",
    					"id='observation/".$lier['id_observation']."'"
    					); 
    				$ordre['event'] = array(
    					'id_observation' => $lier['id_observation'],
    					'objet' => 'campagne',
    					'nature' => 'campagne',
    					'id_objet' => $lier['id_campagne']
    					);
    				break;
    			case 'observation.expo':
    				// Lier une observation à un panneau d'exposition
    				// Lien particulier passant par une table de liens
    				ordre_controlerLienObservation($ordre,$lier,$lier['id_observation'],'article','id_article','spip_articles');
    				$ordre['invalideur'] = array(
    					"id='article/".$lier['id_article']."'",
    					"id='observation/".$lier['id_observation']."'"
    					); 
    				$ordre['event'] = array(
    					'id_observation' => $lier['id_observation'],
    					'objet' => 'article',
    					'nature' => 'exposition',
    					'id_objet' => $lier['id_article']
    					);
    				break;
    			case 'observation.famille':
    				// L'ordre est de lier une observation à une famille (rubrique)
    				// On controle l'existance de la rubrique et on complète l'ordre
    				ordre_controlerId($ordre,$lier,'id_famille','id_rubrique','spip_rubriques');
    				// Lier une observation à une famille casse obligatoirement le lien éventuel
    				// qui existait avec une espèce
    				$ordre['values']['id_espece']=0;
    				// $ordre['values']['statut']='prop';
    				$ordre['invalideur'] = array(
    					"id='rubrique/".$lier['id_famille']."'",
    					"id='observation/".$lier['id_observation']."'"
    					);
    				$ordre['event'] = array(
    					'id_observation' => $lier['id_observation'],
    					'objet' => 'rubrique',
    					'nature' => 'famille',
    					'id_objet' => $lier['id_famille']
    					);
    				break;
    			case 'observation.espece':
    				// L'ordre est de lier une observation à une espèce (article)
    				// On controle l'existance de l'article et on complète l'ordre
    				ordre_controlerId($ordre,$lier,'id_espece','id_article','spip_articles');
    				// Lier une observation à une espèce casse obligatoirement le lien éventuel
    				// qui existait avec une famille
    				$ordre['values']['id_famille']=0;
    				// $ordre['values']['statut']='publie';
    				$ordre['invalideur'] = array(
    					"id='article/".$lier['id_espece']."'",
    					"id='observation/".$lier['id_observation']."'"
    					);
    				$ordre['event'] = array(
    					'id_observation' => $lier['id_observation'],
    					'objet' => 'article',
    					'nature' => 'espece',
    					'id_objet' => $lier['id_espece']
    					);
    				break;
    			case 'observation.taxon':
    				// On recherche l'espèce via le taxon grace au cd_nom
    				// en cas de succes on lie à l'espèce   				
    				if(trouver_taxon($lier)) {
    					ordre_controlerId($ordre,$lier,'id_espece','id_article','spip_articles');
    					$ordre['values']['id_famille']=0;
    					$ordre['values']['statut']='publie';
    					$ordre['invalideur'] = array(
    						"id='article/".$lier['id_espece']."'",
    						"id='observation/".$lier['id_observation']."'"
    						);    				
    					$ordre['event'] = array(
    						'id_observation' => $lier['id_observation'],
    						'objet' => 'article',
    						'nature' => 'espece',
    						'id_objet' => $lier['id_espece']
    						);
    				} else {
    				    $ordre['erreur'] = _T('biodiv:msg_base_lien_manquant');
    				    $ordre['skip'] = true;
    				}
    				break;
    			case 'observation.sujet':
    				ordre_controlerId($ordre,$lier,'id_sujet','id_article','spip_articles');
    				$ordre['invalideur'] = array(
    						"id='article/".$lier['id_sujet']."'",
    						"id='observation/".$lier['id_observation']."'"
    						); 
    				$ordre['event'] = array(
    					'id_observation' => $lier['id_observation'],
    					'objet' => 'article',
    					'nature' => 'sujet',
    					'id_objet' => $lier['id_sujet']
    					);
    				break;
    			case 'observation.source':
    				ordre_controlerId($ordre,$lier,'id_source','id_source','spip_biodiv_sources');
    				$ordre['values']['ref_source']=$lier['ref_source'];
    				$ordre['invalideur'] = array(
    						"id='source/".$lier['id_source']."'",
    						"id='observation/".$lier['id_observation']."'"
    						);  
    				$ordre['event'] = array(
    					'id_observation' => $lier['id_observation'],
    					'objet' => 'source',
    					'nature' => 'source',
    					'id_objet' => $lier['id_source']
    					);
    				break;	
    			case 'observation.auteur':
    				ordre_controlerAuteurObservation($ordre,$lier);
    				$ordre['invalideur'] = array(
    						"id='auteur/".$lier['id_auteur']."'",
    						"id='observation/".$lier['id_observation']."'"
    						);  
    				$ordre['event'] = array(
    					'id_observation' => $lier['id_observation'],
    					'objet' => 'auteur',
    					'nature' => 'observateur',
    					'id_objet' => $lier['id_auteur']
    					);
    				break;
    			case 'observation.sans.operateur':
    				ordre_retirerOperateurObservation($ordre,$lier);
    				// L'invalideur est déjà pris en compte
    				// Pas d'event sur ce type d'action
    				break;
    			default:
    				// La relation portée par l'ordre est inconnue
    				$ordre['erreur'] = _T('biodiv:msg_relation_inconnue', array('rel'=>$lier['xRelation']));
    				break;
    			}
    		} else {
    			// L'observation à lier n'existe pas
    			$ordre['erreur'] = _T('biodiv:msg_observation_inexistante',
    						array('obs'=>intval((string)$lier['id_observation']))
    						);
    		}
    	} else {
    		// L'ordre est mal structuré
    		$ordre['erreur'] = _T('biodiv:msg_ordre_incomplet1');
    	}
	
	return $ordre;		
}

/**
 * Modifie un ordre de liaison à un taxon en retrouvant la fiche espèce associée
 * au taxon si elle existe. L'ordre devient un ordre de liaison à l'espèce.
 *
 * @param 	array &$lier	Ordre à modifier
 * @return  int|null		Identifiant de l'espèce trouvée ou null
 */
function trouver_taxon(&$lier) {
	if(isset($lier['cd_nom'])) {      
		$cdn= intval((string)$lier['cd_nom']);
		$r = sql_fetsel('id_espece','spip_taxrefs',"id_taxref=$cdn");
		if($r and isset($r['id_espece'])) {
			$v = $r['id_espece'];
			$lier['id_espece'] = $r['id_espece'];
			return $r['id_espece'];
		}
	}
	return null;
}

/**
 * Vérifie la validité d'un lien à poser
 *
 * @param array &$ordre 	L'ordre SQL à compléter, y compris avec code d'erreur éventuel
 * @param array $lier		L'ordre XML contenant les instructions
 * @param int|string $self 	La référence éventuelle à un objet (unused ?)
 * @param string $id_lien	Le nom du champ SQL qui portera le lien
 * @param string $table		Nom de la table dont la valeur de $id_lien doit être une clé
 * @param string $id_table	Le champ de la $table portant la clé
 * @return void
 */
function ordre_controlerId(&$ordre,$lier,$id_lien,$id_table,$table)
{
	$target=null;	
	// On vérifie la cohérence de l'ordre
	if(isset($lier[$id_lien])) { //Ok.	
		$target = intval((string)$lier[$id_lien]);	
		// A ce stade, $target est la cible du lien à poser.
		// On vérifie sa valeur.
		if($target) {
			// Cible non nulle. On prépare la partie "values" de l'ordre SQL update.
			$ordre['values'] = array($id_lien => $target);
			// On vérifie que la cible du lien existe dans sa table
			if(sql_countsel($table, "$id_table=$target")) { // Ok			
				$ordre['pret'] = true;
			} else { // Ko
				$ordre['erreur'] = _T('biodiv:msg_base_champ_inexistant', array('ch' => $id_lien));
			}
		} else {  // Cible nulle - non autorisé	
			$ordre['erreur'] = _T('biodiv:msg_base_lien_invalide');
		}
	} else {  // L'ordre n'est pas cohérent
		$ordre['erreur'] = _T('biodiv:msg_base_lien_manquant');
	}	
}

include_spip('inc/u_campagnes');

/**
 * Contrôle du lien à poser
 *
 * On vérifie que tous les objets existent et que le lien n'est pas déjà présent.
 * Pour les liens vers les campagnes, comme l'action est de bas niveau, on vérifie
 * en plus que les critères de la campagne (période et périmètre) sont respectés.
 *
 * @uses	observation_pour_campagne()
 *
 * @param 	array &$ordre 			l'ordre SQL à compléter
 * @param 	array $lier				l'ordre logique (XML) contenant les instructions
 * @param 	int|string $idobs		Identifiant de l'observation
 * @param 	string $objet			Type d'objet à lier
 * @param	int|string $id_table	Identifiant de l'objet à lier
 * @param	string	$table			Nom de la table de liens (unused)
 * @return 	boolean					true si lien OK
 */
function ordre_controlerLienObservation(&$ordre,$lier,$idobs,$objet,$id_table,$table)
{
	// spip_log("controlerLienObservation: ordre: ". print_r($ordre,true), "biodiv."._LOG_INFO_IMPORTANTE);
	// spip_log("controlerLienObservation: lier: ". print_r($lier,true), "biodiv."._LOG_INFO_IMPORTANTE);
	// On vérifie la cohérence de l'ordre
	if(!isset($lier[$id_table])) {
		// L'ordre n'est pas cohérent
		$ordre['erreur'] = _T('biodiv:msg_base_lien_manquant');
		return false;
	}
	
	$target = intval((string)$lier[$id_table]);	
	if($target <= 0) {
		// Index non autorisé	
		$ordre['erreur'] = _T('biodiv:msg_base_lien_invalide');
		return false;
	}			
			
	// A ce stade, $target est la cible du lien à poser. 
	// On vérifie si le lien existe déjà
	if(sql_countsel('spip_biodiv_observations_liens', array('id_observation' => $idobs, 'id_objet' => $target, 'objet' => $objet))) {
		$ordre['erreur'] = _T('biodiv:msg_base_lien_double', 
								array('type' => 'observation', 'id' => $idobs, 'objet' => $objet, 'idobj' => $target));
		return false;
	}

	// On vérifie si la cible du lien existe
	if(!sql_countsel($table, "$id_table=$target")) { 
		$ordre['erreur'] = _T('biodiv:msg_base_objet_inexistant', array('objet' => $objet, 'id' =>$target));
		return false;
	}
	
	// Pour les campagnes, on vérifie la période et le périmètre
	if(($objet == 'campagne') and is_string($e=observation_pour_campagne($idobs,$target))) {
		$ordre['erreur'] = $e;
		return false;
	}
	
	// Tout est OK
	$ordre['table'] = 'spip_biodiv_observations_liens';
	$ordre['where'] = false;
	$ordre['values'] = array(
		'id_observation' => $idobs,
		'objet' => $objet,
		'id_objet' => $target
		);
	$ordre['pret'] = true;
	return true;
}

/**
 * Vérifie la validité de l'auteur auquel se lier
 *
 * On vérifie que tous les objets existent et que le lien n'est pas déjà présent.
 * Renseigne `$ordre['pret']` et `$ordre['erreur']` selon le cas.
 *
 * @param 	array &$ordre 			l'ordre SQL à compléter
 * @param 	array $lier				l'ordre logique (XML) contenant les instructions
 * @return 	boolean					true si lien OK
 */
function ordre_controlerAuteurObservation(&$ordre,$lier) {
	// vérification de la présence des liens
	$idobs = intval((string)$lier['id_observation']);
	if(!isset($lier['id_auteur'])) {
		$ordre['erreur'] = _T('biodiv:msg_base_lien_manquant');
		return false;
	}
	
	$target = intval((string)$lier['id_auteur']);	
	if($target <= 0) {
		// Index non autorisé	
		$ordre['erreur'] = _T('biodiv:msg_base_lien_invalide');
		return false;
	}			
	// A ce stade, $target est la cible du lien. 
	// On vérifie si le lien existe déjà
	$deja = sql_countsel('spip_auteurs_liens', array('id_auteur' => $target, 'id_objet' => $idobs, 'objet' => 'observation'));	
	if($deja) {
		// On veut ajouter et le lien existe déjà
		$ordre['erreur'] = _T('biodiv:msg_base_lien_double', 
							array('type' => 'auteur', 'id' => $target, 'objet' => 'observation', 'idobj' => $idobs));
		return false;
	}
	// On vérifie si la cible du lien existe
	if(!sql_countsel('spip_auteurs', "id_auteur=$target")) { 
		$ordre['erreur'] = _T('biodiv:msg_base_objet_inexistant', array('objet' => 'auteur', 'id' =>$target));
		return false;
	}
	// Tout est OK
	$ordre['table'] = 'spip_auteurs_liens';
	$ordre['where'] = false;
	$ordre['values'] = array(
		'id_auteur' => $target,
		'objet' => 'observation',
		'id_objet' => $idobs
		);
	$ordre['nowhere'] = "id_auteur=$target AND objet='observation' AND id_objet=$idobs";
	$ordre['pret'] = true;
	return true;	
}

/**
 * Vérifie la validité de l'auteur pour le délier
 *
 * On vérifie que tous les objets existent et que le lien est présent.
 * Si le lien n'existe pas, renvoie l'ordre ... de ne rien faire.
 *
 * @param 	array &$ordre 			l'ordre SQL à compléter
 * @param 	array $lier				l'ordre logique (XML) contenant les instructions
 * @return 	boolean					true si lien OK
 */
function ordre_retirerOperateurObservation(&$ordre,$lier) {
	// vérification de la présence des liens
	$idobs = intval((string)$lier['id_observation']);
	if(!isset($lier['id_auteur'])) {
		$ordre['erreur'] = _T('biodiv:msg_base_lien_manquant');
		return false;
	}
	// On identifie les auteurs déclarés et l'operateur
	$convertIdAuteur = function($x) { return intval((string)$x); };
	$auteurs = array_map($convertIdAuteur,explode(",", $lier['id_auteur']));
	$operateur = intval((string)$GLOBALS['visiteur_session']['id_auteur']);
	$xa = serialize($auteurs);
	spip_log("BIODIV::RetirerOperateur($operateur,$xa,$idobs)","biodiv."._LOG_INFO_IMPORTANTE);

	// On se prépare à ne rien faire ...
	$ordre['type'] = 'nop';
	$ordre['skip'] = false;
	$ordre['table'] = false;
	$ordre['where'] = false;
	$ordre['values'] = false;
	$ordre['nowhere'] = false;
	$ordre['invalideur'] = array();
	$ordre['pret'] = true;
		
	if(!in_array($operateur,$auteurs)) {
		// Si l'opérateur n'est pas dans les auteurs déclarés on le supprime
		if(($operateur == 1) and (in_array(0, $auteurs))) {
			// Sauf si c'est le webmestre alors que l'auteur est inconnu
		} else {
			spip_log("BIODIV::OperateurDejaAuteur()","biodiv."._LOG_INFO_IMPORTANTE);
			$ordre['type'] = 'delier';
			$ordre['table'] = 'spip_auteurs_liens';
			$ordre['nowhere'] = "id_auteur=$operateur AND objet='observation' AND id_objet=$idobs";
			$ordre['invalideur'] = array(
    			"id='auteur/$operateur'",
    			"id='observation/$idobs'"
    			); 
		}
	}
	
	return true;
}

/**
 * Traitement générique des ordres de création
 *
 * Examine le type d'objet concerné et sous-traite à une fonction spécialisée
 *
 * @uses 	ordreCreerArticle()
 * @uses	ordreCreerObservation()
 *
 * @param 	array $creer 			l'ordre XML de création à traiter
 * @return 	array					l'ordre SQL à exécuter
 */
function ordreCreer($creer)
{
	$ordre= null;
	$ordre['type'] = 'creer';
	
	switch($creer['xObjet']) {
	case 'espece':
	case 'sujet':
	case 'expo':
		$ordre = ordreCreerArticle($creer);
		break;
	case 'observation':
		$ordre = ordreCreerObservation($creer);
		break;		
	default:
		break;
	}	
	return $ordre;
}


/**
 * Contrôle d'unicité de l'ordre par rapport à une condition logique
 *
 * Pour éviter de créer des doublons, on peut spécifier une condition sur une table
 * Si cette condition existe et est satisfaite, la donnée est considérée non unique
 * Sinon elle est considérée unique.
 * La condition est constituée d'expressions SQL élémentaires séparées par des virgules
 * Par exemple : `id_source=2,xref=28`. Les conditions sont combinées par un ET logique.
 *
 * @param 	array $creer 			l'ordre XML de création à traiter
 * @return 	boolean					true si la donnée est unique, ou non contrôlée
 */
function controleUnicite($creer) {
	if(isset($creer['uTable']) && isset($creer['uCondition'])) {
		// L'ordre fait l'objet d'un controle d'unicite
		// on récupère le critère d'unicité sous forme de tableau
		$where = explode(",",$creer['uCondition']);
		if(sql_countsel($creer['uTable'], $where) !=0) {
			// La donnee existe déjà. On génère une erreur
			return false;	
		}
	}
	// La donnée est soit unique, soit non contrôlée
	return true;
}

include_spip('action/editer_article');
include_spip('inc/modifier');


/**
 * Création d'un article sur la base d'un ordre logique
 *
 * @param 	array $creer 			l'ordre XML de création à traiter
 * @return 	array					l'ordre SQL exécuté
 */
function ordreCreerArticle($creer)
{
	$ordre = array();
	$ordre['pret'] = false;
	
	if(	isset($creer['titre']) and isset($creer['id_rubrique'])) {
    		$id_parent = intval((string)$creer['id_rubrique']);
    		if(sql_countsel('spip_rubriques', "id_rubrique=$id_parent") != 0) {
    			// creation de l'article comme coquille vide		
    			$id_article = article_inserer($id_parent);
    			if($id_article >0) {
    				// Article créé. On ajoute le contenu
    				$c = array();
    				$c['titre'] = $creer['titre'];
    				if(isset($creer['soustitre'])) $c['soustitre'] = $creer['soustitre'];
    				$c['composition'] = $creer['xObjet'];
    				$c['statut']='publie';
    				article_modifier($id_article, $c);
    				// On force le statut à 'publie'
    				/* 
    				$c = array();
    				$c['statut']='publie';
    				$err = article_instituer($id_article, $c);
    				*/
    				// Tout ok.
    				$ordre['id'] = $id_article;
    				$ordre['pret'] = true;
    			} else {
    				// Echec creation
    				$ordre['erreur'] = _T('biodiv:msg_echec_creation_article');
    			}
    		} else {
    			$ordre['erreur'] = _T('biodiv:msg_echec_auteur_ou_rubrique');	
    		}
    	    } else {
    	    	    $ordre['erreur'] = _T('biodiv:msg_ordre_incomplet2');
    	    }
    	
	return $ordre;		
}

/**
 * Création d'une observation sur la base d'un ordre logique
 *
 * @param 	array $creer 			l'ordre XML de création à traiter
 * @return 	array					l'ordre SQL exécuté
 */
function ordreCreerObservation($creer)
{	
    $ordre = array();
	$ordre['pret'] = false;
	
	if(	    isset($creer['espece'])
    	and isset($creer['date'])
    	and isset($creer['lat'])
    	and isset($creer['lng'])
    	and isset($creer['commune'])
    	and isset($creer['insee'])
    	) {
    	  $quantite = intval((string)$creer['quantite']);
    	  $quantite = ($quantite ==0 ) ? 1 : $quantite;
    	  
    	  $id_observation = objet_inserer('observation');
    	  if($id_observation>0) {
    	  	  // Article créé. On ajoute le contenu
    	  	  $c = array();	  	  
    		  $c['espece'] = strlen($creer['espece'])?$creer['espece']:$creer['binomial'];
    		  $c['titre'] = isset($creer['titre'])?$creer['titre']:$c['espece'];
    		  $c['quantite'] = $quantite;
    		  $c['discret'] = isset($creer['discret'])?$creer['discret']:"non";
    		  $c['lat'] = $creer['lat'];
    		  $c['lng'] = $creer['lng'];
    		  $c['date_obs'] = $creer['date'];   
    		  if(isset($creer['pjour'])) {
    		  	  $c['pjour'] = $creer['pjour'];
    		  }
    		  if(isset($creer['denombrement'])) {
    		  	  $c['denombrement'] = $creer['denombrement'];
    		  }
    		  if(isset($creer['adresse'])) {
    		  	  $c['adresse'] = $creer['adresse'];
    		  }
    		  $c['commune'] = $creer['commune'];
    		  $c['insee'] = $creer['insee'];
    		  if(isset($creer['descriptif'])) {
    		  	  $c['descriptif'] = $creer['descriptif'];
    		  }
    		  //$c['statut']='prepa';
    		  $err = objet_modifier('observation',$id_observation,$c);
    		  $ordre['id'] = $id_observation;
    		  $ordre['pret'] = true;
    	  } else {
    		// Echec creation
    		$ordre['erreur'] = _T('biodiv:msg_echec_creation_observation');
    	  }  
    } else {
    	$ordre['erreur'] = _T('biodiv:msg_ordre_incomplet3');
    }
    return $ordre;
}

/**
 * Création d'un lien sur la base d'un ordre SQL
 *
 * @param 	array $ordre 			l'ordre SQL de lien à exécuter
 * @return 	void					l'ordre SQL exécuté
 */
function executerUpdate($ordre)
{
	if(!$ordre['pret']) return;
	if($ordre['type']=='nop') return;
	if($ordre['skip']) return;
	
	if($ordre['where']) { // C'est un update
		// Concerne les liens uniques représentés comme champs de la table principale
		sql_updateq($ordre['table'],$ordre['values'],$ordre['where']);
	} else { // c'est un insert
		// Concerne la création des objets principaux
		// et celles des liens gérés dans une table secondaire.
		if($ordre['type'] == 'delier') {
			// Si c'est un ordre pour délier, il faut supprimer l'entrée
			sql_delete($ordre['table'],$ordre['nowhere']);
		} else {		
			// sinon (lier ou créer) on crée une entrée.
			sql_insertq($ordre['table'],$ordre['values']);
		}
	}
	
	if( isset($ordre['event']) 
		and is_array($ordre['event']) 
		and ($ordre['type']!='delier') 
		) {
		// C'est un ordre de lien d'observation
		pipeline('apres_lien_observation',$ordre['event']);
	}	

	foreach($ordre['invalideur'] as $invalideur) {
		suivre_invalideur($invalideur);
	}
}

/**
 * Gestion unitaire d'une erreur retournée par la bibliothèque libxml
 *
 * @param 	object $error 			Le descriptif de l'erreur retourné par la bibliothèque
 * @return 	string					Le message d'erreur généré
 */
function erreur_libxml($error)
{
    $return = "<br/>\n";
    switch ($error->level) {
        case LIBXML_ERR_WARNING:
            $return .= "<b>LIBXML: Attention $error->code</b>";
            break;
        case LIBXML_ERR_ERROR:
            $return .= "<b>LIBXML: Erreur $error->code</b>";
            break;
        case LIBXML_ERR_FATAL:
            $return .= "<b>LIBXML: Erreur fatale $error->code</b>";
            break;
    }
    $return .= ", ligne <b>$error->line</b> : ";
    $return .= trim($error->message) . "<br/>";
    return $return;
}

/**
 * Gestion du flux d'erreurs retourné par la bibliothèque libxml
 *
 * @uses	erreur_libxml()
 * @return 	string					Le message d'erreur généré
 */
function erreurs_libxml() {
    $errors = libxml_get_errors();
    $msg="";
    foreach ($errors as $error) {
        $msg .= erreur_libxml($error);
    }
    libxml_clear_errors();
    return $msg;
}
