<?php

/*******************************************************************************\
 * BIODIV, plugin et squelette pour SPIP - https://www.spip.net/               *
 *         dédié à la gestion d'observations naturalistes                      *
 *                                                                             *
 *         Copyright (C) 2008-2024 Renaud LAURETTE                             *
 *                                                                             *
 * BIODIV a été développé initialement pour le projet Biodiv.Balma de l'APCVEB *
 * (Association de Protection du Cadre de Vie et de l'Environnement balmanais) * 
 *     voir Biodiv.Balma : https://balma.biodiv.fr/                            *
 *     voir APCVEB : http://apcveb.free.fr/                                    *
 *                                                                             *
 *  Ce programme est un logiciel libre distribué sous licence GNU/GPL.         *
 *  Pour plus de détails voir les fichier COPYING.txt et LICENCE-BIODIV.md     *
\*******************************************************************************/


if (!defined('_ECRIRE_INC_VERSION')) return;
include_spip('inc/utils');

// On récupère la configuration de TAXREF
$txconf = unserialize($GLOBALS['meta']['taxref']);
//spip_log("TAXREF: configuration taxref : ". print_r($txconf,true), "biodiv."._LOG_INFO_IMPORTANTE);

// et on initialise les constantes locales
define('_TAXREF_DELAY', 180);						// validité de l'extraction de la base (sec)
define('_CSV_LINESIZE', 8000);						// taille max d'une ligne du catalogue TAXREF
define('_NOM_BINOMIAL', $txconf['binomial']);		// nom du champ contenant le nom binomial
define('_CD_NOM', $txconf['cdnom']);				// nom du champ contenant le CD_NOM
define('_CD_REF', $txconf['cdref']);				// nom du champ contenant le CD_REF
define('_REGNE', $txconf['regne']);				    // nom du champ contenant le REGNE
define('_GROUP1', $txconf['group1']);				// nom du champ contenant le GROUP1
define('_GROUP2', $txconf['group2']);				// nom du champ contenant le GROUP2
define('_RANG', $txconf['rang']);					// nom du champ contenant le RANG
define('_TAXREF_ITERATION', $txconf['iteration']);  // nombre de lignes lues par iteration
define('_TAXREF_PATTERN',$txconf['pattern']);		// template du nom de fichier. %d sera le numero du fragment
define('_TAXREF_FRAGMENTS',$txconf['fragments']);	// nombre de fragments

/**
 * Charger un extrait de TAXREF
 *
 * @param int $t
 * @return int
 */
function genie_taxref_v2_dist($t) {
	$taxons = array();
	$especes = taxref_v2_lister_especes(_DIR_CACHE.'especes.txt', _TAXREF_DELAY);
	$status = taxref_v2_lire_catalogue2(_ROOT_RACINE ._TAXREF_PATTERN,$taxons,_TAXREF_ITERATION,$especes);
	// taxref_dump($taxons);
	taxref_v2_insert($taxons);
	return $status;
}

/**
 * lister_especes
 *
 * Sérialise toutes les fiches espèces avec leurs numéros et leurs noms binomiaux
 * dans un fichier qui sera relu à chaque itération de lire_catalogue.
 */

function taxref_v2_lister_especes($filename,$delay) {
	// Si un fichier cache existe et n'est pas trop vieux
	// on retourne son contenu
	spip_log("TAXREF lister especes fichier=".$filename." delai=".$delay, "biodiv");	
	
	if(file_exists($filename)) {
		spip_log("TAXREF fichier existant " . $filename, "biodiv");
		$modif = filemtime($filename);
		if((time() - $modif) < $delay) {
			spip_log("TAXREF fichier a jour ".$filename, "biodiv");
			$rows = unserialize(file_get_contents($filename));
			spip_log("TAXREF : especes lues ".count($rows), "biodiv");
			return $rows;
		}
	}
	// Sinon, on va chercher le contenu dans la base
	// et on crée le fichier cache pour prochaine fois.
	spip_log("TAXREF fichier=".$filename." inexistant ou obsolete.", "biodiv");
	$especes = sql_select(
				array('soustitre','id_article'),	// fields
				'spip_articles',					// from
				"composition='espece'",			// where
				'',									// group-by
				"soustitre"							// order-by
				);
	$rows = array(); $count=0;
	
	$pattern = '/ [Ss]p[\\.]?$/';
	$replace = '';
	while($row = sql_fetch($especes)) {
		// On supprime les suffixes ' Sp.' ou ' sp.' qui ne sont pas utilisés dans taxref.
		// 2022-03-08 : et on supprime les espaces en extremite de chaine
		$binomial = preg_replace($pattern,$replace,trim($row['soustitre'])); 
		//$binomial = $row['soustitre'];
		$rows[$binomial] = $row; $count++;
	}
	spip_log("TAXREF : especes dans la base ".$count." dont ".count($rows)." distinctes.", "biodiv.".__LOG_INFO_IMPORTANTE);
	file_put_contents($filename,serialize($rows));
	return $rows;
}

/**
 * lire_catalogue (principale)
 *
 * Cette fonction part du principe que le catalogue est découpé en fragments
 * trop gros pour être chacun lus en une seule itération.
 * On gère une valeur 'ligne' (from) qui représente la ligne à partir de laquelle
 * lire le fragment dans l'itération courante.
 */
 
function taxref_v2_lire_catalogue($catPattern,&$taxons,$nbLignes,$especes) {
	$lDelimiter="\t";
	include_spip('inc/meta');
	
	// La portion du catalogue à lire démare à $from
	// La valeur est stockée dans les métas et mise à jour à chaque appel
	// de cette fonction pour permettre une lecture itérative sans timeout.
	$from = array(
		'ligne' => 0,
		'fragment' => 1,
		'reset' => date("Y-m-d H:i:s"),
		'group1' => '',
		'group2' => ''
		);
	if(isset($GLOBALS['meta']['taxref_debut'])) {
		$from = unserialize($GLOBALS['meta']['taxref_debut']);
		// $debut = intval($GLOBALS['meta']['taxref_debut']);
	}
	
	$catalogue = sprintf($catPattern,intval($from['fragment']));
	spip_log("TAXREF : lecture de ".$catalogue." : ".$nbLignes." lignes depuis ligne ".$from['ligne'], "biodiv");
	$catalogue = realpath($catalogue);
	$lFp = fopen($catalogue,"r");
	if(!$lFp){
		spip_log("TAXREF : Echec ouverture de ".$catalogue, "biodiv."._LOG_INFO_IMPORTANTE);
		if(is_readable($catalogue))
			spip_log("TAXREF : ... mais le fichier ".$catalogue. " est accessible en lecture", "biodiv."._LOG_INFO_IMPORTANTE);
		return(-10);
	}
	// Lecture de la ligne d'entete
	$lHeader = fgetcsv($lFp,_CSV_LINESIZE,$lDelimiter);
	// On ignore tout ce qu'il y a avant $debut
	for($i=0;$i<$from['ligne'];$i++) $skip = fgetcsv($lFp,_CSV_LINESIZE,$lDelimiter);
	// On traite $nbLignes à partir de $debut
	$i=0; 
	$group1 = null; $group2 = null;
	while($taxon=fgetcsv($lFp,_CSV_LINESIZE,$lDelimiter) AND ($i < $nbLignes)) {
		$i++;
		if(!$group1) {
			$group1 = $taxon[_GROUP1];
			$group2 = $taxon[_GROUP2];
		}
		// On ne s'intéresse qu'aux espèces connues
		if(array_key_exists($taxon[_NOM_BINOMIAL],$especes)) {
			$lbnom = $taxon[_NOM_BINOMIAL];
			$taxons[] = array(
				// 'binomial' => $lbnom,
				'nom' => $lbnom,
				// 'cd_nom' => $taxon[_CD_NOM],
				'id_taxref' => $taxon[_CD_NOM],
				'cd_ref' => $taxon[_CD_REF],
				'regne'  => $taxon[_REGNE],
				'group1' => $taxon[_GROUP1],
				'group2' => $taxon[_GROUP2],
				'rang'   => $taxon[_RANG],
				'id_espece' => $especes[$lbnom]['id_article'],
				);
			spip_log("TAXREF : taxon ".$lbnom." regne ".$taxon[_REGNE], "biodiv");
		}
	}
	fclose($lFp);
	spip_log("TAXREF : taxons trouves ".count($taxons), "biodiv");
	
	if($i <	$nbLignes) {
		// on a tout lu : réinitiaisation
		$from['ligne']=0;
		if($from['fragment'] == _TAXREF_FRAGMENTS) {
			 $from['fragment'] = 1;
			 $from['reset'] = date("Y-m-d H:i:s");
			 $from['group1'] = $group1;
			 $from['group2'] = $group2;
			 spip_log("TAXREF : Catalogue entierement lu ", "biodiv");
			 ecrire_meta('taxref_debut',serialize($from));
			 return(1);
		} else {
			spip_log("TAXREF : Fragment lu ".$catalogue, "biodiv");
			$from['fragment']++;
			$from['group1'] = $group1;
			$from['group2'] = $group2;
			ecrire_meta('taxref_debut',serialize($from));
			return(-10);
		}
	} else {
		// il en reste
		$from['ligne']+= $nbLignes;   
		$from['group1'] = $group1;
		$from['group2'] = $group2;
		spip_log("TAXREF : Fragment a poursuivre ".$catalogue." depuis ligne ".$from['ligne'], "biodiv");
		ecrire_meta('taxref_debut',serialize($from));
		return(-10);
	}
		
}

/**
 * lire_catalogue (alternative 2)
 *
 * Cette fonction part du principe que le catalogue est découpé en fragments
 * suffisamment petits pour être chacun lus en une seule itération.
 * On n'utilise pas la valeur 'ligne' (from) mais on la garde à 0 pour la
 * compatibilité avec la fonction lire_catalogue d'origine.
 */
 
function taxref_v2_lire_catalogue2($catPattern,&$taxons,$nbLignes,$especes) {
	$lDelimiter="\t";
	include_spip('inc/meta');
	
	// La portion du catalogue à lire démare à $from
	// La valeur est stockée dans les métas et mise à jour à chaque appel
	// de cette fonction pour permettre une lecture itérative sans timeout.
	$from = array(
		'ligne' => 0,		// reste pour compatibilité mais non utilisé
		'fragment' => 1,
		'reset' => date("Y-m-d H:i:s"),
		'group1' => '',
		'group2' => ''
		);
	if(isset($GLOBALS['meta']['taxref_debut'])) {
		$from = unserialize($GLOBALS['meta']['taxref_debut']);
	}
	
	$catalogue = sprintf($catPattern,intval($from['fragment']));
	spip_log("TAXREF : lecture de ".$catalogue, "biodiv."._LOG_INFO_IMPORTANTE);
	$catalogue = realpath($catalogue);
	$lFp = fopen($catalogue,"r");
	if(!$lFp){
		spip_log("TAXREF : Echec ouverture de ".$catalogue, "biodiv."._LOG_INFO_IMPORTANTE);
		if(is_readable($catalogue))
			spip_log("TAXREF : ... mais le fichier ".$catalogue. " est accessible en lecture", "biodiv."._LOG_INFO_IMPORTANTE);
		return(-10);
	}
	// Lecture de la ligne d'entete
	$lHeader = fgetcsv($lFp,_CSV_LINESIZE,$lDelimiter);
	$group1 = null; $group2 = null;
	
	// On traite tout le fichier
	while($taxon=fgetcsv($lFp,_CSV_LINESIZE,$lDelimiter)) {
		if(!$group1) {
			$group1 = $taxon[_GROUP1];
			$group2 = $taxon[_GROUP2];
		}
		// On ne s'intéresse qu'aux espèces connues
		if(array_key_exists($taxon[_NOM_BINOMIAL],$especes)) {
			$lbnom = $taxon[_NOM_BINOMIAL];
			$taxons[] = array(
				// 'binomial' => $lbnom,
				'nom' => $lbnom,
				// 'cd_nom' => $taxon[_CD_NOM],
				'id_taxref' => $taxon[_CD_NOM],
				'cd_ref' => $taxon[_CD_REF],
				'regne'  => $taxon[_REGNE],
				'group1' => $taxon[_GROUP1],
				'group2' => $taxon[_GROUP2],
				'rang'   => $taxon[_RANG],
				'id_espece' => $especes[$lbnom]['id_article'],
				);
			// spip_log("TAXREF: taxon '$lbnom' cd_nom ".$taxon[_CD_NOM]." règne ".$taxon[_REGNE], "biodiv."._LOG_INFO_IMPORTANTE);
		}
	}
	fclose($lFp);
	spip_log("TAXREF : taxons trouves ".count($taxons), "biodiv");
	
	// on a tout lu : réinitiaisation
	$from['ligne']=0;
	if($from['fragment'] == _TAXREF_FRAGMENTS) {
		$from['fragment'] = 1;
		$from['reset'] = date("Y-m-d H:i:s");
		$from['group1'] = $group1;
		$from['group2'] = $group2;
		spip_log("TAXREF : Catalogue entierement lu ", "biodiv");
		ecrire_meta('taxref_debut',serialize($from));
		return(1);
	} else {
		spip_log("TAXREF : Fragment lu ".$catalogue, "biodiv");
		$from['fragment']++;
		$from['group1'] = $group1;
		$from['group2'] = $group2;
		ecrire_meta('taxref_debut',serialize($from));
		return(-10);
	}	
}


function taxref_v2_insert($taxons) {
	foreach($taxons as $entry) {
		// sql_replace('spip_taxons',$entry);
		sql_replace('spip_taxrefs',$entry);
	}
}

function taxref_v2_dump($taxons) {
	file_put_contents(_DIR_CACHE . 'taxons.txt', print_r($taxons,true));
}

?>
