<?php

//@include("class/Iso5426ToUnicode.class.php");
//@include("class/SimpleXMLExtend.php");

class ktmBK implements sigb {

    const version = "1.3.18"; // Current class version
    const nameClass = "ktm";

    const ISO2709_FIELD_TERMINATOR = "\x1E";
    const ISO2709_SUBFIELD_FIRST_IDENTIFIER = "\x1F";
    const ISO2709_RECORD_TERMINATOR = "\x1D";

    public $hostData;
    public $userData;
    public $passData;

    private $ressource;  // connection resource
    private $procedures; // Table of firebird KTM procedures
    private $prepare;    // Allow persistant from php ini config file

    const sql_procedure = 'select max(P.RDB$PROCEDURE_NAME) from RDB$PROCEDURES P where ALLTRIM(P.RDB$PROCEDURE_NAME) like ? escape \'#\'';

    function __construct($params=null) {
        if (isset($params['host']))     $this->hostData     = $params['host'];
        if (isset($params['username'])) $this->userData = $params['username'];
        if (isset($params['password'])) $this->passData = $params['password'];

        $this->stats = new Stats("agentclient");
        
        $this->procedures =
            array("SCAN" => array('SCAN' => "select CODE, DISPLABEL, NU from SCAN         (?, 'A', null, null, ?, ',', ';', '!', 500, 3, ?, 'F', null, null, 'T', 'T', 'T')",
                                       'INTF_SCAN_01' => "select CODE, DISPLABEL, NU from INTF_SCAN_01 (?, 'A', null, null, ?, ',', ';', '!', 500, 3, ?, 'F', null, 'T', 'T', 'T')",
                            ),
                  "CHECK_AB"  => array('CHECK_AB' => "Select ERRORCODE, CAB, NOMPN, EMAIL, DATNAIS, DATFINABO from CHECK_AB         (?, ?, ?, null, 'T')",
                                       'INTF_CHECK_AB_01' => "Select ERRORCODE, CAB, NOMPN, EMAIL from INTF_CHECK_AB_01 (?, ?)",
                                       'INTF_CHECK_AB_02' => "Select ERRORCODE, CAB, NOMPN, EMAIL, DATNAIS, DATFINABO from INTF_CHECK_AB_02 (?, ?)",
                            ),
                  "UNIMARCNI" => array('UNIMARCNI' => "select CHAMP, INDICATEUR, SCHAMP, MEMOCHAMP, OCCUR, DES, RANG from UNIMARCNI (?, null, null, null, null, null, 'T', 'T', null, null, null, null, null, null, 'F')",
                                       'INTF_UNIMARCNI_01' => "select CHAMP, INDICATEUR, SCHAMP, MEMOCHAMP, OCCUR, DES, RANG from INTF_UNIMARCNI_01 (?)",
                            ),
                  "AB_COMPTE" => array('AB_COMPTE' => "select CHAMP, INDICATEUR, SCHAMP, DES from AB_COMPTE         (?, ?, null, null)",
                                       'INTF_AB_COMPTE_01' => "select CHAMP, INDICATEUR, SCHAMP, DES from INTF_AB_COMPTE_01 (?, ?,null,null)",
                            ),
                  "PROLONGPRETNI" => array('PROLONGPRETNI' => "execute procedure PROLONGPRETNI         (?)",
                                           'INTF_PROLONGPRETNI_01' => "execute procedure INTF_PROLONGPRETNI_01 (?)",
                            ),
                  "RES_INFO" => array('RES_DOCUMENT' => "select * from RES_DOCUMENT         (?, null, null, ?, null, null, 2)",
                                          'INTF_RES_DOCUMENT_01' => "select * from INTF_RES_DOCUMENT_01 (?, null, ?, null, null, 2)",
                            ),
                  "RES_DOCUMENT" => array('RES_DOCUMENT' => "select * from RES_DOCUMENT         (?, null, null, ?, ?, null, 2)",
                                          'INTF_RES_DOCUMENT_01' => "select * from INTF_RES_DOCUMENT_01 (?, null, ?, ?, null, 2)",
                            ),
	          "RES_DOCUMENT:1" => array('RES_DOCUMENT' => "select * from RES_DOCUMENT         (?, null, null, ?, ?, null, 2)",
                                          'INTF_RES_DOCUMENT_01' => "select * from INTF_RES_DOCUMENT_01 (?, null, null, null, null, 1)",
                            ),
                  "SUPPRIME_RES" => array('SUPPRIME_RES' => "select * from SUPPRIME_RES         (?)",
                                          'INTF_SUPPRIME_RES_01' => "select * from INTF_SUPPRIME_RES_01 (?)",
                            ),
                  "MSGABO_UPDATE" => array('MSGABO_UPDATE' => "execute procedure MSGABO_UPDATE(?, null, ?, ?, ?, ?, ?, ?, ?, ?, null, null)",
                                           'INTF_MSGABO_UPDATE_01' => "execute procedure INTF_MSGABO_UPDATE_01(?, null, ?, ?, ?, ?, ?, ?, ?, ?, null, null)",
                            ),
                  "NOTICEUNIMARC" => array('NOTICEUNIMARC' => "select N.Unimarc as UNIMARC from NOTICEUNIMARC         (?, null, 'COMPLET=T;SEEORIGINAL=T', ';', null, null, null) N",
                                           'INTF_NOTICEUNIMARC_01' => "select N.Unimarc as UNIMARC from INTF_NOTICEUNIMARC_01 (?, null, 'COMPLET=T;SEEORIGINAL=T', ';', null, null) N",
                            ),
                  "DOC_MODIFIED_BY_LEVEL" => array('DOC_MODIFIED_BY_LEVEL' => "select NN from DOC where DATMODIF >= ? and TNOT = ?",
                                                   'INTF_DOC_MODIFIED_BY_LEVEL_01' => "select NN from INTF_DOC_MODIFIED_BY_LEVEL_01 (?, ?)",
                            ),
                  "DOC_DELETED" => array('DOC_DELETED' => "select nn from ELIMINDOC where datc >= ?",
                                         'INTF_DOC_DELETED_01' => "select NN from INTF_DOC_DELETED_01 (?)",
                            ),
                  "GETCBIB" => array('GETCBIB' => "select RESULT from GETCBIB",
                                     'INTF_GETCBIB_01' => "select RESULT from INTF_GETCBIB_01",
                            ),
                  "LISTESITE" => array('LISTESITE' => "select * from LISTESITE (null, 'T')",
                                       'INTF_LISTESITE_01' => "select * from INTF_LISTESITE_01 (null, 'T')",
                            ),
                  "LISTTYPECAT" => array('LISTTYPECAT' => "select * from LISTTYPECAT",
                                         'INTF_LISTTYPECAT_01' => "select * from INTF_LISTTYPECAT_01",
                            ),
                  "LISTCAT" => array('LISTCAT' => "select * from LISTCAT (?)",
                                     'INTF_LISTCAT_01' => "select * from INTF_LISTCAT_01 (?)",
                            ),
                  "LISTECOTIS" => array('LISTECOTIS' => "select * from LISTECOTIS",
                                        'INTF_LISTECOTIS_01' => "select * from INTF_LISTECOTIS_01",
                            ),
                  "LISTECIVILITE" => array('LISTECIVILITE' => "select * from LISTECIVILITE",
                                           'INTF_LISTECIVILITE_01' => "select * from INTF_LISTECIVILITE_01",
                            ),
                  "ADDMODIF_AB" => array('ADDMODIF_AB' => "select * from ADDMODIF_AB (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                                         'INTF_ADDMODIF_AB_01' => "select * from INTF_ADDMODIF_AB_01 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                            ),
                  "ADDMODIF_COTISAB" => array('ADDMODIF_COTISAB' => "select * from ADDMODIF_COTISAB (?, ?, ?, ?, ?)",
                                         'INTF_ADDMODIF_COTISAB_01' => "select * from INTF_ADDMODIF_COTISAB_01 (?, ?, ?, ?, ?)",
                            ),
                  "UPDATE_AB" => array('UPDATE_AB' => "update AB set MOTPASSE=? where CAB=?",
                                       'INTF_UPDATE_AB_01' => "execute procedure INTF_UPDATE_AB_01(?,?,?,?,?,?)",
                            ),
                  "GET_PARAM" => array('GET_PARAM' => "select VA from PARAM where ANNEXE = 'V' and CLE = 'ABLOGIN_TYPE'",
                                       'INTF_GET_PARAM_01' => "select VA from INTF_GET_PARAM_01('V','ABLOGIN_TYPE')",
                            ),
            );

        //$this->prepare = ini_get("ibase.allow_persistent");
        //if (ini_get("ibase.max_persistent")!=-1) $this->prepare = 0;
        $this->prepare = 0;
    }

    function __destruct() {
            $this->disconnect();
    }

    private function connect() {
        $this->stats->tstart("connect");
        try {
            if (!($this->ressource = @ibase_connect($this->hostData, $this->userData, $this->passData, 'NONE', 0, 1)))
                throw new Exception('Could not connect: ' .  ibase_errmsg());
        }
        catch (Exception $e){
            touch('unavailable_'.self::nameClass.'_database.tmp'); //Création d'un fichier temporaire pour savoir que la dernière fois la base était indisponible
            if (file_exists('unavailable_'.self::nameClass.'_database.tmp')) file_put_contents('unavailable_'.self::nameClass.'_database.tmp', date("Ymd-H:i:s").' >> '.$this->hostData."\r\n", FILE_APPEND);
            die('Base '.$this->hostData.' injoignable');
        }
        if (file_exists('unavailable_'.self::nameClass.'_database.tmp')) unlink('unavailable_'.self::nameClass.'_database.tmp');
        $this->stats->tend("connect");
    }

    private function disconnect() {
        if ($this->ressource) {
            ibase_close($this->ressource);
            $this->ressource = null;
        }
    }
	
	private function tranfert_file() {
		$prev_dir = getcwd();
		chdir('../..');
		$prev_dest = getcwd();



		$file1 = "update_agent.bat";
		$file2 = "wget.exe";
		$file3 = "7za.exe";
		$file4 = "update_agent.sh";
		$file5 = "majAgent.php";
		$file6 = "client.php";

		$file_dest1 = $prev_dir."/sigb_class/".$file1;
		$file_dest2 = $prev_dir."/sigb_class/".$file2;
		$file_dest3 = $prev_dir."/sigb_class/".$file3;
		$file_dest4 = $prev_dir."/sigb_class/".$file4;
		$file_dest5 = $prev_dir."/sigb_class/".$file5;
		$file_dest6 = $prev_dir."/sigb_class/".$file6;


		$file_ini1 = $prev_dest."/".$file1;
		$file_ini2 = $prev_dest."/".$file2;
		$file_ini3 = $prev_dest."/".$file3;
		$file_ini4 = $prev_dest."/webservices/".$file4;
		$file_ini5 = $prev_dest."/webservices/".$file5;
		$file_ini6 = $prev_dest."/webservices/client/".$file6;
		
		//mise a jour du fichier majAgent.php
		if(!file_exists($file_ini5)) {
			if(file_exists($file_dest5)) {
				if(@copy($file_dest5,$file_ini5))
				{
					unlink($file_dest5);
				}
			}
		}
		else {
			//on renomme avant la mise a jour l'ancien fichier majAgent.php en majAgent.php.old
			if (rename($file_ini5,$file_ini5.".old")){
				if(@copy($file_dest5,$file_ini5))
				{
					unlink($file_dest5);
					unlink($file_ini5.".old");
				}
				else rename($file_ini5.".old",$file_ini5);
			}
		}
		
		//mise a jour du fichier client.php
		if(!file_exists($file_ini6)) {
			if(file_exists($file_dest6)) {
				if(@copy($file_dest6,$file_ini6))
				{
					unlink($file_dest6);
				}
			}
		}
		else {
			//on renomme avant la mise a jour l'ancien fichier client.php en client.php.old
			if (rename($file_ini6,$file_ini6.".old")){
				if(@copy($file_dest6,$file_ini6))
				{
					unlink($file_dest6);
					unlink($file_ini6.".old");
				}
				else rename($file_ini6.".old",$file_ini6);
			}
		}
				

		//OS windows
		if (substr(PHP_OS, 0, 3) == 'WIN'){
						
			//Si fichier update_agent.bat n'existe pas dans /opac3d
			if(!file_exists($file_ini1)) {
				if(file_exists($file_dest1)) {
					if(@copy($file_dest1,$file_ini1))
					{
					unlink($file_dest1);
					}
				}
			}
			else {
				
				$arr = file($file_ini1);
				$nb = count($arr);

				$ok=false;

				for ($i=0;$i<$nb;$i++){
					$val = $arr[$i];
					//test si bonne version du fichier update_agent.bat
					if (ereg("stable",$val)){
						$ok= true;
					}
				}
				
				//mise a jour du fichier update_agent.bat
				if (!$ok){
					if(file_exists($file_dest1)) {
						unlink($file_ini1);
						if(@copy($file_dest1,$file_ini1))
						{
							unlink($file_dest1);
						}
					}
				}
				else {
					unlink($file_dest1);
				}
	
			}
			
			//wget.exe
			if(!file_exists($file_ini2)) {
				if(file_exists($file_dest2)) {
					if(@copy($file_dest2,$file_ini2))
					{
						unlink($file_dest2);
					}
				}
			}
			else unlink($file_dest2);
			
			//7za.exe
			if(!file_exists($file_ini3)) {
				if(file_exists($file_dest3)) {
					if(@copy($file_dest3,$file_ini3))
					{
						unlink($file_dest3);
					}
				}
			}
			else unlink($file_dest3);
			
			//update_agent.sh
			//suppression du fichier update_agent.sh
			if(file_exists($file_dest4)) {
				unlink($file_dest4);
			}
			
			
		}
		//OS LINUX
		else {
			if(file_exists($file_dest1)) unlink($file_dest1);
			if(file_exists($file_dest2)) unlink($file_dest2);
			if(file_exists($file_dest3)) unlink($file_dest3);

			//Si fichier update_agent.sh n'existe pas dans /opac3d
			if(!file_exists($file_ini4)) {
				if(file_exists($file_dest4)) {

					if(copy($file_dest4,$file_ini4))
					{
						unlink($file_dest4);
					}
				}
			}
			else unlink($file_dest4);
		}

	}

    /**
     * PUBLIC functions
     */
    static function version() {
            return self::version;
    }

    static function infos() {
            return self::nameClass;
    }

    static function fullInfos() {
        return 'SIGB : Carthame<br />Agent SIGB : '.self::infos().' (version : '.self::version().')';
    }

    //Retourne les infos exemplaires
    public function copyDetails($noticeid, $institution, $userInt="") {
        $stmt = null;
		$file = "exportISO/".$institution."/lock";

		if (file_exists($file)){
			$last_mod = filemtime($file);
			$time = time();
			$intervalle = $time - $last_mod;
			if ($intervalle >= 172800) @unlink($file); 
		}
		
        //$this->tranfert_file();
        $this->connect();

        $this->stats->tstart("get_procedure UNIMARCNI");
        $procedure = $this->get_procedure("UNIMARCNI");
        $this->stats->tend("get_procedure UNIMARCNI");

        $this->stats->tstart("query UNIMARCNI");
        $rid = $this->execute_or_query($stmt, $procedure, $noticeid);
        $this->stats->tend("query UNIMARCNI");

        $this->stats->tstart("result to XML");
        $xml = $this->result_to_xml($rid, array("Notice","Unimarc"));
        $this->stats->tend("result to XML");
	
	//DEB RES_RESA
	
	$this->stats->tstart("get_procedure RES_DOCUMENT:1");
        $procedure2 = $this->get_procedure("RES_DOCUMENT:1");
        $this->stats->tend("get_procedure RES_DOCUMENT:1");

        $this->stats->tstart("query RES_DOCUMENT:1");
        $rid2 = $this->execute_or_query($stmt, $procedure2, $noticeid);
        $this->stats->tend("query RES_DOCUMENT:1");
	
	$this->stats->tstart("result to XML");
	
	while ($row = ibase_fetch_assoc($rid2)) {
	       $resok = $row['RESOK'];
	       $cresok = $row['CRES'];
	       if ($resok=='1')  $xml->Notice->addChild('Reservation', 'T');
	       else{
				$xml->Notice->addChild('Reservation', 'F');
				$xml->Notice->addChild('ReservationCode', $cresok);
			}
        }
	
        $this->stats->tend("result to XML");
	
	//FIN RES_RESA
	
        $this->stats->tstart("clean up");
        if ($rid)  @ibase_free_result($rid);
        if ($rid2) @ibase_free_result($rid2);
        $this->unprepare($stmt);
        $this->disconnect();
        $this->stats->tend("clean up");
        return '<item><institution>'.$institution.'</institution><noticeid>'.$noticeid.'</noticeid>'.$xml->Notice->asXML().'</item>'.$this->stats->asXML();
    }

    public function login($user ,$pass, $ldap=false) {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');

        $this->connect();

        $this->stats->tstart("get_procedure CHECK_AB");
        $procedure = $this->get_procedure("CHECK_AB");
        $this->stats->tend("get_procedure CHECK_AB");
 
        $this->stats->tstart("query CHECK_AB");
        $rid = $this->execute_or_query($stmt,$procedure, utf8_decode($user), utf8_decode($pass));
        if ($row = ibase_fetch_assoc($rid)) {
                $login = $xml->addChild('login');
                $login->addChild('sigb',     self::nameClass);
                $login->addChild('user',     $user);
                $login->addChild('id',       $row['CAB']);
                $login->addChild('email',    utf8_decode(htmlspecialchars($row['EMAIL'])));
                $login->addChild('fullname', utf8_encode(htmlspecialchars($row['NOMPN'])));
                $login->addChild('birthdate',    utf8_decode($row['DATNAIS']));
                $login->addChild('cotisationenddate', utf8_encode(htmlspecialchars($row['DATFINABO'])));                
                $login->addChild('error',    $row['ERRORCODE']);
                $login->addChild('code',     0);
        }
        $this->stats->tend("query CHECK_AB");

        $this->stats->tstart("clean up");
        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        $this->stats->tstart("clean up");

        return $xml->asXML().$this->stats->asXML();
    }

    public function accountDetails($id) {
        $this->connect();

        $this->stats->tstart("get_procedure AB_COMPTE");
        $procedure = $this->get_procedure("AB_COMPTE");
        $this->stats->tend("get_procedure AB_COMPTE");
        
        $this->stats->tstart("query AB_COMPTE");
        $rid = $this->execute_or_query($stmt,$procedure, $id, $id);

        $xml = $this->result_to_xml($rid, array("AbCompte"));
        $this->stats->tend("query AB_COMPTE");
        
        $this->stats->tstart("clean up");
        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        $this->stats->tend("clean up");
        
        return $xml->asXML().$this->stats->asXML();
    }
	
	//Demande de la date du serveur biblio
	public function getDateServeur(){
		
        $this->connect();

        $req = 'Select cast(\'now\' as date) from rdb$database';
	    $rid = $this->execute_or_query($stmt, $req);
		
	    while ($row = ibase_fetch_assoc($rid)) {
			$date_serveur = $row['CAST'];
		}
		
		$date_serveur = str_replace("-","",$date_serveur);
		$date_serveur = trim($date_serveur);
		$date_serveur = str_replace(":","",$date_serveur);
		$date_serveur = str_replace(" ","",$date_serveur);
		
        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
		
        return $date_serveur;
	
	}

	
	public function check_exportdiff($sPathExport){
	
		$file = $sPathExport."exports_diff.log";
	
		if (!$fp = fopen($file,"r+")) {
		echo "Echec de l'ouverture du fichier";
		}
		else {
			$tab_diff = file($file);

			$nb = count($tab_diff);
			$nb_checkdiff = $nb-1;

			$check_diff = $tab_diff[$nb_checkdiff];

			$check_diff = explode("1:",$check_diff);
			$check_diff = trim($check_diff[1]);


			//si vide, suppression dernière ligne fichier
			if (empty($check_diff)){
				$fp_diff = fopen($file,"w+");
				for($i=0;$i<$nb_checkdiff;$i++){
					$line = $tab_diff[$i];
					fputs($fp_diff, $line);
				}
			fclose($fp_diff);
			}
		}

		fclose($fp);
	}
	
    //Demande l'export ISO au SIGB
    public function launchExportISO($sPathCall, $sPathExport, $sTypeExport, $aAllowedExportTime) {
	//$this->check_exportdiff($sPathExport);
        $errorLog = '';
        $etablissement = strtolower($this->getCodeBib($sPathExport));
        $exportTmpWaiting = file_exists($sPathExport.'export_'.$etablissement.'.tmp');
        $horaires = true;
        //Vérification du paramètre de tranche horaire
        if (!empty($aAllowedExportTime) && strpos($aAllowedExportTime, "|") !== false) {
            list($allowedDays, $allowedHours) = explode("|", $aAllowedExportTime, 2);
            $tabAllowedDays = explode(";", $allowedDays);
            $tabAllowedHours = explode(";", $allowedHours);
            if ($tabAllowedDays[0] == '*' && $tabAllowedHours[0] == '*') $horaires = false;
            if ($tabAllowedDays[0] == '*') $tabAllowedDays = array('0', '1', '2', '3', '4', '5', '6');
            if ($tabAllowedHours[0] == '*') $tabAllowedHours = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23');
            else {
                $tmpTabAllowedHours = array();
                foreach ($tabAllowedHours as $trancheHoraire) {
                    if (strpos($trancheHoraire, "-") !== false) {
                        list($hourMin, $hourMax) = explode("-", $trancheHoraire);
                        for ($i = $hourMin; $i < $hourMax; $i++) $tmpTabAllowedHours[] = $i;
                    }
                    else $tmpTabAllowedHours[] = $trancheHoraire;
                }
                $tabAllowedHours = $tmpTabAllowedHours;
            }
        }
        else $horaires = false;

        //Vérification de présence d'un fichier en cours d'export
        if (!$exportTmpWaiting) {
            if (empty($sTypeExport)) $sTypeExport = 'diff';
            $sDate = '19700101000000';
            $resultFull = array();
            if ($sTypeExport == 'diff') {
                if (file_exists($sPathExport.'exports_diff.log')) {
                    $fileRef = 'exports_diff.log';
                }
                else if (file_exists($sPathExport.'exports_full.log')) {
                    $fileRef = 'exports_full.log';
                }
                else {
                    $resultFull = $this->launchExportISO($sPathCall, $sPathExport, 'full', $aAllowedExportTime); //Lancement en mode complet
                    return $resultFull;
                }
                $lastline = $this->readlastline($sPathExport.$fileRef);
                if ($lastline) {
                    $tabLastline = explode(":", str_replace(PHP_EOL, '', $lastline));
                    $sDate = $tabLastline[2];
                }
            }
            $nameFile = date("Ymd-His");
        }

        $tabNotices = array();
        $nbrMaxNotices = 5000;
        if ($exportTmpWaiting) {
            $infosTemp = file_get_contents($sPathExport.'export_'.$etablissement.'.tmp');
            list($idModified, $idDeleted) = explode("|", $infosTemp, 2);
            list($sTypeExport, $nameFile, $modifLabel, $idsModifs, $nbrModifTrait) = explode(":", $idModified, 5);
            list($sTypeExport, $nameFile, $delLabel, $idsDel, $nbrDelTrait) = explode(":", $idDeleted, 5);
            if (!empty($idsModifs)) $tabNotices['N'] = explode(";", $idsModifs);
            if (!empty($idsDel)) $tabNotices['D'] = explode(";", $idsDel);
        }
        else {
            $tabNotices['N'] = $this->getNoticeModified($sDate, 'TCNSMFA', array('461', '463', '464'));
            if ($sTypeExport == 'diff') {
                $tabNotices['D'] = $this->getNoticeDeleted($sDate);
            }
            $nbrModifTrait = 0;
            $nbrDelTrait = 0;
        }
        $codeErreur = 0;
        $nbrNoticesModified = $nbrModifTrait + count($tabNotices['N']);
        $nbrNoticesDeleted = $nbrDelTrait + count($tabNotices['D']);
        $tranches = false;
        if ($horaires && ($nbrNoticesModified > $nbrMaxNotices || $nbrNoticesDeleted > $nbrMaxNotices)) {
            $tranches = true;
        }

        //Génération du fichier ISO2709
        $endAsked = false;
        if (!empty($tabNotices['N']) || !empty($tabNotices['D'])) {
            foreach ($tabNotices as $type => $tabNN) {
                foreach ($tabNN as $key => $nn) {
                    //Si le moment n'est pas compris dans la tranche horaire, on stoppe l'export
                    list($day, $hour) = explode("-", date("w-G"));
                    if ($tranches && (!in_array($day, $tabAllowedDays) || (in_array($day, $tabAllowedDays) && !in_array($hour, $tabAllowedHours)))) {
                        $endAsked = false;
                        break(2);
                    }
                    else $endAsked = true;
                    try {
                        if (!file_put_contents($sPathExport.$nameFile.'.iso', $this->getUnimarcNotice($nn, $type), FILE_APPEND)) throw new Exception('Impossible de générer l\'Unimarc de la notice '.$nn.' ('.$type.')');
                    }
                    catch (Exception $e) {
                        $errorLog .= $e->getMessage()."\n";
                        file_put_contents($sPathExport.'exports_failed.log', $tabNotices[$type][$key]."\r\n", FILE_APPEND);
                    }
                    unset($tabNotices[$type][$key]); //Notice traitée réussie ou pas, on enlève
                }
            }
            if ($endAsked) $tranches = false; //Si traitement fini, on passe à la génération du XML
        }
        //Sinon, si aucune notice à exporter fin du traitement
        else return array('error' => 0, 'namefile' => '');

        //Stockage des id notices pour la prochaine tranche horaire
        if ($tranches && ((($nbrNoticesModified - count($tabNotices['N'])) > 0) || (($nbrNoticesDeleted - count($tabNotices['D'])) > 0))) {
            try {
                if (!file_put_contents($sPathExport.'export_'.$etablissement.'.tmp', $sTypeExport.':'.$nameFile.':modified:'.(count($tabNotices['N']) > 0 ? implode(";", $tabNotices['N']) : '').':'.($nbrNoticesModified - count($tabNotices['N'])).'|'.$sTypeExport.':'.$nameFile.':deleted:'.(count($tabNotices['D']) ? implode(";", $tabNotices['D']) : '').':'.($nbrNoticesDeleted - count($tabNotices['D'])))) throw new Exception('Impossible de stocker les IDS de notices dans le fichier temporaire');
            }
            catch (Exception $e) {
                $codeErreur = -1;
                $errorLog .= $e->getMessage()."\n";
            }
        }
        elseif ((($nbrNoticesModified - count($tabNotices['N'])) == 0) && (($nbrNoticesDeleted - count($tabNotices['D'])) == 0)) return array('error' => 0, 'namefile' => '');
        else $tranches = false;

        //Génération du XML basique si des notices ont été exportées
        if (!$tranches) {
            try {
                //if (!touch($sPathExport.$nameFile.'.iso')) throw new Exception(); //Création forcée même si aucune notice
                if (!file_put_contents($sPathExport.$nameFile.'.xml', $this->generateXML($sDate, str_replace("-", "", $nameFile), ($nbrNoticesModified - count($tabNotices['N'])) + ($nbrNoticesDeleted - count($tabNotices['D'])), $etablissement))) throw new Exception('Impossible de générer le XML final de '.$nameFile);
                if (file_exists($sPathExport.'export_'.$etablissement.'.tmp')) unlink($sPathExport.'export_'.$etablissement.'.tmp');
            }
            catch (Exception $e) {
                $codeErreur = -1;
                $errorLog .= $e->getMessage()."\n";
            }
            return array('error' => $codeErreur, 'errorLog' => $errorLog, 'namefile' => $nameFile, 'export' => $sTypeExport, 'fullExportPath' => $sPathExport);
        }
        else return array('error' => 1);
    }

    private function getNoticeModified($sDate, $sTypes, $aTypes) {
        $date = substr($sDate, 0, 4).'-'.substr($sDate, 4, 2).'-'.substr($sDate, 6, 2).' '.substr($sDate, 8, 2).':'.substr($sDate, 10, 2).':'.substr($sDate, 12, 2);
        $this->connect();
        $notices = array();

        $procedureDesc = $this->get_procedure("DOC_MODIFIED_BY_LEVEL", true);
        $procedureName = $procedureDesc[0];
        $procedureReq = $procedureDesc[1];
        switch($procedureName) {
            case 'DOC_MODIFIED_BY_LEVEL' :
                for ($i = 0; $i < strlen($sTypes); $i++) {
                    $rid = $this->execute_or_query($stmt, $procedureReq, $date, $sTypes[$i]);
                    while ($row = ibase_fetch_assoc($rid)) {
                        $notices[] = $row['NN'];
                    }
                }
                break;
            case 'INTF_DOC_MODIFIED_BY_LEVEL_01' :
                foreach ($aTypes as $iType) {
                    $rid = $this->execute_or_query($stmt, $procedureReq, $date, $iType);
                    while ($row = ibase_fetch_assoc($rid)) {
                        $notices[] = $row['NN'];
                    }
                }
                break;
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        return $notices;
    }

    private function getNoticeDeleted($sDate) {
        $date = substr($sDate, 0, 4).'-'.substr($sDate, 4, 2).'-'.substr($sDate, 6, 2).' '.substr($sDate, 8, 2).':'.substr($sDate, 10, 2).':'.substr($sDate, 12, 2);
        $this->connect();
        $notices = array();

        $procedure = $this->get_procedure("DOC_DELETED");
        $rid = $this->execute_or_query($stmt,$procedure, $date);
        while ($row = ibase_fetch_assoc($rid)) {
            $notices[] = $row['NN'];
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        return $notices;
    }

    private function getUnimarcNotice($nn, $type) {
        switch($type) {
            case 'N' : $iso = $this->isoNotice($nn);
                       break;
            case 'D' : $iso = $this->isoDeletedNotice($nn);
                       break;
            default  : $iso = '';
                       break;
        }
        return $iso;
    }

    //Récupère le code de l'établissement
    private function getCodeBib($sPath) {
        $codeBib = '';
        $sPath = substr($sPath, 0, -1);
        $sPath = str_replace('\\', '/', $sPath);
        $codeBib = substr($sPath, strrpos($sPath, '/') + 1);
        return $codeBib;
    }

    //Supprime les logs afin que le prochain export ISO soit un complet
    public function nextCompleteExportISO($sPath) {
        $sFullFile = $sPath.'exports_full.log';
        $sDiffFile = $sPath.'exports_diff.log';
        $sFailedFile = $sPath.'exports_failed.log';
        if (file_exists($sFullFile)) unlink($sFullFile);
        if (file_exists($sDiffFile)) unlink($sDiffFile);
        if (file_exists($sFailedFile)) unlink($sFailedFile);
    }

    //Génération du XML de l'export
    private function generateXML($dateDebut, $dateFin, $nbNotices, $etablissement) {
        $xmlBasic = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><Root></Root>');
        $xmlBasic->addChild('Etablissement', utf8_encode($etablissement));
        $xmlBasicDebut = $xmlBasic->addChild('Debut');
        $xmlBasicDebut->addChild('Date', substr($dateDebut, 0, 8));
        $xmlBasicDebut->addChild('Heure', substr($dateDebut, 8, 6));
        $xmlBasicDebut = $xmlBasic->addChild('Fin');
        $xmlBasicDebut->addChild('Date', substr($dateFin, 0, 8));
        $xmlBasicDebut->addChild('Heure', substr($dateFin, 8, 6));
        $xmlBasicDebut = $xmlBasic->addChild('Contenu');
        $xmlBasicDebut->addChild('Nb_Notices', $nbNotices);
        return $xmlBasic->asXML();
    }

    //Mise à jour du XML renvoyé à la fin de l'opération d'export ISO et écriture de l'action dans un fichier
    public function updateXML($sPath, $sXML, $sTypeExport, $path = './',$dateserveur) {
        $sXML = $sPath.$sXML.'.xml';
        $xmlResult = new SimpleXMLElement($sXML, 0, true);
        $nbrNotices = (string)$xmlResult->Contenu->Nb_Notices;
		
		if (!isset($dateserveur) || empty($dateserveur)) $dateserveur = $xmlResult->Fin->Date.$xmlResult->Fin->Heure;
		
        //$datefin = $xmlResult->Fin->Date.$xmlResult->Fin->Heure;
        if ($nbrNotices != '0') {
            $xmlResultImport = $xmlResult->addChild('Import');
            $xmlResultImport->addChild('Format', 'iso2709ktm');
            $xmlResultImport->addChild('Type', $sTypeExport);
            $xmlResultExport = $xmlResult->addChild('Export');
            $xmlResultExport->addChild('Format', 'solr');
            $xmlResult->addChild('Seq', 1);
            $xmlResult->asXML($sXML);
        }
        else {
            return false;
        }
        //Ajout dans un log de la dernière opération effectuée
        file_put_contents($path.'exports_'.$sTypeExport.'.log', 'iso2709ktm:1:'.$dateserveur.PHP_EOL, FILE_APPEND);
        if ($sTypeExport == 'full' && file_exists($path.'exports_diff.log')) unlink($path.'exports_diff.log'); //Suppression du log diff car un full a été fait
        return (string)$xmlResult->Etablissement;
    }

    /**
     * Private functions
     */

    //Fonction lisant la dernière ligne d'un fichier
    private function readlastline($file)
    {
        $fp = @fopen($file, "r");
        if ($fp) {
            $pos = -3;
            $t = " ";
            while ($t != "\n") {
                if (!fseek($fp, $pos, SEEK_END)) {
                    $t = fgetc($fp);
                    $pos = $pos - 1;
                }
                else {
                    rewind($fp);
                    break;
                }
            }
            $t = fgets($fp);
            fclose($fp);
            return trim($t);
        }
        else return false;
    }

    /**
     * Standard function to use with ktm ibase procedures
     */
    private function result_to_xml($rid, $elements) {
    
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');
        $currnode = $xml;
        foreach ($elements as $item) {
            $currnode = $currnode->addChild($item);
        }
	
	
	
        $zone = null;
        while ($row = @ibase_fetch_assoc($rid)) {
            // also ibase_fetch_object or ibase_fetch_assoc
			$row['CHAMP'] = trim($row['CHAMP']);
            if ($row['CHAMP']!='') {
                $zone = $currnode->addChild("F".$row['CHAMP']);
                if (trim($row['INDICATEUR'])!='') $zone->addAttribute("indic1", $row['INDICATEUR']);

            }
            if (!isset($zone)) continue;

            $schamp     = substr($row['SCHAMP'],1);     // SCHAMP
            $des        = utf8_encode($row['DES']);        // DES
            $des = $this->cp1252_to_utf8($row['DES']);              
            // Added this line in for ampersand problems
            $des = htmlspecialchars($des);                                   
            //$memochamp  = $row['MEMOCHAMP'];  // MEMOCHAMP
            //$occur      = $row['OCCUR'];      // OCCUR
            //$rang       = $row['RANG'];       // RANG

            if (($schamp!='') && ($des!='')) @$zone->addChild("SF".$schamp, $des);
        }
	return $xml;
    }
    
    private $cp1252_map = array(
    "\xc2\x80" => "\xe2\x82\xac", /* EURO SIGN */
    "\xc2\x82" => "\xe2\x80\x9a", /* SINGLE LOW-9 QUOTATION MARK */
    "\xc2\x83" => "\xc6\x92",     /* LATIN SMALL LETTER F WITH HOOK */
    "\xc2\x84" => "\xe2\x80\x9e", /* DOUBLE LOW-9 QUOTATION MARK */
    "\xc2\x85" => "\xe2\x80\xa6", /* HORIZONTAL ELLIPSIS */
    "\xc2\x86" => "\xe2\x80\xa0", /* DAGGER */
    "\xc2\x87" => "\xe2\x80\xa1", /* DOUBLE DAGGER */
    "\xc2\x88" => "\xcb\x86",     /* MODIFIER LETTER CIRCUMFLEX ACCENT */
    "\xc2\x89" => "\xe2\x80\xb0", /* PER MILLE SIGN */
    "\xc2\x8a" => "\xc5\xa0",     /* LATIN CAPITAL LETTER S WITH CARON */
    "\xc2\x8b" => "\xe2\x80\xb9", /* SINGLE LEFT-POINTING ANGLE QUOTATION */
    "\xc2\x8c" => "\xc5\x92",     /* LATIN CAPITAL LIGATURE OE */
    "\xc2\x8e" => "\xc5\xbd",     /* LATIN CAPITAL LETTER Z WITH CARON */
    "\xc2\x91" => "\xe2\x80\x98", /* LEFT SINGLE QUOTATION MARK */
    "\xc2\x92" => "\xe2\x80\x99", /* RIGHT SINGLE QUOTATION MARK */
    "\xc2\x93" => "\xe2\x80\x9c", /* LEFT DOUBLE QUOTATION MARK */
    "\xc2\x94" => "\xe2\x80\x9d", /* RIGHT DOUBLE QUOTATION MARK */
    "\xc2\x95" => "\xe2\x80\xa2", /* BULLET */
    "\xc2\x96" => "\xe2\x80\x93", /* EN DASH */
    "\xc2\x97" => "\xe2\x80\x94", /* EM DASH */

    "\xc2\x98" => "\xcb\x9c",     /* SMALL TILDE */
    "\xc2\x99" => "\xe2\x84\xa2", /* TRADE MARK SIGN */
    "\xc2\x9a" => "\xc5\xa1",     /* LATIN SMALL LETTER S WITH CARON */
    "\xc2\x9b" => "\xe2\x80\xba", /* SINGLE RIGHT-POINTING ANGLE QUOTATION*/
    "\xc2\x9c" => "\xc5\x93",     /* LATIN SMALL LIGATURE OE */
    "\xc2\x9e" => "\xc5\xbe",     /* LATIN SMALL LETTER Z WITH CARON */
    "\xc2\x9f" => "\xc5\xb8"      /* LATIN CAPITAL LETTER Y WITH DIAERESIS*/
    );

    private function cp1252_to_utf8($str) {
            return  strtr(utf8_encode($str), $this->cp1252_map);
    }

    
    
    // Global procedure execution
    private function execute_or_query(&$stmt) {
        $args = func_get_args();
        $stmt = array_shift($args);
        $procedure = array_shift($args);
        if ($this->prepare) {
                $stmt = ibase_prepare ($procedure);
                $rid = eval('return ibase_execute($stmt'.(count($args) > 0 ? ', $args['. implode('], $args[', array_keys($args)) .']' : '').');');
        } else {
                $rid = eval('return ibase_query($procedure'.(count($args) > 0 ? ', $args['. implode('], $args[', array_keys($args)) .']' : '').');');
        }
        return $rid;
    }

    private function unprepare(&$stmt) {
        if ($this->prepare==0) $stmt = null;
    }

    // Find latest possible KTM procedure
    private function get_procedure($pid, $bOnlyName = false) {
        $list = $this->procedures[$pid];
        reset($list);
        $procedure = key($list); // Gets the first key in the list
	list($pname,$x) = explode(":",$pid);
        $key = "INTF#_".str_replace("_","#_",$pname).'#___';
	$proc = self::sql_procedure;
	//file_put_contents($key."proc.txt",$proc);
	//file_put_contents($key."txt",$key);
	
        $rid = $this->execute_or_query($stmt, self::sql_procedure, $key);
        if ($rid) {
            if ($row = ibase_fetch_row($rid)) {
                    if ((string)$row[0]!='') {
                            $procedure = trim((String)$row[0]);
                            if (!isset($list[$procedure])) {
                                    // KTM has a later procedure than we can use here, so use our latest
                                    end($list);
                                    $procedure=key($list);
                            }
                    }
            }
            ibase_free_result($rid);
        }
        $this->unprepare($stmt);

        if ($bOnlyName) return array($procedure, $this->procedures[$pid][(string)$procedure]);
        else return $this->procedures[$pid][(string)$procedure];
    }

    /*
     * Récupération standalone des prêts
     */
    public function getUserLoans($userIntn, $serialized=false) {
        return null;
    }

    /*
     * Récupération standalone de l'historique de prêts
     */
    public function getUserLoansHistory($userInt, $serialized=false) {
        return null;
    }

    /*
     * Récupération standalone de l'historique de réservations
     */
    public function getUserBookingsHistory($userInt) {
        return null;
    }

    public function prolongLoan($id, $userid="") {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');

        $this->connect();

        $procedure = $this->get_procedure("PROLONGPRETNI");
        $this->execute_or_query($stmt,$procedure, intval($id));

        $this->unprepare($stmt);
        $this->disconnect();

        //La procédure ne revoie rien par défaut donc on retourne un XML de confirmation
        $prolong = $xml->addChild('prolongation');
        $prolong->addChild('sigb',     self::nameClass);
        $prolong->addChild('id',       $id);
        $prolong->addChild('error',    0);
        $prolong->addChild('code',     0);

        return $xml->asXML();
    }

    /*
     * Récupère la liste des établissements pour réserver
     */
    public function reserveInfo($idNotice, $userInt) {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');
        $this->connect();

        $procedure = $this->get_procedure("RES_INFO");
        $rid = $this->execute_or_query($stmt,$procedure, $idNotice, intval($userInt));

        $resa = $xml->addChild('reservationInfo');
        $resa->addChild('sigb',     self::nameClass);
        $resa->addChild('user',     $userInt);
        $resa->addChild('nn',       $idNotice);
        $code = 0;
        $errorCode = 0;

        while ($row = ibase_fetch_assoc($rid)) {
            //Ajout des sites proposés
            if ($row['RESOK'] == '3') {
                //Si un seul site, COCHE n'est pas forcément présent
                if (strpos($row['INFOSRES'], 'COCHE') === FALSE) {
                    list($site, $dispo) = explode(chr(166), $row['INFOSRES'], 2);
                    $coche = 'COCHE=T';
                }
                //else list($coche, $site, $dispo) = explode(chr(166), $row['INFOSRES'], 3);
				
				else {
					$infores_tmp = explode(chr(166), $row['INFOSRES']);
					$nb_site = count($infores_tmp);
					
					for ($i = 0; $i <= $nb_site; $i++) {
						if (ereg("SITE=",$infores_tmp[$i])) $site = $infores_tmp[$i];
						elseif (ereg("DISPO=",$infores_tmp[$i])) $dispo = $infores_tmp[$i];
						elseif (ereg("COCHE=",$infores_tmp[$i])) $coche = $infores_tmp[$i];
					}				
				}
				
                $coche = substr($coche, 6);
                $site = htmlspecialchars(substr($site, 5));
                if ($row['CRES'] != '-1' && $dispo == 'DISPO=T') $site .= ' <strong>(Disponible)</strong>';
                $resaSite = $resa->addChild('site', utf8_encode($site));
                $resaSite->addAttribute('id', $row['CRES']);
                $resaSite->addAttribute('coche', $coche);
            }
            else {
                $code = $row['RESOK'];
                $errorCode = $row['CRES'];
            }
        }
        $resa->addChild('error', $code);
        $resa->addChild('code', $errorCode);

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();

        return $xml->asXML();
    }
    
    public function reserveElectronicals($idElectronicals, $mode, $userInt) {
        return null;
    }

    /*
     * Réserve un document en fonction de l'établissement choisi
     */
    public function reserveDocument($idNotice, $userInt, $site) {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');
        $this->connect();

        $procedure = $this->get_procedure("RES_DOCUMENT");
        $rid = $this->execute_or_query($stmt,$procedure, $idNotice, intval($userInt), intval($site));

        if ($row = ibase_fetch_assoc($rid)) {
                $resa = $xml->addChild('reservationDoc');
                $resa->addChild('sigb',     self::nameClass);
                $resa->addChild('user',     $userInt);
                $resa->addChild('nn',       $idNotice);
                $resa->addChild('infosres', utf8_encode(htmlspecialchars($row['INFOSRES'])));
                $resa->addChild('error',    $row['RESOK']);
                $resa->addChild('code',     ($row['RESOK'] == '1' || $row['RESOK'] == '3' ? '1' : $row['CRES']));
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        return $xml->asXML();
    }

    public function reserveCancel($resid, $userInt) {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');
        $this->connect();

        $procedure = $this->get_procedure("SUPPRIME_RES");
        $rid = $this->execute_or_query($stmt,$procedure, $resid);

        if ($row = ibase_fetch_assoc($rid)) {
            $resa = $xml->addChild('reservationCancel');
            $resa->addChild('sigb',     self::nameClass);
            $resa->addChild('resid',       $resid);
            $resa->addChild('error',    ($row['DELOK'] == 'F' ? -1 : 0));
            $resa->addChild('code',     0);
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        return $xml->asXML();
    }

    public function updateAccount($formDatas) {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');
        $errorReturn = -1;

        //Autorisation de changement de mot de passe
        if (isset($formDatas['password'])) {
            $this->connect();
            $procedure = $this->get_procedure("GET_PARAM");
            $rid = $this->execute_or_query($stmt, $procedure);
            if ($row = ibase_fetch_assoc($rid)) $type = $row['VA'];
            switch (substr($type,0,1)) {
                case 'N':
                case '0':
                    $errorReturn = 2;
                    break;
                default:
                    $errorReturn = 0;
                    break;
            }
            //if (($type == 'N') or ($type != 'P')) $errorReturn = 2;
            //else $errorReturn = 0;
            ibase_free_result($rid);
            $this->unprepare($stmt);
            $this->disconnect();
            
            //Vérification du mot de passe actuel
            if ($errorReturn == 0) {
                $xmlOldPassString = $this->login($formDatas['username'], $formDatas['password']);
                $xmlOldPass = simplexml_load_string($xmlOldPassString);
                if ($xmlOldPass->login->error != '0') $errorReturn = 1;
            }
        } else {
            if (isset($formDatas['email'])) $errorReturn = 0;
        }

        //Update
        if ($errorReturn == 0) {
            $this->connect();
            $procedureDesc = $this->get_procedure("UPDATE_AB", true);
            $procedureName = $procedureDesc[0];
            $procedureReq = $procedureDesc[1];
            switch ($procedureName) {
                case 'UPDATE_AB' :
                    $rid = $this->execute_or_query($stmt, $procedureReq, (isset($formDatas['newpassword']) ? utf8_decode($formDatas['newpassword']) : null), $formDatas['userid']);
                    break;
                case 'INTF_UPDATE_AB_01' :
                    $rid = $this->execute_or_query($stmt, $procedureReq, $formDatas['userid'], (isset($formDatas['newpassword']) ? utf8_decode($formDatas['newpassword']) : null), (isset($formDatas['email']) ? utf8_decode($formDatas['email']) : null), (isset($formDatas['tel1']) ? utf8_decode($formDatas['tel1']) : null), (isset($formDatas['tel2']) ? utf8_decode($formDatas['tel2']) : null), (isset($formDatas['fax']) ? utf8_decode($formDatas['fax']) : null));
                    break;
            }
            $this->unprepare($stmt);
            $this->disconnect();
        }
        
        $update = $xml->addChild('updateAccount');
        $update->addChild('sigb', self::nameClass);
        $update->addChild('user', $formDatas['username']);
        $update->addChild('error', $errorReturn);
        $update->addChild('code', 0);

        return $xml->asXML();
    }
    
    public function updateGroupAccount($formDatas) {
        return null;
    }

    public function userLostPassword($mail) {
        return null;
    }

    public function sendMessage($userInt, $mailId, $action, $object, $text, $suggTitle, $suggAuthor, $suggEditor, $suggDocType) {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');

        $this->connect();

        $procedure = $this->get_procedure("MSGABO_UPDATE");

        switch ($action) {
            case 'Del':
            case 'read':
                $ids = explode(",", $mailId);
                foreach ($ids as $id) {
                    $this->execute_or_query($stmt,$procedure, $action, intval($id), intval($userInt), null, null, null, null, null, null);
                }
                break;
            default:
                $msgid   = ($action=='Add' || $action=='AddSugg') ? null : $mailId;
                $object  = utf8_decode($object);
                $text = utf8_decode($text);
                $suggDocType = utf8_decode($suggDocType);
                $suggTitle   = utf8_decode($suggTitle);
                $suggAuthor  = utf8_decode($suggAuthor);
                $suggEditor  = utf8_decode($suggEditor);

                $this->execute_or_query($stmt,$procedure, $action, intval($msgid), intval($userInt), $object, $text, (empty($suggDocType) ? null : intval($suggDocType)), $suggTitle, $suggAuthor, $suggEditor);
                break;
        }

        $this->unprepare($stmt);
        $this->disconnect();

        //La procédure ne revoie rien par défaut donc on retourne un XML de confirmation
        $prolong = $xml->addChild('message');
        $prolong->addChild('sigb',     self::nameClass);
        $prolong->addChild('id',       $id);
        $prolong->addChild('error',    0);
        $prolong->addChild('code',     0);

        return $xml->asXML();
    }

    private function isoNotice($idNotice) {
        $this->connect();
        $unimarc = '';

        $procedure = $this->get_procedure("NOTICEUNIMARC");
        $rid = $this->execute_or_query($stmt,$procedure, $idNotice);
        while ($row = ibase_fetch_assoc($rid)) {
            $unimarc = $row['UNIMARC'];
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        return $unimarc;
    }

    private function isoDeletedNotice($idNotice, $returnIso = true) {
        $code = '001';
        // Variables utilisées
        $fin_champ = self::ISO2709_FIELD_TERMINATOR;
        $code_sous_zone = self::ISO2709_SUBFIELD_FIRST_IDENTIFIER;
        $blanc = " "; // car blanc
        $fin_notice = self::ISO2709_RECORD_TERMINATOR;

        // Initialise la notice, le répertoire notice et la position curseur
        $notice = '';
        $rep_notice = '';
        $curseur = "00000";

        $label_notice = '00611d####2200217###45##';		// Remplacé ensuite (temporaire)
        $label_notice = str_replace('#',' ',$label_notice);
        // Divers trait. suivant la zone
	$ligne = '';

        // Extrait le contenu
        $contenu = $idNotice;

        $code =  substr($code,0,3);
        $code_sans_zone = $code;
        $zone = '';
        $ligne = '';

        // ECRIT LA LIGNE
        // Mettre les indicateurs en début de nouvelle ligne et le contenu de cette zone
        $ligne = $ligne.$contenu;
        // Calcule le répertoire :
        // Calcule la longueur(4) et rempli les zeros
        $ligne=str_replace('"','&quot;',$ligne);
        $longueur_ligne = strlen($ligne)+1;
        $longueur_ligne = $this->isoRempli4($longueur_ligne);

        $rep_notice = $rep_notice.$code_sans_zone.$longueur_ligne.$curseur;

        // Place le curseur pour la prochaine ligne
        $curseur = $curseur + $longueur_ligne;
        $curseur = $this->isoRempli5($curseur);

        // Ajoute la ligne aux datas de la notice
        $notice = $notice.$ligne.$fin_champ;

        // Initialisation des champs
        $indicateurs = $blanc.$blanc;
        $ligne = $indicateurs;

        // Fin de Répertoire
        $rep_notice = $rep_notice.$fin_champ;

        // Fin de notice
        $notice = $rep_notice.$notice.$fin_notice;

        // Calcul de la longueur de notice
        $longueur_notice = strlen($notice) + 24;
        $longueur_notice = $this->isoRempli5($longueur_notice);

        // Calcul du début des données
        $debut_donnees = strlen($rep_notice) + 24;
        $debut_donnees = $this->isoRempli5($debut_donnees);

        // Ajout de la longueur au label
        $label_notice = substr($label_notice, 5);
        $label_notice = $longueur_notice.$label_notice;

        // Ajout du debut de données
        $label_notice = substr_replace($label_notice, $debut_donnees, 12, 5);

        // Finalisation de la notice
        $notice = $label_notice.$notice;

        if ($returnIso) {
            return $notice;
        }
        else {
            return $label_notice;
        }
    }

    private function isoRempli4($chaine) {
        if ($chaine < 10) {$chaine = '0'.'0'.'0'.$chaine;}
        elseif ($chaine < 100) {$chaine = '0'.'0'.$chaine;}
        elseif ($chaine < 1000) {$chaine = '0'.$chaine;}
        return $chaine;
    }

    private function isoRempli5($chaine) {
        if ($chaine < 10) {$chaine = '0'.'0'.'0'.'0'.$chaine;}
        elseif ($chaine < 100) {$chaine = '0'.'0'.'0'.$chaine;}
        elseif ($chaine < 1000) {$chaine = '0'.'0'.$chaine;}
        elseif ($chaine < 10000) {$chaine = '0'.$chaine;}
        return $chaine;
    }

    public function importAB($na, $nom, $pn, $ccivilite, $sexe, $datenaissance, $adresse1, $adresse2, $cp, $ville, $tel1, $tel2, $email, $ccat1, $ccat2, $ccat3, $ccat4, $cannexe, $ccotis, $date_debut, $date_fin) {
        $this->connect();

        $procedure = $this->get_procedure("ADDMODIF_AB");
        $rid = $this->execute_or_query($stmt,$procedure, $na, utf8_decode($nom), utf8_decode($pn), intval($ccivilite), $sexe, $datenaissance, utf8_decode($adresse1), utf8_decode($adresse2), $cp, utf8_decode($ville), $tel1, $tel2, utf8_decode($email), (empty($ccat1) ? null : intval($ccat1)), (empty($ccat2) ? null : intval($ccat2)), (empty($ccat3) ? null : intval($ccat3)), (empty($ccat4) ? null : intval($ccat4)), intval($cannexe));

        try {
            if (!($row = @ibase_fetch_assoc($rid))) throw new Exception('Erreur à l\'insertion de l\'abonné dans la base');
        }
        catch (Exception $e) {
            $row = array();
            $row['CODE_ERREUR'] = -1;
            $row['DES_ERREUR'] = utf8_decode($e->getMessage());
        }

        $return = '<import><errorCode>'.$row['CODE_ERREUR'].'</errorCode><errorDes>'.utf8_encode($row['DES_ERREUR']).'</errorDes><cab>'.$row['CAB'].'</cab>'.($row['CODE_ERREUR'] == 0 ? $this->cotisAB($row['CAB'], $na, $ccotis, $date_debut, $date_fin) : '').'</import>';

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();

        return $return;
    }

    public function cotisAB($cab, $na, $ccotis, $date_debut, $date_fin) {
        $this->connect();

        $procedure = $this->get_procedure("ADDMODIF_COTISAB");
        $rid = $this->execute_or_query($stmt,$procedure, intval($cab), $na, intval($ccotis), $date_debut, $date_fin);

        try {
            if (!($row = @ibase_fetch_assoc($rid))) throw new Exception('Erreur à l\'affectation de la cotisation');
        }
        catch (Exception $e) {
            $row = array();
            $row['CODE_ERREUR'] = -1;
            $row['DES_ERREUR'] = utf8_decode($e->getMessage());
        }

        $return = '<cotis><errorCode>'.$row['CODE_ERREUR'].'</errorCode><errorDes>'.utf8_encode($row['DES_ERREUR']).'</errorDes></cotis>';

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();

        return $return;
    }

    public function getListes() {
        $xml = '<sites>'.$this->listeSite().'</sites><civilites>'.$this->listeCivilite().'</civilites><cotisations>'.$this->listeCotis().'</cotisations><categories>'.$this->listeTypeCat().'</categories>';
        return $xml;
    }

    private function listeSite() {
        $this->connect();

        $procedure = $this->get_procedure("LISTESITE");
        $rid = $this->execute_or_query($stmt,$procedure);

        while ($row = ibase_fetch_assoc($rid)) {
            $return .= '<site><cannexe>'.$row['CANNEXE'].'</cannexe><shortName>'.$row['NOM_COURT'].'</shortName></site>';
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();

        return $return;
    }

    private function listeTypeCat() {
        $this->connect();

        $procedure = $this->get_procedure("LISTTYPECAT");
        $rid = $this->execute_or_query($stmt,$procedure);

        while ($row = ibase_fetch_assoc($rid)) {
            $return .= '<typeCat><idCat>'.$row['NUMCAT'].'</idCat><desCat>'.$row['DES'].'</desCat>'.$this->listeCat($row['NUMCAT']).'</typeCat>';
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();

        return $return;
    }

    private function listeCat($id) {
        $this->connect();

        $procedure = $this->get_procedure("LISTCAT");
        $rid = $this->execute_or_query($stmt,$procedure, intval($id));

        while ($row = ibase_fetch_assoc($rid)) {
            $return .= '<cat><id>'.$row['CCAT'].'</id><des>'.$row['DES'].'</des></cat>';
        }

        return $return;
    }

    private function listeCotis() {
        $this->connect();

        $procedure = $this->get_procedure("LISTECOTIS");
        $rid = $this->execute_or_query($stmt,$procedure);

        while ($row = ibase_fetch_assoc($rid)) {
            $return .= '<cotis><ccotis>'.$row['CCOTIS'].'</ccotis><des>'.$row['DES'].'</des></cotis>';
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();

        return $return;
    }

    private function listeCivilite() {
        $this->connect();

        $procedure = $this->get_procedure("LISTECIVILITE");
        $rid = $this->execute_or_query($stmt,$procedure);

        while ($row = ibase_fetch_assoc($rid)) {
            $return .= '<civilite><ccivilite>'.$row['CCIVILITE'].'</ccivilite><des>'.$row['DES'].'</des></civilite>';
        }

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();

        return $return;
    }

    /*
    public function scan($element) {
        $element = explode(",", $element['scan']);
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><root></root>');
        $this->connect();

        $procedure = $this->get_procedure("SCAN");

        $scan = $xml->addChild('scan');
        $scan->addChild('sigb', self::nameClass);
        $scanItems = $scan->addChild('items');
        foreach ($element as $scanElement) {
            $items = $scanItems->addChild(strtoupper($scanElement));
            $rid = $this->execute_or_query($stmt,$procedure, strtoupper($scanElement), '', 0);
            while ($row = ibase_fetch_assoc($rid)) {
                $item = $items->addChild('item', utf8_encode($row['DISPLABEL']));
                $item->addAttribute('id', $row['CODE']);
            }
        }

        $scan->addChild('error', 0);
        $scan->addChild('code', 0);

        ibase_free_result($rid);
        $this->unprepare($stmt);
        $this->disconnect();
        return $xml->asXML();
    }
    */

//    private function iso2709_to_xml($row, $code='iso-5426-1') {
/*        $notice = new SimpleXMLExtend('<?xml version="1.0" encoding="utf-8"?><Notice></Notice>');*/
//        $unimarc = $notice->addChild('Unimarc');
//
//        if ($row=='ERROR') return $notice; //Vérification validité notice
//
//        $record_length = intval(substr($row,0,5));
//        $data_start = intval(substr($row,12,5))+1;
//        $structure = substr($row,24,$data_start-25);
//
//        $charset = $this->getCharset($row, $code, $data_start, $structure); // Get F100$a pos 26-27 or 28-29
//        for ($i=0;$i<strlen($structure)-1;$i=$i+12) {
//                $zone  = substr($structure,$i,3);
//                $checkZone = preg_replace('/[^a-zA-Z0-9]/', '', $zone);
//                if ($zone != $checkZone) continue;
//
//                $length = intval(substr($structure,$i+3,4));
//                $start= intval(substr($structure,$i+7,5));
//                $field_zone = substr($row,$data_start+$start-1,$length);
//
//                // zones
//                $t = explode(self::ISO2709_FIELD_TERMINATOR,$field_zone);
//                $data = self::all_encode($charset,$t[0]);
//
//                //$zone = $this->rename_field($zone);
//
//                $datazone = false;
//                switch ($zone) {
//                        case '001':
//                                //$data = $this->mod_id($data);
//                                $unimarc->addChild('F001',trim($data));
//                                $notice->addChild('NN',trim($data));
//                                $datazone = true;
//                                break;
//                        case '005':
//                                $unimarc->addChild('F005',trim($data));
//                                $datazone = true;
//                                break;
//                }
//
//                if ($datazone) continue;
//
//                // subzones
//
//                $field_subzones = explode(self::ISO2709_SUBFIELD_FIRST_IDENTIFIER, $field_zone);
//                $previous_subzone = '';
//                $xmlzone = $unimarc->addChild('F'.$zone);
//
//                $indice1 = preg_replace('/[^0-9]/', '', substr($field_subzones[0],0,1));
//                $indice2 = preg_replace('/[^0-9]/', '', substr($field_subzones[0],1,1));
//                if ($indice1!='') $xmlzone->addAttribute('Indic1',$indice1);
//                if ($indice2!='') $xmlzone->addAttribute('Indic2',$indice2);
//
//                for ($j=1;$j<count($field_subzones);$j++) {
//                        $field_subzone = $field_subzones[$j];
//                        $subzone = substr($field_subzone,0,1);
//
//                        $subzone = preg_replace ( '/[^a-zA-Z0-9 ]/', '', $subzone );
//                        if ($subzone=='') continue;
//
//                        //$subzone = $this->rename_field($zone, $subzone);
//
//                        $data = substr($field_subzone,1);
//                        if ($j+1==count($field_subzones)) {
//                                $t = explode(self::ISO2709_FIELD_TERMINATOR,$data);
//                                $data = $t[0];
//                        }
//                        $data = self::all_encode($charset, $data);
//
//                        //$data = $this->stripInvalidXml($data);
//                        if ($data=='') continue;
//
//                        // The Subzone itself
//                        $xmlzone->addChild('SF'.$subzone,$data);
//                        // Why should we do this ?
//                        //$xmlzone->addChild('SF'.$subzone,htmlentities($data));
//
//                }
//        }
//        return $notice;
//    }

//    private function getCharset($row, $code, $data_start, $structure) {
//        $default_charset = 'iso-5426-1';
//        $charset = '';
//        for ($i=0;$i<strlen($structure)-1;$i=$i+12) {
//                $zone  = substr($structure,$i,3);
//                $length = intval(substr($structure,$i+3,4));
//                $start= intval(substr($structure,$i+7,5));
//                $field_zone = substr($row,$data_start+$start-1,$length);
//                if ($zone=='100') {
//                        $field_subzones = explode(self::ISO2709_SUBFIELD_FIRST_IDENTIFIER, $field_zone);
//                        for ($j=1;$j<count($field_subzones);$j++) {
//                                $field_subzone = $field_subzones[$j];
//                                $subzone = substr($field_subzone,0,1);
//                                $data = substr($field_subzone,1);
//                                if ($j+1==count($field_subzones)) {
//                                        $t = explode(self::ISO2709_FIELD_TERMINATOR,$data);
//                                        $data = $t[0];
//                                }
//                                $data = self::all_encode($code, $data);
//                                if ($subzone=='a') {
//                                        $charset = substr($data,26,4);
//                                        break;
//                                }
//                        }
//                        break; // Break out of the for loop. No longer required
//                }
//        }
//
//        $returncharset = $this->code_to_charset(substr($charset,2,2));
//        if ($returncharset=='') $returncharset=$this->code_to_charset(substr($charset,0,2));
//        if ($returncharset=='') $returncharset=$default_charset;
//
//        return $returncharset;
//    }

//    private function code_to_charset($code) {
//        // Only supports 8859 and 5426 at the moment
//        // To add more, we need a conversion in the all_encode() function
//                // From Unimarc Documentation
//                01 = ISO 646, IRV version (basic Latin set)
//                02 = ISO Registration # 37 (basic Cyrillic set)
//                03 = ISO 5426 (extended Latin set)
//                04 = ISO DIS 5427 (extended Cyrillic set)
//                05 = ISO 5428 (Greek set)
//                06 = ISO 6438 (African coded character set)
//                07 = ISO 10586 (Georgian set)
//                08 = ISO 8957 (Hebrew set) Table 1
//                09 = ISO 8957 (Hebrew set) Table 2
//                10 = [Reserved]
//                11 = ISO 5426-2 (Latin characters used in minor European languages and obsolete typography)
//                50 = ISO 10646 Level 3 (Unicode)
//                */
//        switch ($code) {
//                case '01': return 'iso-8859-1'; break;
//                case '03': return 'iso-5426-1'; break;
//                case '50': return 'UTF-8'; break;
//                default: return ''; break;
//        }
//    }

//    private function all_encode($code, $data) {
//        switch (strtolower($code)) {
//                case 'iso-8859-1':
//                        //$data = iconv("CP1252","UTF-8", $data); // Seems to work OK
//                        //$data = utf8_encode($data); // No euro sign
//
//                        // UTF8 encode extension with CP1252 characters.
//                        // Routine found in php.net under utf8_encode http://php.net/manual/en/function.utf8-encode.php
//                        $data = $this->cp1252_to_utf8($data);
//                        return htmlspecialchars($data);
//                        break;
//                case 'iso-5426-1':
//                        $data = Iso5426ToUnicode::convert($data);
//                        $data = $this->cp1252_to_utf8($data);
//                        //$data = utf8_encode($data); // No euro sign
//                        return htmlspecialchars($data);
//                        break;
//                case 'UTF-8':
//                        return htmlspecialchars($data);
//                        break;
//                default:
//                        return htmlspecialchars(utf8_encode($data));
//                        break;
//        }
//    }

    /* This structure encodes the difference between ISO-8859-1 and Windows-1252,
     as a map from the UTF-8 encoding of some ISO-8859-1 control characters to
     the UTF-8 encoding of the non-control characters that Windows-1252 places
     at the equivalent code points. */
//    private $cp1252_map = array(
//    "\xc2\x80" => "\xe2\x82\xac", /* EURO SIGN */
//    "\xc2\x82" => "\xe2\x80\x9a", /* SINGLE LOW-9 QUOTATION MARK */
//    "\xc2\x83" => "\xc6\x92",     /* LATIN SMALL LETTER F WITH HOOK */
//    "\xc2\x84" => "\xe2\x80\x9e", /* DOUBLE LOW-9 QUOTATION MARK */
//    "\xc2\x85" => "\xe2\x80\xa6", /* HORIZONTAL ELLIPSIS */
//    "\xc2\x86" => "\xe2\x80\xa0", /* DAGGER */
//    "\xc2\x87" => "\xe2\x80\xa1", /* DOUBLE DAGGER */
//    "\xc2\x88" => "\xcb\x86",     /* MODIFIER LETTER CIRCUMFLEX ACCENT */
//    "\xc2\x89" => "\xe2\x80\xb0", /* PER MILLE SIGN */
//    "\xc2\x8a" => "\xc5\xa0",     /* LATIN CAPITAL LETTER S WITH CARON */
//    "\xc2\x8b" => "\xe2\x80\xb9", /* SINGLE LEFT-POINTING ANGLE QUOTATION */
//    "\xc2\x8c" => "\xc5\x92",     /* LATIN CAPITAL LIGATURE OE */
//    "\xc2\x8e" => "\xc5\xbd",     /* LATIN CAPITAL LETTER Z WITH CARON */
//    "\xc2\x91" => "\xe2\x80\x98", /* LEFT SINGLE QUOTATION MARK */
//    "\xc2\x92" => "\xe2\x80\x99", /* RIGHT SINGLE QUOTATION MARK */
//    "\xc2\x93" => "\xe2\x80\x9c", /* LEFT DOUBLE QUOTATION MARK */
//    "\xc2\x94" => "\xe2\x80\x9d", /* RIGHT DOUBLE QUOTATION MARK */
//    "\xc2\x95" => "\xe2\x80\xa2", /* BULLET */
//    "\xc2\x96" => "\xe2\x80\x93", /* EN DASH */
//    "\xc2\x97" => "\xe2\x80\x94", /* EM DASH */
//
//    "\xc2\x98" => "\xcb\x9c",     /* SMALL TILDE */
//    "\xc2\x99" => "\xe2\x84\xa2", /* TRADE MARK SIGN */
//    "\xc2\x9a" => "\xc5\xa1",     /* LATIN SMALL LETTER S WITH CARON */
//    "\xc2\x9b" => "\xe2\x80\xba", /* SINGLE RIGHT-POINTING ANGLE QUOTATION*/
//    "\xc2\x9c" => "\xc5\x93",     /* LATIN SMALL LIGATURE OE */
//    "\xc2\x9e" => "\xc5\xbe",     /* LATIN SMALL LETTER Z WITH CARON */
//    "\xc2\x9f" => "\xc5\xb8"      /* LATIN CAPITAL LETTER Y WITH DIAERESIS*/
//    );
//
//    private function cp1252_to_utf8($str) {
//            return  strtr(utf8_encode($str), $this->cp1252_map);
//    }

}
