granularity=$granularity;
	}
	
	/**
	 * \brief Conversion d'une date unix (nomnbres de secondes depuis le 01/01/1970) en date au format iso8601 selon la granularité
	 * @param integer $time date au format unix (nombres de secondes depuis le 01/01/1970)
	 * @return string date au format YYYY-MM-DD ou YYYY-MM-DDThh:mm:ssZ selon la granularité
	 */
	function unixtime_to_iso8601($time) {
		$granularity=str_replace("T","\\T",$this->granularity);
		$granularity=str_replace("Z","\\Z",$granularity);
		$granularity=str_replace("YYYY","Y",$granularity);
		$granularity=str_replace("DD","d",$granularity);
		$granularity=str_replace("hh","H",$granularity);
		$granularity=str_replace("mm","i",$granularity);
		$granularity=str_replace("MM","m",$granularity);
		$granularity=str_replace("ss","s",$granularity);
		$date=date($granularity,$time);
		return $date;
	}
	
	/**
	 * \brief Conversion d'une date au format iso8601 en date au format unix (nomnbres de secondes depuis le 01/01/1970) selon la granularité
	 * @param string $date date au format iso8601 YYYY-MM-DD ou YYYY-MM-DDThh:mm:ssZ selon la granularité
	 * @return integer date au format unix (nombres de secondes depuis le 01/01/1970)
	 */
	function iso8601_to_unixtime($date) {
		$parts=explode("T",$date);
		if (count($parts)==2) {
			$day=$parts[0]; 
			$time=$parts[1];
		} else {
			$day=$parts[0];
		}
		$days=explode("-",$day);
		if ($this->granularity=="YYYY-MM-DDThh:mm:ssZ") {
			if ($time) $times=explode(":",$time);
			if ($times[2]) {
				if (substr($times[2],strlen($times[2])-1,1)=="Z") $times[2]=substr($times[2],0,strlen($times[2])-1);
			}
		}
		$unixtime=mktime($times[0]+0,$times[1]+0,$time[2]+0,$days[1]+0,$days[2]+0,$days[0]+0);
		return $unixtime;
	}
}
/*
 * oai_out_protocol
 * \brief Cette classe gère toute l'entrée sortie http et le protocol oai 
 * Cette classe ne connait pas ses enregistrement ni leur types, elle les récupère grace à une instance d'une classe fille de oai_out_get_records
 * Norme du protocole: http://www.openarchives.org/OAI/openarchivesprotocol.html
 */
class oai_out_protocol {
	private $msg=array();
	private $repositoryName="";
	private $adminEmail;
	private $sets=array();
	private $repositoryIdentifier="";
	private $oai_out_get_records_object=NULL;
	private $known_metadata_formats=array(
		/*"notice_id" => array(
			"metadataPrefix" => "notice_id",
			"metadataNamespace" => "http://sigb.net/pmb/es/oai/notice_id",
			"schema" => "http://sigb.net/pmb/es/oai/notice_id.xsd"
		),*/
		"pmb_xml_unimarc" => array(
			"metadataPrefix" => "pmb_xml_unimarc",
			"metadataNamespace" => "http://sigb.net/pmb/es/oai/pmb_xml_marc",
			"schema" => "http://sigb.net/pmb/es/oai/pmb_xml_marc.xsd"
		),
		"oai_dc" => array(
			"metadataPrefix" => "oai_dc",
			"metadataNamespace" => "http://www.openarchives.org/OAI/2.0/oai_dc/",
			"schema" => "http://www.openarchives.org/OAI/2.0/oai_dc.xsd"
		)
	);
	private $nb_results=100;
	private $token_life_expectancy=600;
	private $compression=true;
	private $deletion_support="no";
	private $errored=false;
	private $xmlheader_sent=false;
	private $base_url="";
	//Constructeur
	function oai_out_protocol($oai_out_get_records_object, &$msg, $repositoryName, $adminEmail, $sets, $repositoryIdentifier, $nb_results, $token_life_expectancy, $compression, $deletion_support, $additional_metadataformats, $base_url) {
		$this->msg = $msg;
		$this->oai_out_get_records_object=$oai_out_get_records_object;
		$this->repositoryName = $repositoryName;
		$this->adminEmail = $adminEmail;
		$this->sets = $sets;
		$this->repositoryIdentifier = $repositoryIdentifier;
		$this->nb_results = $nb_results;
		$this->token_life_expectancy = $token_life_expectancy;
		$this->compression = $compression;
		$this->deletion_support = $deletion_support;
		$this->known_metadata_formats = array_merge($this->known_metadata_formats, $additional_metadataformats);
		$this->base_url = $base_url;
	}
	
	//Renvoie l'entête
	function oai_header() {
		global $verb;
		$page_url = $this->base_url;
		$iso8601 = new iso8601("YYYY-MM-DDThh:mm:ssZ");
		$curdate = $iso8601->unixtime_to_iso8601(time());
		$this->xmlheader_sent = true;
		return '
				
					
						'.$curdate.'
						errored ? '' : 'verb="'.$verb.'"').'>'.XMLEntities($page_url).'';
	}
	//Renvoie le pied de page
	function oai_footer() {
		return '';
	}
	//Renvoie une erreur
	function oai_error($error_code, $error_string) {
		$this->errored = true;
		$buffer = XMLEntities($error_string);
		$buffer = $charset != "utf-8" ? utf8_encode($buffer) : $buffer;
		$result = "";
		$result .= ''.$buffer.'';
		return $result;
	}
	//Renvoie le résultat du verb Identify
	function oai_identify() {
		global $charset;
		global $pmb_version_brut;
		$result = "";
		$result .= "";
		
		$buffer = XMLEntities($this->repositoryName);
		$buffer = $charset != "utf-8" ? utf8_encode($buffer) : $buffer;
		$result .= ''.$buffer.'';
		$result .= ''.XMLEntities($this->base_url).'';
		$result .= '2.0';
		
		$unix_earliestdate = $this->oai_out_get_records_object->get_earliest_datestamp();
		$iso8601 = new iso8601("YYYY-MM-DDThh:mm:ssZ");
		$earliestdate = $iso8601->unixtime_to_iso8601($unix_earliestdate);
		$result .= ''.$earliestdate.'';
		$result .= ''.$this->deletion_support.'';
		$result .= 'YYYY-MM-DDThh:mm:ssZ';
		$buffer = XMLEntities($this->adminEmail);
		$buffer = $charset != "utf-8" ? utf8_encode($buffer) : $buffer;
		$result .= ''.$buffer.'';
		
		$buffer = XMLEntities($this->oai_out_get_records_object->get_sample_oai_identifier());
		$buffer = $charset != "utf-8" ? utf8_encode($buffer) : $buffer;
		$buffer_ri = XMLEntities($this->oai_out_get_records_object->repository_identifier);
		$buffer_ri = $charset !="utf-8" ? utf8_encode($buffer_ri) : $buffer_ri;
		$result .= '
						
						oai
						'.$buffer_ri.'
						:
						'.$buffer.'
						
					';
		
		$result .= '
						
							PMB OAI Connector
							
								Erwan Martin
								emartin@sigb.net
								PMB Services
							
							'.$pmb_version_brut.'
							
							http://sigb.net
						
					';
		
		$result .= "";
		
		return $result;
	}
	
	//Renvoie le résultat du verb ListSets
	function oai_list_sets() {
		$result = '';
		$result .= '';
		foreach ($this->sets as $aset) {
			$buffer = XMLEntities($aset["caption"]);
			$buffer = $charset != "utf-8" ? utf8_encode($buffer) : $buffer;
			
			$result .= '
    						set_'.XMLEntities($aset["id"]).'
    						'.$buffer.'
  						';
		}
		
		$result .= '';
		return $result;
	}
	
	//Renvoie le résultat du verb ListRecords
	function oai_list_records($root_tag="ListRecords") {
		global $charset, $dbh, $set, $resumptionToken, $from, $until;
		//Vérifications préhalables
		global $metadataPrefix;
		if (!$metadataPrefix)
			$metadataPrefix = "oai_dc";
		if (substr($metadataPrefix, 0, 8) == "convert:") {
			
		}
		else if (($metadataPrefix != "__oai_identifier") && !in_array($metadataPrefix, array_keys($this->known_metadata_formats))) {
			$erreur_message = $charset != "utf-8" ? utf8_encode(sprintf($this->msg["cannotDisseminateFormat"], XMLEntities($metadataPrefix))) : sprintf($this->msg["cannotDisseminateFormat"], XMLEntities($metadataPrefix));
			return $this->oai_error("cannotDisseminateFormat", $erreur_message);
		}
		//Un peu de ménage dans les tokens
		$sql = "DELETE FROM connectors_out_oai_tokens WHERE NOW() >= connectors_out_oai_token_expirationdate";
		mysql_query($sql, $dbh);
		//On aura besoin d'un objet date iso magique
		$iso8601 = new iso8601("YYYY-MM-DDThh:mm:ssZ");
		$result = "";
		$max_records = $this->nb_results;
		$total_number_of_records=0;
		$datefrom=false;
		$dateuntil=false;
		
		//Un token? Cherchons le dans la base de donnée et restaurons son environnement
		if ($resumptionToken) {
			$sql = "SELECT connectors_out_oai_token_environnement FROM connectors_out_oai_tokens WHERE connectors_out_oai_token_token = '".addslashes($resumptionToken)."'";
			$res = mysql_query($sql, $dbh);
			if (!mysql_num_rows($res))
				return $this->oai_error("badResumptionToken", $this->msg["badResumptionToken"]);
			$row = mysql_fetch_assoc($res);
			$config = unserialize($row["connectors_out_oai_token_environnement"]);
			$set_id_list = $config["sets"];
			$datefrom = $config["datefrom"];
			$dateuntil = $config["dateuntil"];
			$metadataPrefix = $config["metadataprefix"];
		}
		//Sinon config de début de recherche
		else {
			//Vérifions si on souhaite un set précis
			if (isset($set) && $set) {
				$the_set_id = substr($set, 4);
				//On a un id, vérifions qu'il existe dans la liste
				$found=false;
				foreach ($this->sets as $aset) {
					if ($aset["id"] == $the_set_id) {
						$found = true;
						break;
					}
				}
				//Non? Erreur!
				if (!$found) {
					$buffer = $charset != 'utf-8' ? utf8_encode($this->msg["unknown_set"]) : $this->msg["unknown_set"];
					return $this->oai_error("unknown_set", $buffer);
				}
				//Oui? On génère la "liste" des sets
				else {
					$set_id_list = array(0=>array("id" => $the_set_id));
				}
			}
			//Sinon on fouille dans tous les sets
			else 
				$set_id_list = $this->sets;
				
			if (isset($from) && $from)
				$datefrom = $iso8601->iso8601_to_unixtime($from);
			if (isset($until) && $until)
				$dateuntil = $iso8601->iso8601_to_unixtime($until);
		}
		//Allons chercher les enregistrements grace à la classe associée
		$records=array();
		foreach($set_id_list as &$aset) {
			if (!isset($aset["fetched_count"]))
				$aset["fetched_count"] = 0;
			//Si on en a déjà assez, on ne fait que compter (pour le total)
			if (count($records) >= $max_records) {
				$total_number_of_records += $this->oai_out_get_records_object->get_record_count($aset["id"], $datefrom, $dateuntil);
				continue;
			}
			
			//Si on a déjà tout extrait dans ce set, on compte et on continue
			if ($aset["fetched_count"]) {
				 $current_set_count = $this->oai_out_get_records_object->get_record_count($aset["id"], $datefrom, $dateuntil);
				 if ($aset["fetched_count"] == $current_set_count) {
				    $total_number_of_records += $current_set_count;
				 	continue;
				 }
			}
			//Allons chercher les enregistrements du set
			$number_to_fetch = $max_records - count($records);
			$set_records = $this->oai_out_get_records_object->get_records($aset["id"], $metadataPrefix, $aset["fetched_count"], $number_to_fetch, $datefrom, $dateuntil);
			$aset["fetched_count"] += count($set_records);
			$current_set_count = $this->oai_out_get_records_object->get_record_count($aset["id"], $datefrom, $dateuntil);
			$total_number_of_records += $current_set_count;
			foreach($set_records as $notice_id => $record_content) {
				if (!isset($records[$notice_id])) {
					$records[$notice_id] = $record_content;
				}
			}
		}
		//Si pas d'enregistrement, le protocol veut qu'on renvoie une erreur
		if (!$records) {
			$erreur_message = $charset != "utf-8" ? utf8_encode($this->msg["noRecordsMatch"]) : $this->msg["noRecordsMatch"];
			return $this->oai_error("noRecordsMatch", $erreur_message);
		}
		
		//Affichons les enregistrements
		$result .= " <".$root_tag.">";
		foreach ($records as $arecords) {
			$result .= $arecords;
		}
		//Calculons le curseur
		$cursor = 0;
		foreach($set_id_list as $aset_c) {
			if (!isset($aset_c["fetched_count"]))
				continue;
			$cursor += $aset_c["fetched_count"];
		}
		if ($cursor < $total_number_of_records) {
			//Enregistrons l'environnement
			$env=array(
				"sets" => $set_id_list,
				"datefrom" => $datefrom,
				"dateuntil" => $dateuntil,
				"metadataprefix" => $metadataPrefix
			);
			$token = md5(microtime());
			$sql = "INSERT INTO connectors_out_oai_tokens (connectors_out_oai_token_token, connectors_out_oai_token_environnement, connectors_out_oai_token_expirationdate) VALUES ('".$token."', '".addslashes(serialize($env))."', NOW() + INTERVAL ".$this->token_life_expectancy." SECOND)";
			mysql_query($sql, $dbh);
			
			$token_expiration_date = time() + $this->token_life_expectancy;
			$result .= ''.$token.'';
		}
		
		$result .= " ".$root_tag.">";
		return $result;
	}
	
	function oai_list_identifier() {
		global $metadataPrefix;
		$metadataPrefix = "__oai_identifier";
		return $this->oai_list_records('ListIdentifiers');
	}
	
	function oai_get_record() {
		global $identifier;
		global $metadataPrefix;
		global $charset;
		if (!$metadataPrefix)
			$metadataPrefix = "oai_dc";
			
		$record = $this->oai_out_get_records_object->get_record($identifier, $metadataPrefix);
		if ($record === false) {
			$error_message = $charset != 'utf-8' ? utf8_encode($this->msg["idDoesNotExist"]) : $this->msg["idDoesNotExist"];
			return $this->oai_error("idDoesNotExist", $error_message);
		}
		$result = "";
		$result .= $record;
		$result .= "";
		return $result;
	}
	
	//Renvoie le résultat du verb ListMetadataFormat
	function oai_list_metadata_formats() {
		$result = '';
		$result .= '';
		foreach ($this->known_metadata_formats as $aformat) {
			$result .= '
	     					'.$aformat["metadataPrefix"].'
	     					'.$aformat["schema"].'
	     					'.$aformat["metadataNamespace"].'
	   					';			
		}
		$result .= '';
		return $result;		
	}
	
	function sets_being_refreshed(){
		global $charset, $dbh, $set;
		global $verb;
			
		$set_id_list = array();
		//dans certains cas, cela n'a pas d'importance...
		switch($verb) {
			case 'ListRecords':
			case 'GetRecord':
				//Vérifions si on souhaite un set précis
				if (isset($set) && $set) {
					$the_set_id = substr($set, 4);
					//On a un id, vérifions qu'il existe dans la liste
					$found=false;
					foreach ($this->sets as $aset) {
						if ($aset["id"] == $the_set_id) {
							$found = true;
							break;
						}
					}
					//Non? Erreur!
					if ($found) {
						$set_id_list = array($the_set_id);
					}
				} else{
					$set_id_list = array();
					foreach($this->sets as $aset){
						$set_id_list[] = $aset['id'];
					}
				} 
				$query = "select being_refreshed from connectors_out_sets where being_refreshed=1 and connector_out_set_id in (".implode(",",$set_id_list).")";
				$res = mysql_query($query);
				if(mysql_num_rows($res)>0){
					$result = true;
				}else {
					$result = false;
				}
				break;
			default:
				$result = false;
				break;
		}
		return $result;
	}
}
/*
 * oai_out_get_records
 * \brief Cette classe utilisée par la classe oai_out_protocol permet de récupérer les metadatas des enregistrements (en UTF-8)
 * 
 */
abstract class oai_out_get_records {
	public $error_code="";
	public $error_string="";
	private $msg=array();
	protected $total_record_count_per_set=array();
	
	//Constructeur
	public function oai_out_get_records(&$msg) {
		$this->msg=$msg;
	}
	//Renvoi un exemple d'identifier
	abstract public function get_sample_oai_identifier();
	//Renvoi le datestamp du plus viel enregistrement
	abstract public function get_earliest_datestamp();
	//Retourne le nombre d'enregistrements
	abstract public function get_record_count($set_id, $datefrom=false, $dateuntil=false);
	//Retrouve un enregistrement
    abstract public function get_record($rec_id, $format);
    //Liste les enregistrements
    abstract public function get_records($set_id="", $format, $first=false, $count=false, $datefrom=false, $dateuntil=false);
}
/*
 * oai_out_get_records_notice
 * \brief Cette classe récupère les enregistrements pour un entrepot oai de notices 
 * 
 */
class oai_out_get_records_notice extends oai_out_get_records {
	public $oai_cache_duration = 84000;
	public $source_set_ids=array();
	public $repository_identifier="";
	public $notice_statut_deletion=0;
	public $include_items=0;
	public $include_links=array('genere_lien'=>0);
	protected $xslt = "";
	
	//Constructeur
	public function oai_out_get_records_notice(&$msg,$xslt="") {
		parent::oai_out_get_records($msg);
		$this->xslt = $xslt;
	}
	
	
	
	public function get_sample_oai_identifier() {
		$result = 123456789;
		//Allons chercher un notice_id dans un set
		foreach ($this->source_set_ids as $asetid) {
			$co_set = new_connector_out_set_typed($asetid);
			$co_set->update_if_expired();
			$values = $co_set->get_values();
			//Set vide? On cherche dans un autre
			if (!$values)
				continue;
			//On en a un? On le prend
			$result = $values[0];
			break;
		}
		$result = "oai:".$this->repository_identifier.":".$result;
		return $result;
	}
	
	public function get_earliest_datestamp() {
		//Allons chercher la date la plus vieille pour chaque set, et ensuite on prendra la plus vieille
		$current_min_unix_timestamp = time();
		foreach ($this->source_set_ids as $asetid) {
			$co_set = new_connector_out_set_typed($asetid);
			$co_set->update_if_expired();
			$set_min_date = $co_set->get_earliest_updatedate();
			$current_min_unix_timestamp = $set_min_date < $current_min_unix_timestamp ? $set_min_date : $current_min_unix_timestamp; 
		}
		return $current_min_unix_timestamp;
	}
	
	public function get_record($rec_id, $format) {
		global $charset;
		//Extractons l'id de la notice
		$notice_id = substr(strrchr($rec_id, ":"), 1);
		if (!$notice_id)
			return false;
		//Vérifions que la notice est bien dans les sets de la source
		$notice_sets = connector_out_set_noticecaddie::get_notice_setlist($notice_id);
		$notice_sets = array_intersect($notice_sets, $this->source_set_ids);
		if (!$notice_sets)
			return false;
		$co_set = new_connector_out_set_typed($notice_sets[0]);
		$co_set->update_if_expired();
		$oai_cache = new external_services_converter_oairecord(1, $this->oai_cache_duration, $co_set->cache->cache_duration_in_seconds(), $this->source_set_ids, $this->repository_identifier, $this->notice_statut_deletion, $this->include_items,$this->xslt,$this->include_links);
		$records = $oai_cache->convert_batch(array($notice_id), $format, 'utf-8');
/*		if ($records && $records[$notice_id])
			if (($charset != 'utf-8') && !in_array($format, $this->utf8_formats))
				$records[$notice_id] = utf8_encode($records[$notice_id]);*/
		return $records ? $records[$notice_id] : false;
	}
	
	public function get_records($set_id=0, $format, $first=false, $count=false, $datefrom=false, $dateuntil=false) {
		global $charset;
		//Récupérons du cache les ids des notices
		$co_set = new_connector_out_set_typed($set_id);
		$co_set->update_if_expired();
		$notice_ids = $co_set->get_values($first, $count, $datefrom, $dateuntil);
		$this->total_record_count[$set_id] = $co_set->get_value_count($datefrom, $dateuntil);
		//Récupérons les enregistrements (avec gestion du cache)
		$oai_cache = new external_services_converter_oairecord(1, $this->oai_cache_duration, $co_set->cache->cache_duration_in_seconds(), $this->source_set_ids, $this->repository_identifier, $this->notice_statut_deletion, $this->include_items,$this->xslt,$this->include_links);
		$records = $oai_cache->convert_batch($notice_ids, $format, 'utf-8');
/*		if ($records) {
			if (($charset != 'utf-8') && !in_array($format, $this->utf8_formats)) {
				foreach ($records as $rnotice_id => $rrecord_content) {
					$records[$rnotice_id] = utf8_encode($rrecord_content);
				}
			}
		}*/
		
		return $records;
	}
	
	public function get_record_count($set_id, $datefrom=false, $dateuntil=false) {
		if (!isset($this->total_record_count[$set_id])) {
			$co_set = new_connector_out_set_typed($set_id);
			$co_set->update_if_expired();
			$this->total_record_count[$set_id] = $co_set->get_value_count($datefrom, $dateuntil);
		}
		return $this->total_record_count[$set_id];
	}
}
/*
 * external_services_converter_oairecord
 * \brief Cette classe génère les enregistrement oai de notices complets et les met en cache 
 * 
 */
class external_services_converter_oairecord extends external_services_converter {
	private $set_life_duration;
	private $source_set_ids=array();
	private $repository_identifier="";
	private $deleted_record_statut=0;
	private $include_items=0;
	private $xslt = "";
	private $include_links=0;
	
	function external_services_converter_oairecord($object_type, $life_duration, $set_life_duration, $source_set_ids, $repository_identifier, $deleted_record_statut, $include_items,$xslt="",$include_links) {
		parent::external_services_converter($object_type, $life_duration);
		$this->set_life_duration = $set_life_duration+0;
		$this->source_set_ids = $source_set_ids;
		$this->repository_identifier = $repository_identifier;
		$this->deleted_record_statut = $deleted_record_statut;
		$this->include_items = $include_items;
		$this->xslt = $xslt;
		$this->include_links = $include_links;
	}
	
	function convert_batch($objects, $format, $target_charset='utf-8') {
		//Va chercher dans le cache les notices encore bonnes
		parent::convert_batch($objects, "oai_".$format, $target_charset);
		//Converti les notices qui doivent l'être
		$this->convert_uncachedoairecords($format, $target_charset);
		return $this->results;
	}
	
	function convert_batch_to_oairecords($notices_to_convert, $format, $target_charset) {
		global $dbh;
		if (!$notices_to_convert) //Rien à faire? On fait rien
			return;
		//Allons chercher les dates et les statuts des notices
		$notice_datestamps=array();
		$notice_statuts=array();
		$notice_ids = $notices_to_convert;
		//Par paquets de 100 pour ne pas brusquer mysql
		$notice_idsz = array_chunk($notice_ids, 100);
		$iso8601 = new iso8601("YYYY-MM-DDThh:mm:ssZ");
		foreach ($notice_idsz as $anotice_ids) {
			$sql = "SELECT notice_id, UNIX_TIMESTAMP(update_date) AS datestamp, statut FROM notices WHERE notice_id IN (".implode(",", $anotice_ids).")";
			$res = mysql_query($sql, $dbh);
			while($row=mysql_fetch_assoc($res)) {
				$notice_datestamps[$row["notice_id"]] = $iso8601->unixtime_to_iso8601($row["datestamp"]);
				$notice_statuts[$row["notice_id"]] = $row["statut"];
			}
		}
		//Si il existe un status correspondant à la suppression, on génère ces enregistrements et on les supprime de la liste à générer.
		if ($this->deleted_record_statut) {
			foreach ($notice_statuts as $notice_id => $anotice_statut)
				if ($anotice_statut == $this->deleted_record_statut) {
					$notice_sets = connector_out_set_noticecaddie::get_notice_setlist($notice_id);
					$notice_sets = array_intersect($notice_sets, $this->source_set_ids);
					$oai_record = "";
					$oai_record .= "";
					$oai_record .= '
									oai:'.XMLEntities($this->repository_identifier).':'.$notice_id.'
									'.$notice_datestamps[$notice_id].'';
					foreach ($notice_sets as $aset_id) {
						$oai_record .= "set_".$aset_id."";				
					}
					$oai_record .= '';
					$oai_record .= "";
					$this->results[$notice_id] = $oai_record;
					unset($notices_to_convert[array_search($notice_id, $notices_to_convert)]);
				}
		}
		
		//Convertissons les notices au format demandé si on ne souhaite pas uniquement les entêtes		
		$only_identifier = $format == "__oai_identifier";
		if (!$only_identifier) {
			$converter = new external_services_converter_notices(1, $this->set_life_duration);
			$converter->params["include_items"] = $this->include_items;
			$converter->params["include_links"] = $this->include_links;
			$metadatas = $converter->convert_batch($notices_to_convert, $format, $target_charset,$this->xslt);
		}
		
		//Fabriquons les enregistrements
		foreach ($notices_to_convert as $notice_id) {
			$notice_sets = connector_out_set_noticecaddie::get_notice_setlist($notice_id);
			$notice_sets = array_intersect($notice_sets, $this->source_set_ids);
			$oai_record = "";
			
			if (!$only_identifier)
				$oai_record .= "";
			$oai_record .= '
							oai:'.XMLEntities($this->repository_identifier).':'.$notice_id.'
							'.$notice_datestamps[$notice_id].'';
			foreach ($notice_sets as $aset_id) {
				$oai_record .= "set_".$aset_id."";				
			}
			$oai_record .= '';
			if (!$only_identifier) {
				$oai_record .= "";
				$oai_record .= $metadatas[$notice_id];
				$oai_record .= "";
			}
			if (!$only_identifier)
				$oai_record .= "";
			
			$this->results[$notice_id] = $oai_record;
		}
	}
	
	function convert_uncachedoairecords($format, $target_charset='utf-8') {
		$notices_to_convert=array();
		foreach ($this->results as $notice_id => $aresult) {
			if (!$aresult) {
				$notices_to_convert[] = $notice_id;
			}
		}
		$this->convert_batch_to_oairecords($notices_to_convert, $format, $target_charset);
		
		//Cachons les notices converties maintenant.
		foreach ($notices_to_convert as $anotice_id) {
			if ($this->results[$anotice_id])
				$this->encache_value($anotice_id, $this->results[$anotice_id], "oai_".$format);			
		}
	}
}
/*
 * oai_out_server
 * \brief Cette classe fait le lien entre toutes les autres et fait tourner le bouzin 
 * 
 */
class oai_out_server {
	private $msg=array();
	private $oai_source_object = NULL;
	private $sets=array();
	
	//Constructeur
	function oai_out_server(&$msg, &$oai_source_object) {
		$this->msg = $msg;
		$this->oai_source_object = $oai_source_object;
	}
	
	//Fait tourner le serveur
	function process() {
		global $verb;
		
		//Pour ne pas avoir les entêtes définissant le fichier comme du xml, placer un &nx dans l'url (pour pouvoir utiliser le debugger zend par exemple)
		global $nx;
		if (!isset($nx))
			header('Content-Type: text/xml');
		
		$outsets = new connector_out_sets();
		foreach ($outsets->sets as &$aset) {
			if (in_array($aset->id, $this->oai_source_object->included_sets))
				$this->sets[] = array(
					"id" => $aset->id,
					"caption" => $aset->caption
				);
		}
		//Créons l'object que le serveur va utiliser pour récupérer les enregistrements
		$get_records_objects = new oai_out_get_records_notice($this->msg,$this->oai_source_object->config['feuille_xslt']);
		$get_records_objects->oai_cache_duration = $this->oai_source_object->cache_complete_records_seconds;
		$get_records_objects->source_set_ids = $this->oai_source_object->included_sets;
		$get_records_objects->repository_identifier = $this->oai_source_object->repositoryIdentifier;
		$get_records_objects->notice_statut_deletion = $this->oai_source_object->link_status_to_deletion ? $this->oai_source_object->linked_status_to_deletion : 0;
		$get_records_objects->include_items = $this->oai_source_object->include_items ? $this->oai_source_object->include_items : 0;
		$get_records_objects->include_links = $this->oai_source_object->include_links ? $this->oai_source_object->include_links : 0;
		
		$additional_metadataformat = array();
		foreach ($this->oai_source_object->allowed_admin_convert_paths as $convert_path) {
			$additional_metadataformat["convert:".$convert_path] = array(
				"metadataPrefix" => "convert:".$convert_path,
				"metadataNamespace" => "http://sigb.net/pmb/es/oai/"."convert:".$convert_path,
				"schema" => "http://sigb.net/pmb/es/oai/unknown.xsd"
			);
		}
		
		//Créons l'objet protocol
		$deletion = ($this->oai_source_object->link_status_to_deletion ? 'transient' : 'no');
		$base_url = $this->oai_source_object->baseURL;
		if (!$base_url) {
			$base_url = curPageBaseURL();
			$base_url = substr($default_base_url, 0, strrpos($default_base_url, '/')+1);
			$base_url .= 'ws/connector_out.php?source_id='.$this->oai_source_object->id;
		}
		$oai_out_protocol = new oai_out_protocol($get_records_objects, $this->msg, $this->oai_source_object->repository_name, $this->oai_source_object->admin_email, $this->sets, $this->oai_source_object->repositoryIdentifier, $this->oai_source_object->chunksize, $this->oai_source_object->token_lifeduration, $this->oai_source_object->allow_gzip_compression, $deletion, $additional_metadataformat, $base_url);
		//Si on peut compresser, on compresse
		if ($this->oai_source_object->allow_gzip_compression)
			$test = ob_start("ob_gzhandler");
		$response = "";
		
		//Si la source n'est pas bien configurée
		if (!$this->oai_source_object->repository_name || !$this->oai_source_object->admin_email || !$this->oai_source_object->repositoryIdentifier) {
			echo $oai_out_protocol->oai_header();
			echo $oai_out_protocol->oai_error('unconfigured', $this->msg["unconfigured_source"]);
			echo $oai_out_protocol->oai_footer();
			return;
		}
		//Sinon c'est parti
		else {
			//on regarde si un des sets manipulés n'est en cours de rafraississement, si oui, on bloque tout et fait patienter le client
			if($oai_out_protocol->sets_being_refreshed()){
				header('HTTP/1.1 503 Service Temporarily Unavailable',true,503);
				header('Status: 503 Service Temporarily Unavailable');
				header('Retry-After: 10');
			}else{
				switch($verb) {
					case 'Identify':
						$response .= $oai_out_protocol->oai_identify();
						break;
					case 'ListRecords':
						$response .= $oai_out_protocol->oai_list_records();
						break;
					case 'GetRecord':
						$response .= $oai_out_protocol->oai_get_record();
						break;
					case 'ListSets':
						$response .= $oai_out_protocol->oai_list_sets();
						break;
					case 'ListIdentifiers':
						$response .= $oai_out_protocol->oai_list_identifier();
						break;
					case 'ListMetadataFormats':
						$response .= $oai_out_protocol->oai_list_metadata_formats();
						break;
					default:
						$response .= $oai_out_protocol->oai_error('badVerb', $this->msg["illegal_verb"]);
						break;
				}
			}
			//Header
			$response = $oai_out_protocol->oai_header() . $response;
	
			//Footer
			$response .= $oai_out_protocol->oai_footer();
	
			echo $response;
		}
	}
}
?>