/*
Copyright (C) 2000-2010  Ministere de la culture et de la communication (France), AJLSM
See LICENCE file
 */
package fr.gouv.culture.sdx.utils.logging;

import java.util.Date;
import java.util.Hashtable;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.Logger;

import fr.gouv.culture.sdx.exception.SDXException;
import fr.gouv.culture.sdx.exception.SDXExceptionCode;
import fr.gouv.culture.sdx.utils.AbstractSdxObject;
import fr.gouv.culture.sdx.utils.Utilities;

/**
 * Specific logger for indexation process.
 * <p>
 * This logger is specific to the indexation process. It manages all steps of
 * indexation and log those informations according the logger type (currently
 * a JDBC logger).
 * <p>
 * Messages are formated according the following pattern:<br/>
 * <code>indexation ID</code>;<code>document base id</code>;<code>number of documents to index</code>;
 * <code>start time</code>;<code>end time</code>;<code>number steps to proceed</code>;
 * <code>current step</code>;<code>current document rank</code>;<code>current document start time</code>;
 * <code>current document end time</code>;<code>current document ID</code>;
 * <code>current document attached number</code>;<code>current document sub-documents documents number</code>;
 * <code>current document attached rank</code>;<code>current document sub-document rank</code>
 * <br/>
 * Some informations may be null (eg, the current document may not have sub-documents).
 * <br/>
 * The default separator is a semi-colon "<code>;</code>". This can be modified (@see #setSeparator(String)).
 * <br/>
 * An ID is constructed for all indexation process according the pattern:
 * "<code>indexation start time</code>." Adding the document ID is not necessary ; to add this information
 * you just have to configure the target logger (eg, WEB-INF/logkit.xconf) to managed this granularity. By default, the granularity
 * of this indexation logger is: "<code>sdx.framework.indexation</code>".
 * 
 * @author mpichot
 *
 */
/*
	1) le nombre de documents à indexer
	2) le temps de départ
	3) le temps de fin
	4) infos sur le document en cours d'indexation :
	  a) son id
	  b) le nombre de sous-documents éventuels
	  c) le temps de départ
	  d) le temps de fin
	  e) les informations le pré-traitement d'indexation (donc à prendre depuis des classes Java mais aussi des XSL dans ces dernières, on peut appeler des méthodes statiques)
	formatage du message: {indeationID};{sdxdbid};{nbdocs};{start};{end};{steps};{step};{docrank};{doc-start};{doc-end};{docid};{nbattached};{nbsubdocs};{attachedrank};{subdocrank}
 */
public class LoggingIndexation extends AbstractSdxObject {

	public static final String CLASS_NAME_SUFFIX = "LoggingIndexation";

	/**The current logger*/
	public Logger logger;
	/**The logger of the super class to witch this logger is attached*/
	private Logger s_logger;
	/**The level of the current logger*/
	private int level;

	/**Indexation information*/
	/**Indexation ID*/
	protected String m_indexationID;
	/**Indexation start time*/
	protected long m_start;
	protected String m_startFormatedDate;
	/**Indexation end time*/
	protected long m_end;
	protected String m_endFormatedDate;
	/**Number of documents concerned by this indexation*/
	protected int m_nbdocs;
	/**Number of documents added*/
	protected int m_nbDocsAdded;
	/**Number of documents added*/
	protected int m_nbDocsError;
	/**The document base to index*/
	protected String m_dbid;
	/**The current document ID*/
	protected String m_doc_id;
	/**Number of sub-documents for the current document*/
	protected int m_doc_nbsubdocs;
	/**Number of attached documents for the current document*/
	protected int m_doc_nbattached;
	/**Current document indexation start time*/
	protected long m_doc_start;
	protected String m_doc_startFormatedDate;
	/**Current document indexation end time*/
	protected long m_doc_end;
	protected String m_doc_endFormatedDate;
	/**Current document rank*/
	protected int m_doc_rank;
	/**Current dub-document ID*/
	protected String m_doc_subdocid;
	/**Current sub-document rank*/
	protected int m_doc_subdoc_rank;
	/**Current attached document rank*/
	protected int m_doc_attached_rank;
	/**Number of steps*/
	protected int m_steps;
	/**Current step*/
	protected int m_step;
	/**Documents added list*/
	protected Hashtable m_docsadded;
	/**Documents error list*/
	protected Hashtable m_docserror;
	/**Documents error messages*/
	protected Hashtable m_docserror_msg;
	/**Documents informations*/
	protected Hashtable m_docs_infos;
	/**Current document information
	 * <p>Current document information such as: <li>ID</li><li>start</li><li>end</li><li>number of sub-documents</li><li>number of attached documents</li>*/
	protected Hashtable m_doc_infos;

	/**The separator used to format messages*/
	public String m_separator;
	/**Default separator*/
	public static final String DEFAULT_SEPARATOR = ";";

	/**The format of date as a string*/
	protected String m_dateFormat;
	/**Default date format*/
	public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.S z";

	/**The limit to output informations of each document*/
	public static int docMoreInfosOutput = 500;
	
	/**Indexation steps*/
	/**Indexation start*/
	public static final int STEP_INDEXATION_INIT = 1;
	/**Document indexation start*/
	public static final int STEP_DOCUMENT_INDEXATION_START = 111;
	/**Transforming of the document to index*/
	public static final int STEP_DOCUMENT_TRANSFORMATION = 1111;
	/**Start time for the transformation of the document to index*/
	public static final int STEP_DOCUMENT_TRANSFORMATION_START = 11111;
	/**End time for the transformation of the document to index*/
	public static final int STEP_DOCUMENT_TRANSFORMATION_END = 111111;
	/**Adding the document*/
	public static final int STEP_DOCUMENT_ADD = 112;
	/**Setting the ID of the document to index*/
	public static final int STEP_DOCUMENT_ADD_SET_ID = 1121;
	/**Adding the original document if needed*/
	public static final int STEP_DOCUMENT_ADD_STORE_ORIGINAL_DOCUMENT = 1122;
	/**Start time for attached documents process*/
	public static final int STEP_DOCUMENT_ADD_ATTACHED_START = 1123;
	/**Adding the current attached document*/
	public static final int STEP_DOCUMENT_ADD_ATTACHED_ADD = 11231;
	/**End time for attached documents process*/
	public static final int STEP_DOCUMENT_ADD_ATTACHED_END = 11232;
	/**Start time for sub-documents process*/
	public static final int STEP_DOCUMENT_ADD_SUBDOCUMENTS_START = 1124;
	/**Adding the current sub-document*/
	public static final int STEP_DOCUMENT_ADD_SUBDOCUMENTS_ADD = 11241;
	/**End time for sub-documents process*/
	public static final int STEP_DOCUMENT_ADD_SUBDOCUMENTS_END = 11242;
	/**Adding the current document to the search index*/
	public static final int STEP_DOCUMENT_ADD_TO_SEARCH_INDEX = 1125;
	/**Updating the OAI repository for the current document*/
	public static final int STEP_DOCUMENT_ADD_OAI_DELETED_RECORD = 1126;
	/**Adding the current document to the documents repository*/
	public static final int STEP_DOCUMENT_ADD_TO_REPOSITORY = 1127;
	/**Updating the internal database for the current document*/
	public static final int STEP_DOCUMENT_ADD_UPDATE_METADATA = 1128;
	/**Document indexation end*/
	public static final int STEP_DOCUMENT_INDEXATION_END = 113;
	/**Merging the batch indexes if needed*/
	public static final int STEP_MERGE_BATCH_INDEX = 12;
	/**Optimizing the document base if needed*/
	public static final int STEP_OPTIMIZE_DOCUMENT_BASE = 13;
	/**Indexation end*/
	public static final int STEP_INDEXATION_END = 2;
	
	/**Indexation start*/
	public static final String STEP_INDEXATION_INIT_STRING = "INDEXATION_INIT";
	/**Document indexation start*/
	public static final String STEP_DOCUMENT_INDEXATION_START_STRING = "DOCUMENT_INDEXATION_START";
	/**Transforming of the document to index*/
	public static final String STEP_DOCUMENT_TRANSFORMATION_STRING = "DOCUMENT_TRANSFORMATION";
	/**Start time for the transformation of the document to index*/
	public static final String STEP_DOCUMENT_TRANSFORMATION_START_STRING = "DOCUMENT_TRANSFORMATION_START";
	/**End time for the transformation of the document to index*/
	public static final String STEP_DOCUMENT_TRANSFORMATION_END_STRING = "DOCUMENT_TRANSFORMATION_END";
	/**Adding the document*/
	public static final String STEP_DOCUMENT_ADD_STRING = "DOCUMENT_ADD";
	/**Setting the ID of the document to index*/
	public static final String STEP_DOCUMENT_ADD_SET_ID_STRING = "DOCUMENT_ADD_SET_ID";
	/**Adding the original document if needed*/
	public static final String STEP_DOCUMENT_ADD_STORE_ORIGINAL_DOCUMENT_STRING = "DOCUMENT_ADD_STORE_ORIGINAL_DOCUMENT";
	/**Start time for attached documents process*/
	public static final String STEP_DOCUMENT_ADD_ATTACHED_START_STRING = "DOCUMENT_ADD_ATTACHED_START";
	/**Adding the current attached document*/
	public static final String STEP_DOCUMENT_ADD_ATTACHED_ADD_STRING = "DOCUMENT_ADD_ATTACHED_ADD";
	/**End time for attached documents process*/
	public static final String STEP_DOCUMENT_ADD_ATTACHED_END_STRING = "DOCUMENT_ADD_ATTACHED_END";
	/**Start time for sub-documents process*/
	public static final String STEP_DOCUMENT_ADD_SUBDOCUMENTS_START_STRING = "DOCUMENT_ADD_SUBDOCUMENTS_START";
	/**Adding the current sub-document*/
	public static final String STEP_DOCUMENT_ADD_SUBDOCUMENTS_ADD_STRING = "DOCUMENT_ADD_SUBDOCUMENTS_ADD";
	/**End time for sub-documents process*/
	public static final String STEP_DOCUMENT_ADD_SUBDOCUMENTS_END_STRING = "DOCUMENT_ADD_SUBDOCUMENTS_END";
	/**Adding the current document to the search index*/
	public static final String STEP_DOCUMENT_ADD_TO_SEARCH_INDEX_STRING = "DOCUMENT_ADD_TO_SEARCH_INDEX";
	/**Updating the OAI repository for the current document*/
	public static final String STEP_DOCUMENT_ADD_OAI_DELETED_RECORD_STRING = "DOCUMENT_ADD_OAI_DELETED_RECORD";
	/**Adding the current document to the documents repository*/
	public static final String STEP_DOCUMENT_ADD_TO_REPOSITORY_STRING = "DOCUMENT_ADD_TO_REPOSITORY";
	/**Updating the internal database for the current document*/
	public static final String STEP_DOCUMENT_ADD_UPDATE_METADATA_STRING = "DOCUMENT_ADD_UPDATE_METADATA";
	/**Document indexation end*/
	public static final String STEP_DOCUMENT_INDEXATION_END_STRING = "DOCUMENT_INDEXATION_END";
	/**Merging the batch indexes if needed*/
	public static final String STEP_MERGE_BATCH_INDEX_STRING = "MERGE_BATCH_INDEX";
	/**Optimizing the document base if needed*/
	public static final String STEP_OPTIMIZE_DOCUMENT_BASE_STRING = "OPTIMIZE_DOCUMENT_BASE";
	/**Indexation end*/
	public static final String STEP_INDEXATION_END_STRING = "INDEXATION_END";

	/**Current logger level*/
	public static final int LEVEL_DEBUG = 10000;
	public static final int LEVEL_INFO = 1000;
	public static final int LEVEL_WARN = 100;
	public static final int LEVEL_ERROR = 10;
	public static final int LEVEL_FATAL = 1;
	public static final int LEVEL_OFF = 0;
	/**String representation of the current logger level*/
	public static final String LEVEL_DEBUG_STRING = "debug";
	public static final String LEVEL_ERROR_STRING = "error";
	public static final String LEVEL_INFO_STRING = "info";
	public static final String LEVEL_WARN_STRING = "warn";
	public static final String LEVEL_FATAL_STRING = "fatal_error";
	public static final String LEVEL_OFF_STRING = "off";

	public LoggingIndexation() {
		/*nothing here*/;
	}

	public void configure( Configuration conf, String dbid, long start, int nbdocs, String indexationID, String separator ) 
	throws ConfigurationException {

		try {

			if (!Utilities.checkString(dbid)) {
				String[] args = new String[1];
				args[0] = conf.getLocation();
				throw new SDXException(s_logger,SDXExceptionCode.ERROR_CONFIGURE_INDEXATION_LOGGER,args, null);
			}

			super.configure(conf);

			// Settings the essentials informations
			m_dbid = dbid; // document base ID
			m_start = (start!=-1) ? start : System.currentTimeMillis(); // indexation start time
			m_nbdocs = (nbdocs >= 0) ? nbdocs : 0; // number of documents concerned by this indexation
			m_nbDocsAdded = 0;
			m_nbDocsError = 0;
			m_indexationID = ( Utilities.checkString(indexationID) ) ? indexationID : start+""; // indexation ID
			m_separator = ( Utilities.checkString(separator) ) ? separator : DEFAULT_SEPARATOR; // the separator used for formating the logs
			m_dateFormat = DEFAULT_DATE_FORMAT;
			m_step = STEP_INDEXATION_INIT;
			//m_steps = setSteps();
			m_docsadded = new Hashtable(m_nbdocs);
			m_docserror = new Hashtable();
			m_docserror_msg = new Hashtable();
			m_docs_infos = new Hashtable(m_nbdocs);
			m_doc_infos = initDocInfos();

			m_startFormatedDate = fr.gouv.culture.sdx.utils.Date.formatDate( new Date(start), m_dateFormat ); 

			try {
				configureLogger();
			} catch(Exception e) {
				/*nothing here*/;
			}
		} catch (SDXException sdxe) {
			throw new ConfigurationException(sdxe.getMessage(), sdxe.fillInStackTrace());
		} catch (ConfigurationException ce) {
			String[] args = new String[1];
			args[0] = conf.getLocation();
			args[0] = ce.getMessage();
			SDXException sdxe = new SDXException(s_logger,SDXExceptionCode.ERROR_CONFIGURE_INDEXATION_LOGGER,args, ce);
			throw new ConfigurationException(sdxe.getMessage(), sdxe.fillInStackTrace());
		} finally{
			conf=null; dbid=null; start=-1; nbdocs=-1; indexationID=null; separator=null;
		}

	}

	private Hashtable initDocInfos() {
		Hashtable m_hash = new Hashtable(6);
		m_hash.put("id","");
		m_hash.put("rank","");
		m_hash.put("start","");
		m_hash.put("end","");
		m_hash.put("nbsubdocs","");
		m_hash.put("nbattached","");
		return m_hash;
	}
	
	public void setSteps() {
		// TODO (MP): definir le nombre d'etapes suivant la verbosite du logger
		this.m_steps = 2;
	}

	public void configureLogger() {

		s_logger = super.getLog();

		if (s_logger==null) return;

		// Getting the logger
		String logid = "indexation";
		if (Utilities.checkString(m_dbid) && m_dbid.indexOf("..") == -1)//avoiding empty category for logger name ".."
			logid += "."+m_dbid;
		logger = s_logger.getChildLogger(logid);

		// Setting the level of the current logger
		if (logger.isDebugEnabled()) {
			level = LEVEL_DEBUG;
		}
		else if (logger.isErrorEnabled()) {
			level = LEVEL_ERROR;
		}
		else if (logger.isInfoEnabled()) {
			level = LEVEL_INFO;
		}
		else if (logger.isWarnEnabled()) {
			level = LEVEL_WARN;
		}
		else if (logger.isFatalErrorEnabled()) {
			level = LEVEL_FATAL;
		}
		else
			level = LEVEL_OFF;

		if (s_logger.isDebugEnabled()) LoggingUtils.logDebug(s_logger, "Configuration of the indexation logger "+logid+" at level "+getLevelString()+" for the document base "+_id);
		logid = null;
	}

	public String log() {

		if (logger==null) {
			configureLogger();
		}

		if (m_step <= level) {
			String msg = formatMessage();
			logInfo(msg);
			return msg;
		}
		else 
			return null;
	}
	public void logInfo(String message) {
		if (logger==null) {
			configureLogger();
		}
		if (logger!=null 
				&& Utilities.checkString(message) 
				&& m_step <= level ) // l'etape que l'on veut logguer doit correspondre au niveau de verbosite 
		{
			logger.fatalError(message);// Pas terrible mais au moins on sait que ca passera tout le temps
		}
	}

	/*
	 * formatage du message: {indeationID};{sdxdbid};{nbdocs};{start};{end};{steps};{step};{docrank};{doc-start};{doc-end};{docid};{nbattached};{nbsubdocs};{attachedrank};{subdocrank}
	 */
	public String formatMessage() {
		String msg =  m_indexationID + m_separator // indexation ID
		+ ( (Utilities.checkString(m_dbid)) ? m_dbid : "" ) + m_separator // sdxdbid
		+ ( (m_nbdocs > 0) ? m_nbdocs+"" : "") + m_separator // nbdocs
		+ ( (Utilities.checkString(m_startFormatedDate)) ? m_startFormatedDate : "" ) + m_separator // start
		+ ( (Utilities.checkString(m_endFormatedDate)) ? m_endFormatedDate : "" ) + m_separator // end
		+ getStepString() + m_separator // steps
		+ ( (m_step > 0) ? m_step+"" : "") + m_separator // current step
		+ ( (m_doc_rank > 0) ? m_doc_rank+"" : "") + m_separator // current doc rank
		+ ( (Utilities.checkString(m_doc_startFormatedDate)) ? m_doc_startFormatedDate : "" ) + m_separator // current document start
		+ ( (Utilities.checkString(m_doc_endFormatedDate)) ? m_doc_endFormatedDate : "" ) + m_separator // current document end
		+ ( (Utilities.checkString(m_doc_id)) ? m_doc_id : "" ) + m_separator // current doc id
		+ ( (m_doc_nbattached > 0) ? m_doc_nbattached+"" : "") + m_separator // current doc nbattached
		+ ( (m_doc_nbsubdocs > 0) ? m_doc_nbsubdocs+"" : "") + m_separator // current doc sbsubdocs
		+ ( (m_doc_attached_rank > 0) ? m_doc_attached_rank+"" : "") + m_separator // current attached rank
		+ ( (m_doc_subdoc_rank > 0) ? m_doc_subdoc_rank+"" : "") // current subdoc rank
		;
		return msg;
	}
	
	/**
	 * Logs all documents IDs (added documents and error documents).
	 * <p>
	 * The log is formated as below:
	 * <br/>
	 * <code>{Indexation ID};{sdxdbid};{nb docs to index};{start time};{end time};ADDED_ERROR_DOCS_ID;{docs added IDs list};{docs error IDs list}</code>
	 */
	public void logAddedAndErrorDocs() {
		String msg =  m_indexationID + m_separator // indexation ID
		+ ( (Utilities.checkString(m_dbid)) ? m_dbid : "" ) + m_separator // sdxdbid
		+ ( (m_nbdocs > 0) ? m_nbdocs+"" : "") + m_separator // nbdocs
		+ ( (Utilities.checkString(m_startFormatedDate)) ? m_startFormatedDate : "" ) + m_separator // start
		+ ( (Utilities.checkString(m_endFormatedDate)) ? m_endFormatedDate : "" ) + m_separator // end
		+ "DOCS_IDS" + m_separator
		+ m_nbDocsAdded + m_separator
		+ m_nbDocsError + m_separator
		+ m_docsadded.toString() + m_separator
		+ m_docserror.toString();
		logInfo(msg);
	}
	
	/**
	 * Logs all error messages.
	 * <p>
	 * The log is formated as below:
	 * <br/>
	 * <code>{Indexation ID};{sdxdbid};{nb docs to index};{start time};{end time};ERROR_MESSAGES;{error messages list}</code>
	 */
	public void logErrorsMessages() {
		String msg =  m_indexationID + m_separator // indexation ID
		+ ( (Utilities.checkString(m_dbid)) ? m_dbid : "" ) + m_separator // sdxdbid
		+ ( (m_nbdocs > 0) ? m_nbdocs+"" : "") + m_separator // nbdocs
		+ ( (Utilities.checkString(m_startFormatedDate)) ? m_startFormatedDate : "" ) + m_separator // start
		+ ( (Utilities.checkString(m_endFormatedDate)) ? m_endFormatedDate : "" ) + m_separator // end
		+ "ERROR_MESSAGES" + m_separator
		+ m_docserror_msg.toString();
		logInfo(msg);
	}

	public void setSeparator(String s) {
		if (Utilities.checkString(s)) {
			m_separator = s;
		}
	}

	public String getSeparator() {
		return m_separator;
	}

	public void setDateFormat(String s) {
		if (Utilities.checkString(s)) {
			m_dateFormat = s;
		}
	}

	public String getDateFormat() {
		return m_dateFormat;
	}

	public void setStep(int currentStep){
		m_step = currentStep;
		log();
	}
	public int getCurrentStep(){
		return m_step;
	}

	public void setStart(long indexationStart) {
		m_start = indexationStart;
		m_startFormatedDate = fr.gouv.culture.sdx.utils.Date.formatDate( new Date(m_start), m_dateFormat );
		setStep(STEP_INDEXATION_INIT);
	}
	public long getStart() {
		return m_start;
	}

	public void setEnd(long indexationEnd) {
		m_end = indexationEnd;
		m_endFormatedDate = fr.gouv.culture.sdx.utils.Date.formatDate( new Date(m_end), m_dateFormat );
		// ending current doc info
		m_doc_end = -1; 
		m_doc_id = null;
		m_doc_attached_rank = -1;
		m_doc_subdoc_rank = -1;
		setStep(STEP_INDEXATION_END);
		// log documents IDs
		logAddedAndErrorDocs();
		// log errors messages
		logErrorsMessages();
	}
	public long getEnd() {
		return m_end;
	}

	public void setDocID(String docID) {
		m_doc_id = docID;
		m_doc_infos.put("id",docID);
		addAddedDoc(m_doc_rank, m_doc_id);
		setStep(STEP_DOCUMENT_ADD_SET_ID);
	}
	public String getDocID() {
		return m_doc_id;
	}

	public void setDocRank(int docRank) {
		m_doc_rank = docRank;
		m_doc_infos = initDocInfos();
		m_doc_infos.put("rank", m_doc_rank+"");
		setDocStart(System.currentTimeMillis());
		setStep(STEP_DOCUMENT_INDEXATION_START);
	}
	public int getDocRank() {
		return m_doc_rank;
	}
	
	public void addErrorDoc(int rank, String docid) {
		addErrorDoc(rank, docid, null, null);
	}
	public void addErrorDoc(int rank, String docid, String message, Exception e) {
		m_nbDocsError++;
		// ajout de l'id dans la liste des documents avec erreur
		m_docserror.put( rank+"", docid );
		m_doc_infos = null;
		// ajout du message d'erreur
		m_docserror_msg.put( 
				( Utilities.checkString(docid) ) ? docid : rank+"", 
				( Utilities.checkString(message) ) ? message : e.getLocalizedMessage() );
		setStep(STEP_DOCUMENT_INDEXATION_END);
	}
	public Hashtable getErrorDocs() {
		return m_docserror;
	}
	
	public void addAddedDoc(int rank, String docid) {
		m_docsadded.put(rank+"", docid);
		m_nbDocsAdded++;
	}
	public Hashtable getAddedDocs() {
		return m_docsadded;
	}

	public static int getDocMoreInfosOutput() {
		return docMoreInfosOutput;
	}

	public static void setDocMoreInfosOutput(int docMoreInfosOutput) {
		LoggingIndexation.docMoreInfosOutput = docMoreInfosOutput;
	}
	
	public void setDocStart(long docStart) {
		m_doc_start = docStart;
		m_doc_startFormatedDate = fr.gouv.culture.sdx.utils.Date.formatDate( new Date(m_doc_start), m_dateFormat );
		m_doc_infos.put("start",m_doc_startFormatedDate);
		m_doc_end = -1; 
		m_doc_id = null;
		m_doc_attached_rank = -1;
		m_doc_subdoc_rank = -1;
	}
	public int getDocStart() {
		return m_doc_rank;
	}

	public void setDocEnd(long docEnd) {
		m_doc_end = docEnd;
		m_doc_endFormatedDate = fr.gouv.culture.sdx.utils.Date.formatDate( new Date(m_doc_end), m_dateFormat );
		if (m_doc_infos!=null) {
			m_doc_infos.put("end",m_doc_endFormatedDate);
			m_docs_infos.put(m_doc_rank+"",m_doc_infos);
		}
	}
	public long getDocEnd() {
		return m_doc_end;
	}

	public void setDocNbSubdocs(int nbsubdocs) {
		m_doc_nbsubdocs = nbsubdocs;
		m_doc_infos.put("nbsubdocs", nbsubdocs+"");
	}
	public int getDocNbSubdocs() {
		return m_doc_nbsubdocs;
	}
	public void setDocNbAttached(int nbattached) {
		m_doc_nbattached = nbattached;
		m_doc_infos.put("nbattached", nbattached+"");
		setStep(STEP_DOCUMENT_ADD_ATTACHED_ADD);
	}
	public int getDocNbAttached() {
		return m_doc_nbattached;
	}

	public void setDocSubdocRank(int subdocRank) {
		m_doc_subdoc_rank = subdocRank;
	}
	public int getDocSubdocRank() {
		return m_doc_subdoc_rank;
	}

	public void setDocAttachedRank(int attachedRank) {
		m_doc_attached_rank = attachedRank;
		setStep(STEP_DOCUMENT_ADD_ATTACHED_ADD);
	}
	public int getDocAttachedRank() {
		return m_doc_attached_rank;
	}

	public int getLevel() {
		return level;		
	}

	public String getLevelString() {
		String ret = null;
		switch (level) {
		case LEVEL_DEBUG:
			ret = LEVEL_DEBUG_STRING;
			break;
		case LEVEL_INFO:
			ret = LEVEL_INFO_STRING;
			break;
		case LEVEL_ERROR:
			ret = LEVEL_ERROR_STRING;
			break;
		case LEVEL_WARN:
			ret = LEVEL_WARN_STRING;
			break;
		case LEVEL_FATAL:
			ret = LEVEL_FATAL_STRING;
			break;
		default:
			ret = LEVEL_OFF_STRING;
			break;
		}
		return ret;
	}
	public String getStepString() {
		String ret = null;
		switch (m_step) {
		case STEP_INDEXATION_INIT:
			ret = STEP_INDEXATION_INIT_STRING;
			break;
		case STEP_INDEXATION_END:
			ret = STEP_INDEXATION_END_STRING;
			break;
		case STEP_OPTIMIZE_DOCUMENT_BASE:
			ret = STEP_OPTIMIZE_DOCUMENT_BASE_STRING;
			break;
		case STEP_MERGE_BATCH_INDEX:
			ret = STEP_MERGE_BATCH_INDEX_STRING;
			break;
		case STEP_DOCUMENT_INDEXATION_START:
			ret = STEP_DOCUMENT_INDEXATION_START_STRING;
			break;
		case STEP_DOCUMENT_INDEXATION_END:
			ret = STEP_DOCUMENT_INDEXATION_END_STRING;
			break;
		case STEP_DOCUMENT_TRANSFORMATION_START:
			ret = STEP_DOCUMENT_TRANSFORMATION_START_STRING;
			break;
		case STEP_DOCUMENT_TRANSFORMATION_END:
			ret = STEP_DOCUMENT_TRANSFORMATION_END_STRING;
			break;
		case STEP_DOCUMENT_ADD:
			ret = STEP_DOCUMENT_ADD_STRING;
			break;
		case STEP_DOCUMENT_ADD_SET_ID:
			ret = STEP_DOCUMENT_ADD_SET_ID_STRING;
			break;
		case STEP_DOCUMENT_ADD_TO_REPOSITORY:
			ret = STEP_DOCUMENT_ADD_TO_REPOSITORY_STRING;
			break;
		case STEP_DOCUMENT_ADD_TO_SEARCH_INDEX:
			ret = STEP_DOCUMENT_ADD_TO_SEARCH_INDEX_STRING;
			break;
		case STEP_DOCUMENT_ADD_OAI_DELETED_RECORD:
			ret = STEP_DOCUMENT_ADD_OAI_DELETED_RECORD_STRING;
			break;
		case STEP_DOCUMENT_ADD_UPDATE_METADATA:
			ret = STEP_DOCUMENT_ADD_UPDATE_METADATA_STRING;
			break;
		case STEP_DOCUMENT_ADD_STORE_ORIGINAL_DOCUMENT:
			ret = STEP_DOCUMENT_ADD_STORE_ORIGINAL_DOCUMENT_STRING;
			break;
		case STEP_DOCUMENT_ADD_ATTACHED_START:
			ret = STEP_DOCUMENT_ADD_ATTACHED_START_STRING;
			break;
		case STEP_DOCUMENT_ADD_ATTACHED_ADD:
			ret = STEP_DOCUMENT_ADD_ATTACHED_ADD_STRING;
			break;
		case STEP_DOCUMENT_ADD_ATTACHED_END:
			ret = STEP_DOCUMENT_ADD_ATTACHED_END_STRING;
			break;
		case STEP_DOCUMENT_ADD_SUBDOCUMENTS_START:
			ret = STEP_DOCUMENT_ADD_SUBDOCUMENTS_START_STRING;
			break;
		case STEP_DOCUMENT_ADD_SUBDOCUMENTS_END:
			ret = STEP_DOCUMENT_ADD_SUBDOCUMENTS_END_STRING;
			break;
		case STEP_DOCUMENT_ADD_SUBDOCUMENTS_ADD:
			ret = STEP_DOCUMENT_ADD_SUBDOCUMENTS_ADD_STRING;
			break;
		default:
			ret = m_step+"";
			break;
		}
		return ret;
	}

	protected String getClassNameSuffix() {
		return LoggingIndexation.CLASS_NAME_SUFFIX;
	}
	
	protected boolean initToSax() {
		getXMLInformation();
		return true;
	}
	
	protected void initVolatileObjectsToSax() {
		getXMLInformation();
	}

	public void getXMLInformation() {
		String docid, msg; StringBuffer sb;
		//	formatage du message: {indeationID};{sdxdbid};{nbdocs};{start};{end};{steps};{step};{docrank};{doc-start};{doc-end};{docid};{nbattached};{nbsubdocs};{attachedrank};{subdocrank}
		this._xmlizable_objects.put("IndexationID",String.valueOf(this.m_indexationID));
		this._xmlizable_objects.put("sdxdbid",String.valueOf(this.m_dbid));
		this._xmlizable_objects.put("steps",String.valueOf(this.m_steps));
		this._xmlizable_objects.put("step",String.valueOf(getStepString()));
		this._xmlizable_objects.put("nb-docs-to-index",String.valueOf(this.m_nbdocs));
		this._xmlizable_objects.put("nb-docs-added",String.valueOf(this.m_nbDocsAdded));
		this._xmlizable_objects.put("nb-docs-error",String.valueOf(this.m_nbDocsError));
		this._xmlizable_objects.put("doc-rank",String.valueOf(this.m_doc_rank));
		this._xmlizable_objects.put("start",String.valueOf(this.m_startFormatedDate));
		this._xmlizable_objects.put("end",String.valueOf(this.m_endFormatedDate));
		// added docs id ({rank};{docid})
		this._xmlizable_objects.put("added-docs",String.valueOf(this.m_docsadded));
		if ( this.m_docsadded!=null && !this.m_docsadded.isEmpty() ) {
			sb = new StringBuffer(this.m_docsadded.size());
			for ( java.util.Enumeration e = m_docsadded.keys(); e.hasMoreElements(); ) {
				docid = (String) e.nextElement();
				if (sb.length()!=0) sb.append(m_separator);
				sb.append( docid + "=" + (String) m_docsadded.get(docid) );
			}
			this._xmlizable_objects.put("added-docs", sb.toString());
			sb = null; docid = null;
		}
		// error docs id ({rank};{docid})
		this._xmlizable_objects.put("error-docs",String.valueOf(this.m_docserror));
		if ( this.m_docserror!=null && !this.m_docserror.isEmpty() ) {
			sb = new StringBuffer(this.m_docserror.size());
			for ( java.util.Enumeration e = m_docserror.keys(); e.hasMoreElements(); ) {
				docid = (String) e.nextElement();
				msg = (String) m_docserror.get(docid);
				if (sb.length()!=0) sb.append(m_separator);
				sb.append( docid + ( (Utilities.checkString(msg)) ?  "="+msg : "" ) );
			}
			this._xmlizable_objects.put("error-docs", sb.toString());
			sb = null; msg = null; docid = null;
		}
		this._xmlizable_objects.put("doc-start",String.valueOf(this.m_doc_startFormatedDate));
		this._xmlizable_objects.put("doc-end",String.valueOf(this.m_doc_endFormatedDate));
		this._xmlizable_objects.put("doc-id",String.valueOf(this.m_doc_id));
		this._xmlizable_objects.put("doc-nbattached",String.valueOf(this.m_doc_nbattached));
		this._xmlizable_objects.put("doc-nbsubocs",String.valueOf(this.m_doc_nbsubdocs));
		this._xmlizable_objects.put("doc-attached_rank",String.valueOf(this.m_doc_attached_rank));
		this._xmlizable_objects.put("doc-subdoc_rank",String.valueOf(this.m_doc_subdoc_rank));
		// docs more infos
		if ( this.m_nbdocs < docMoreInfosOutput && this.m_docs_infos!=null && !this.m_docs_infos.isEmpty() ) {
			for (java.util.Enumeration e = m_docs_infos.keys(); e.hasMoreElements();) {
				docid = (String) e.nextElement();
				this._xmlizable_objects.put("doc-more-infos-"+docid, m_docs_infos.get(docid).toString());
			}
			docid = null;
		} else if (this.m_nbdocs >= docMoreInfosOutput) {
			this._xmlizable_objects.put("message","DOC_MORE_INFOS_OUTPUT");
		}
		// error messages
		if ( this.m_docserror_msg!=null && !this.m_docserror_msg.isEmpty() ) {
			for (java.util.Enumeration e = m_docserror_msg.keys(); e.hasMoreElements();) {
				docid = (String) e.nextElement();
				msg = (String) m_docserror_msg.get(docid);
				if (Utilities.checkString(docid) && Utilities.checkString(msg)) {
					this._xmlizable_objects.put("doc-error-info-"+docid,  ( (Utilities.checkString(docid)) ? docid+"="+msg : msg ) );
				}
				docid = null; msg = null;
			}
		}
		docid = null; msg = null; sb = null;
	}

}
