/*
 * Copyright
 *   2007 axYus - www.axyus.com
 *   2005 C.Marchand - christophe.marchand@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package fr.gouv.finances.cp.xemelios.common.config;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import fr.gouv.finances.cp.utils.Amount;
import fr.gouv.finances.cp.utils.xml.marshal.InvalidXmlDefinition;
import fr.gouv.finances.cp.utils.xml.marshal.NoeudModifiable;
import fr.gouv.finances.cp.utils.xml.marshal.XmlAttributes;
import fr.gouv.finances.cp.utils.xml.marshal.XmlMarshallable;
import fr.gouv.finances.cp.utils.xml.marshal.XmlOutputter;
import fr.gouv.finances.cp.xemelios.ui.resulttable.PjRefHandler;

/**
 * Modelise un champ a d'affichage
 * @author chm
 */
public class ChampModel implements NoeudModifiable{
    private static Logger logger = Logger.getLogger(ChampModel.class);
    private String configXPath = null;
    public static final transient String DATATYPE_PJ="pj-list";
    public static final transient String DATATYPE_DECIMAL="decimal";
    public static final transient String DATATYPE_AMOUNT="amount";
    public static final transient String DATATYPE_INTEGER="integer";
    public static final transient String DATATYPE_DATE="date";
    
    public static final transient String TAG = "champ";
    private String tag;
    private String id, libelle, datatype;
    private XPathModel path;
    private Class classToReturn=null;
    private boolean checked = false;
    private boolean afficheDefaut = true;
    private boolean sommePossible = false;
    /**
     * par d�faut un champs est affichable; cela pour des raisons de compatibilit� avec les anciennes configurations qui ne pr�cisent pas cet attribut
     */
    private boolean affichable = true;
    private boolean exportable = false;
    private boolean identifiant = false;
    
    private NoeudModifiable _NMParent = null;
    
    private NoeudModifiable parent = null;
    
    public void setParent(NoeudModifiable parent) {
        this.parent = parent;
    }
    public ChampModel(String tagName) {
        super();
        this.tag=tagName;
    }
    public void addCharacterData(String cData) throws SAXException {}
    public void addChild(XmlMarshallable child, String tagName) throws SAXException {
        if("valeur".equals(tagName)) {
            path = (XPathModel)child;
            path.setParent(this);
            path.setParentAsNoeudModifiable(this);
        }
    }
    public XmlMarshallable getAttributes(XmlAttributes attributes) throws SAXException {
        id = (attributes.getValue("id")!=null?attributes.getValue("id"):id);
        libelle = (attributes.getValue("libelle")!=null?attributes.getValue("libelle"):libelle);
        datatype=(attributes.getValue("datatype")!=null?attributes.getValue("datatype"):datatype);
        if(datatype==null) datatype="string";
        if (attributes.getValue("checked")!=null)
            checked = attributes.getBooleanValue("checked");
        if(attributes.getValue("default-display")!=null)
            afficheDefaut = attributes.getBooleanValue("default-display");
        if (attributes.getValue("aggregate")!=null)
            sommePossible = attributes.getBooleanValue("aggregate");
        if(attributes.getValue("affichable")!=null)
            affichable = attributes.getBooleanValue("affichable");
        if(attributes.getValue("exportable")!=null)
            exportable = attributes.getBooleanValue("exportable");
        if(attributes.getValue("identifiant")!=null)
            identifiant = attributes.getBooleanValue("identifiant");
        return this;
    }
    public void marshall(XmlOutputter output) {
        output.startTag(tag);
        output.addAttribute("id",StringEscapeUtils.escapeXml(id));
        output.addAttribute("libelle",StringEscapeUtils.escapeXml(libelle));
        output.addAttribute("datatype",StringEscapeUtils.escapeXml(datatype));
        if(checked) output.addAttribute("checked","true");
        if(!afficheDefaut) output.addAttribute("default-display", "false");
        if(sommePossible) output.addAttribute("aggregate", "true");
        path.marshall(output);
        output.endTag(tag);
    }
    public void validate() throws InvalidXmlDefinition {
        if(id==null) throw new InvalidXmlDefinition("//"+TAG+"/@id is required ("+getParentAsNoeudModifiable().getConfigXPath()+"/"+TAG+")");
        if(libelle==null || libelle.length()==0) throw new InvalidXmlDefinition("//"+TAG+"/@libelle is required ("+getConfigXPath()+")");
        path.validate();
    }
    public String getId() {return id;}
    public String getLibelle() {return libelle;}
    public XPathModel getPath() { return path; }
    public Class getDataClass() {
        if(classToReturn==null) {
            if(DATATYPE_INTEGER.equalsIgnoreCase(datatype)) classToReturn=java.lang.Integer.class;
            else if(DATATYPE_DECIMAL.equalsIgnoreCase(datatype)) classToReturn=java.lang.Float.class;
            else if(DATATYPE_DATE.equalsIgnoreCase(datatype)) classToReturn=java.util.Date.class;
            else if(DATATYPE_AMOUNT.equalsIgnoreCase(datatype)) classToReturn= Amount.class ;
            else if(DATATYPE_PJ.equalsIgnoreCase(datatype)) classToReturn = PjRefHandler.class;
            else classToReturn=java.lang.String.class;
        }
        return classToReturn;
    }
    @Override
    public ChampModel clone() {
        ChampModel cm = new ChampModel(tag);
        cm .id = this.id;
//        cm.tag = this.tag;
        cm.libelle = this.libelle;
        cm.datatype = this.datatype;
        try {cm.addChild(this.path.clone(), "valeur");} catch (Throwable t) {logger.error(t);}
        cm.checked = this.checked;
        cm.afficheDefaut = this.afficheDefaut;
        cm.sommePossible = this.sommePossible;
        cm.affichable=this.affichable;
        cm.identifiant=this.identifiant;
        cm.exportable=this.exportable;
        return cm;
    }
    
    @Override
    public boolean equals(Object other) {
        if(other instanceof ChampModel) {
            return(((ChampModel)other).id.equals(this.id));
        } else
            return false;
        //return this.equals(other);
    }
    
    
    
    public boolean isChecked() { return checked; }
    public void setChecked(boolean bChk) { checked = bChk; }
    public boolean isAfficheDefaut() { return afficheDefaut; }
    public void setAfficheDefaut(boolean affDef) { afficheDefaut = affDef; }
    public boolean isSommePossible() { return sommePossible; }
    public void setSommePossible(boolean somPos) { sommePossible = somPos; }
    
    public String getDatatype() { return datatype; }
    
    
    public void setParentAsNoeudModifiable(NoeudModifiable p) {
        this._NMParent = p;
    }
    public NoeudModifiable getParentAsNoeudModifiable() {
        return this._NMParent;
    }
    public NoeudModifiable getChildAsNoeudModifiable(String tagName, String id) {
        return null;
    }
    public void modifyAttr(String attrName, String value) {
        // TODO Raccord de m�thode auto-g�n�r�
        
    }
    public void modifyAttrs(Attributes attrs) {
        try {
            getAttributes(new XmlAttributes(attrs));
        } catch (Exception e) {
            logger.error("Erreur lors de la mise � jour des attributs : "+e);
        }
    }
    public String[] getChildIdAttrName(String childTagName) {
        return null;
    }
    public void resetCharData() {
    }
    public boolean isAffichable() {
        return affichable;
    }
    public void setAffichable(boolean affichable) {
        this.affichable = affichable;
    }
    public String getIdValue() { return getId(); }
    public boolean isExportable() {
        return exportable;
    }
    public boolean isIdentifiant() {
        return identifiant;
    }
    public String getConfigXPath() {
        if(configXPath==null) {
            if(getParentAsNoeudModifiable()!=null) configXPath = getParentAsNoeudModifiable().getConfigXPath();
            else configXPath = "";
            configXPath+="/"+TAG+"[@id='"+getId()+"']";
        }
        return configXPath;
    }
}
