/*
 * Créé le 5 juin 07
 *
 * Pour changer le modèle de ce fichier généré, allez à :
 * Fenêtre&gt;Préférences&gt;Java&gt;Génération de code&gt;Code et commentaires
 */
package fr.gouv.finances.cp.xemelios.common.config;

import java.lang.reflect.Constructor;
import java.util.HashMap;

import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import fr.gouv.finances.cp.utils.xml.marshal.NoeudModifiable;
import fr.gouv.finances.cp.utils.xml.marshal.XmlAttributes;
import javax.xml.namespace.QName;

/**
 * @deprecated
 * @author nicolas.lecorre
 */
public class DocumentsDeriveParser extends DefaultHandler {
	private static Logger logger = Logger.getLogger(DocumentsDeriveParser.class);
	
	NoeudModifiable current, oldCurrent = null;
	boolean inConstruction = false;
	String closeConstructionOn=null;
	String baseDirectory;
	private HashMap<QName, Class> mapping ;
	
	// la liste des configuration déjà lues et dont on peut dériver
	private DocumentsModel dmsReference = null;
	
	// le DocumentModel que l'on enrichi
	private DocumentModel dmEnrichi = null;
	
	public DocumentModel getDmEnrichi() {
		return dmEnrichi;
	}

	public DocumentsDeriveParser (DocumentsModel dm, String baseDir) {
		dmsReference = dm;
		baseDirectory=baseDir;
                mapping = new DocumentsMapping();
	}

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		/**
		 * Si on lit un début de balise documents-derives, on l'ignore
		 */
		if ("documents-derives".equals(localName)) return;
		
		/**
		 * Si on lit un début de balise document, il faut aller chercher la configuration dont on dérive via l'attribut "extends"
		 */
		if ("document".equals(localName)) {
			if (dmsReference == null || dmsReference.getDocuments().size()==0) throw new SAXException ("Aucun document n'est disponible pour héritage.");
            String extendsId = attributes.getValue("extends");
            DocumentModel dmEtendu = dmsReference.getDocumentById(extendsId);
            if(dmEtendu==null) throw new SAXException("Configuration de "+extendsId+" introuvable");
			dmEnrichi = dmEtendu.clone();
			// on le prends comme point de départ.
			current = dmEnrichi;
			// on mets à jour 
			current.modifyAttrs(attributes);
			dmEnrichi.setBaseDirectory(baseDirectory);
			dmEnrichi.setExtendedDocId(extendsId);
			/**
			 * ATTENTION
			 * Si la configuration dont on dérive est une configuration dérivée, il se peut qu'elle ne soit pas encore chargée.
			 * La dérivation de plusieurs niveaux n'est pas prise en charge...
			 */
			
			
		/**
		 * Sinon on tente d'enrichir le modèle trouvé
		 */	
		} else {
			
			/**
			 * On récupère dans la configuration dont on dérive, le noeud qui nous intéresse, c'est à dire le noeud qui doit être
			 * modifié par la nouvelle configuration 
			 */
			
			NoeudModifiable child = null;
			// la clef du fils cherché.
			// Elle est soit simplement la valeur d'un attribut,
			// soit la concaténation de plusieurs
			String clef = "";
			Object ob = current.getChildIdAttrName(localName);
			if (ob!=null) {
				String[] clefs = (String[])ob;
				for (String c:clefs) {
					clef += attributes.getValue(c)+"|";
				}
				if (clef.endsWith("|")) clef = clef.substring(0, clef.length()-1);
			}
			child = current.getChildAsNoeudModifiable(localName,clef);
						
			/**
			 * Si ce noeud n'existe pas, il s'agit alors d'un noeud à créer
			 * Si on est en "construction", cela veux dire que l'on a commencé à créer un nouveau fils qui a lui même des fils. 
			 * On se trouve par exemple à traiter une valeur d'un nouveau champs :
			 * 	<champ id="lr8" datatype="string" libelle="Montant Cumul annuel" affichable="true" exportable="true" identifiant="false">
	         *  	<valeur>BlocBordereau/MtCumulAnnuel/@V</valeur>
	         *  </champ>
			 * 
			 */
			if(child==null || inConstruction) {
				try {
					Class[] paramTypes = new Class[1]; paramTypes[0] = String.class;
					Class clazz = mapping.get (localName);
					Constructor ctr = clazz.getConstructor(paramTypes);
					Object[] params = new Object[1]; params[0] = localName;
					NoeudModifiable nouveau = (NoeudModifiable)ctr.newInstance(params);
					nouveau.getAttributes(new XmlAttributes(attributes));
					//current.addChild(nouveau, localName);
					current=nouveau;
					closeConstructionOn=localName;
					inConstruction = true;
				} catch (Exception e) {
					logger.error ("Erreur lors de la création du noeud ("+localName+") : ", e);
					throw new SAXException(e);
				}
				
			/**
			 * Sinon, on modifie simplement les attributs du noeud avec ceux éventuellement redéfinis et on se repositionne pour la suite
			 */
			} else {
				current = child;
				current.modifyAttrs(attributes);
			}
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		/**
		 * Si on lit une fin de balise documents-derives, on l'ignore
		 */
		if ("documents-derives".equals(localName)) return;
		
		/**
		 * Si l'on a une fin de document, alors on a fini d'enrichir dmEnrichi. Il faut l'ajouter à la liste des docs
		 */
		if ("document".equals(localName)) {
			dmsReference.addChild(dmEnrichi, DocumentModel.QN);
		} 
		/**
		 * On a traité un noeud. On se repositionne pour la suite.
		 */
		else {
			current = current.getParentAsNoeudModifiable();
			if(inConstruction && localName.equals(closeConstructionOn)) inConstruction = false;
		}
	}

	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		if (current != null) {
			// Attention, on supprime l'ancienne valeur de ce tag; 
			// peut être existe-t-il des cas où cela ne doit pas être fait
			if (!current.equals(oldCurrent)) {
				current.resetCharData();
				oldCurrent = current;
			}
			current.addCharacterData(new String (ch, start, length));
		}
		else
			super.characters(ch, start, length);
	} 
	
	
}
