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

import fr.gouv.culture.oai.util.OAIUtilities;
import org.apache.avalon.framework.parameters.Parameters;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

public abstract class AbstractOAIMetadataFormat extends OAIObjectImpl implements OAIMetadataFormat {

    /*
        <metadataFormat>
         <metadataPrefix>oai_dc</metadataPrefix>
         <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd
           </schema>
         <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/
           </metadataNamespace>
       </metadataFormat>
       */

    /**Format name string*/
    protected String formatName = "";
    /**The metadataPrefix*/
    protected String prefix = "";
    /**The schema url of the metadata format*/
    protected String schemaUrl = "";
    /**The namespace of the metadata format*/
    protected String namespace = "";
    /**The root element for metadata*/
    protected String rootElement = "";
    /*The metadata mappings (paramName/paramValue = inElementName/outElementName)*/
    protected Parameters metadataMappings = null;

    /**Retrieves the human readable name of the metadata format*/
    public String getName() {
        return formatName;
    }

    /**Establishes the human readable name of the metadata format*/
    public void setName(String formatName) {
        this.formatName = formatName;
    }

    /**Retrieves the prefix of this metadata format*/
    public String getPrefix() {
        return prefix;
    }

    /**Establishes the prefix of this metadata format*/
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    /**Retrieves the schema url of this metadata format*/
    public String getSchemaUrl() {
        return schemaUrl;
    }

    /**Establishes the schema url of this metadata format*/
    public void setSchemaUrl(String schemaUrl) {
        this.schemaUrl = schemaUrl;
    }

    /**Retrieves the namespace uri of this metadata format*/
    public String getNamespace() {
        return namespace;
    }

    /**Establishes the namespace uri of this metadata format*/
    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    /**Retrieves a Parameters object with mappings for
     * element sent via this object
     * @see #metadataMappings
     */
    public Parameters getMappings() {
        return metadataMappings;
    }

    /**Establishes a Parameters object with mappings for
     * element sent via this object
     * @see #metadataMappings
     */
    public void setMappings(Parameters mappings) {
        this.metadataMappings = mappings;
    }

    /**Sends SAX events to the provided content handler,
     * describing the metadata format in the syntax of
     * the oai repository ListMetadataFormats verb response.
     *
     * @param contentHandler
     * @throws SAXException
     */
    public void toSAX(ContentHandler contentHandler) throws SAXException {
        /*
        <metadataFormat>
         <metadataPrefix>oai_dc</metadataPrefix>
         <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd
           </schema>
         <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/
           </metadataNamespace>
       </metadataFormat>
       */
        if (OAIUtilities.checkString(this.prefix) && OAIUtilities.checkString(this.schemaUrl) && OAIUtilities.checkString(this.namespace)) {
            ContentHandler currentHandler = super.contentHandler;

            super.setContentHandler(contentHandler);

            String oai20xmlns = OAIObject.Node.Xmlns.OAI_2_0;
            super.startElement(oai20xmlns, OAIObject.Node.Name.METADATA_FORMAT, OAIObject.Node.Name.METADATA_FORMAT, null);

            super.sendElement(oai20xmlns, OAIObject.Node.Name.METADATA_PREFIX, OAIObject.Node.Name.METADATA_PREFIX, null, this.prefix);
            super.sendElement(oai20xmlns, OAIObject.Node.Name.SCHEMA, OAIObject.Node.Name.SCHEMA, null, this.schemaUrl);
            super.sendElement(oai20xmlns, OAIObject.Node.Name.METADATA_NAMESPACE, OAIObject.Node.Name.METADATA_NAMESPACE, null, this.namespace);

            super.endElement(oai20xmlns, OAIObject.Node.Name.METADATA_FORMAT, OAIObject.Node.Name.METADATA_FORMAT);

            super.setContentHandler(currentHandler);
        }


    }

    /**Sends START of the root element for this metadata format
     *
     * @throws SAXException
     */
    public void startMetadataFormatRootElement() throws SAXException {
        /*
        <oai_dc:dc
                xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
                xmlns:dc="http://purl.org/dc/elements/1.1/"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
                http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
        */
        String elemName = null;
        String qName = null;
        String uri = this.namespace;
        if (OAIUtilities.checkString(this.prefix) && OAIUtilities.checkString(this.namespace) && OAIUtilities.checkString(this.schemaUrl)) {
            elemName = this.rootElement;
            qName = this.prefix + ":" + elemName;
            AttributesImpl atts = new AttributesImpl();

            if (this.prefix.equals(OAIObject.Node.Prefix.OAI_DC)) {
                elemName = OAIObject.Node.Prefix.DC;
                qName = OAIObject.Node.Prefix.OAI_DC + ":" + OAIObject.Node.Prefix.DC;
                uri = OAIObject.Node.Xmlns.OAI_DC_2_0;
                super.startPrefixMapping(OAIObject.Node.Prefix.DC, OAIObject.Node.Xmlns.DC);
                //atts.addAttribute("", ATTRIBUTE_NAME_DC, ATTRIBUTE_NAME_DC, NODE_TYPE_CDATA, DC);
            } /*else {
                String nsUrlAttName = ATTRIBUTE_NAME_XMLNS + ":" + this.prefix;
                atts.addAttribute("", nsUrlAttName, nsUrlAttName, NODE_TYPE_CDATA, this.namespace);
            }*/
            //atts.addAttribute("", ATTRIBUTE_NAME_XSI, ATTRIBUTE_NAME_XSI, NODE_TYPE_CDATA, XSI);
            super.startPrefixMapping(OAIObject.Node.Prefix.XSI, OAIObject.Node.Xmlns.XSI);
            super.startPrefixMapping(this.prefix, uri);
            String schemaLocVal = uri + " " + this.schemaUrl;
            //if ( /*isXmlnsXsiPresent*/atts.getIndex(OAIObject.Node.Name.XMLNS+":"+OAIObject.Node.Prefix.XSI) < 0 )
            //	atts.addAttribute("", OAIObject.Node.Name.XMLNS + ":" + OAIObject.Node.Prefix.XSI, OAIObject.Node.Name.XMLNS + ":" + OAIObject.Node.Prefix.XSI, OAIObject.Node.Type.CDATA, OAIObject.Node.Xmlns.XSI);
            if ( /*isSchemaLocationPresent*/atts.getIndex(OAIObject.Node.Name.Qualified.XSI_SCHEMA_LOCATION) < 0 )
                atts.addAttribute(OAIObject.Node.Xmlns.XSI, "schemaLocation", OAIObject.Node.Name.Qualified.XSI_SCHEMA_LOCATION, OAIObject.Node.Type.CDATA, schemaLocVal);
            super.startElement(uri, elemName, qName, atts);


        }


    }

    /**Sends END of the root element for this metadata format
     *
     * @throws SAXException
     */

    public void endMetadataFormatRootElement() throws SAXException {
        //</oai_dc:dc>
        String elemName = null;
        String qName = null;
        String uri = "";
        if (OAIUtilities.checkString(this.prefix)) {
            elemName = this.prefix;
            qName = this.prefix + ":" + elemName;
            if (this.prefix.equals(OAIObject.Node.Prefix.OAI_DC)) {
                uri = OAIObject.Node.Xmlns.OAI_DC_2_0;
                elemName = OAIObject.Node.Prefix.DC;
                qName = OAIObject.Node.Prefix.OAI_DC + ":" + OAIObject.Node.Prefix.DC;
            }
            super.endElement(uri, elemName, qName);
            super.endPrefixMapping(elemName);
            super.endPrefixMapping(OAIObject.Node.Prefix.XSI);

        }

    }

    /**Sends an element to this object's
     * consumer passing through any
     * specified mappings
     *
     * @param origName
     * @param value
     * @throws SAXException
     * @see #metadataMappings
     */
    protected void prepareAndSendElement(String origName, String value) throws SAXException {
        if (OAIUtilities.checkString(this.namespace) && OAIUtilities.checkString(prefix)
                && OAIUtilities.checkString(origName) && OAIUtilities.checkString(value)) {
            String uri = this.namespace;
            String locName = null;
            if (this.metadataMappings != null && this.metadataMappings.isParameter(origName))
                locName = this.metadataMappings.getParameter(origName, null);
            if (OAIUtilities.checkString(locName)) {
                String qName = locName;
                String tmpPrefix = this.prefix;
                if (tmpPrefix.equals(OAIObject.Node.Prefix.OAI_DC))
                    qName = OAIObject.Node.Prefix.DC + ":" + locName;

                super.sendElement(uri, locName, qName, new AttributesImpl(), value);
            }
        }

    }

    /**Sends an element to this object's consumer
     *
     * @param origName
     * @param value
     * @throws SAXException
     * @see #prepareAndSendElement
     */
    public void sendElement(String origName, String value) throws SAXException {
        if (OAIUtilities.checkString(origName) && OAIUtilities.checkString(value))
            prepareAndSendElement(origName, value);
    }


}
