/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@ow2.org
 *
 * This library 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 2.1 of the License, or any later version.
 *
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial Developer : Delplanque Xavier & Sauthier Guillaume
 * --------------------------------------------------------------------------
 * $Id: MappingFile.java 15428 2008-10-07 11:20:29Z sauthieg $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.deployment.ws;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import org.ow2.jonas.deployment.common.xml.Qname;
import org.ow2.jonas.deployment.ws.xml.JavaWsdlMapping;
import org.ow2.jonas.deployment.ws.xml.JavaXmlTypeMapping;
import org.ow2.jonas.deployment.ws.xml.PackageMapping;




/**
 * this Class is used to manipulate jaxrpc-mapping-file. This file contains
 * informations for mapping between XML namespaces and java packages. We
 * actually support just a few part of this file. According with JSR 921, this
 * file must contain class mapping information (exceptions/faults,
 * types/classes, portTypes/interfaces ...).
 *
 * @author Guillaume Sauthier
 * @author Xavier Delplanque
 * @author Helene Joanin
 */
public class MappingFile {

    /** Associates a namespace to its package. It's the cache. */
    private Map namespacePackageMapping;

    /** Associates an XML QName to its java classname */
    private Map xmlType2javaClassname;

    /** parsed object */
    private JavaWsdlMapping javaWSDLMapping;

    /**
     * Constructor : creates a MappingFile object.
     *
     * @param jwMapping XML Element java-wsdl-mapping
     */
    public MappingFile(JavaWsdlMapping jwMapping) {

        javaWSDLMapping = jwMapping;

        // init vars
        namespacePackageMapping = new Hashtable();
        xmlType2javaClassname = new Hashtable();

        fillPackageMapping(jwMapping);
        fillXmlTypeMapping(jwMapping);

    }


    /**
     * Fill up the package mapping hashtable
     *
     * @param mapping jaxrpc-mapping-file root element.
     */
    private void fillPackageMapping(JavaWsdlMapping mapping) {
        List pml = mapping.getPackageMappingList();

        for (Iterator i = pml.iterator(); i.hasNext();) {
            // get each mapping file package mappings
            PackageMapping pm = (PackageMapping) i.next();

            String pt = pm.getPackageType();
            String nuri = pm.getNamespaceURI();

            //add in the hashtable the namespace to package relation (cache)
            namespacePackageMapping.put(nuri, pt);
        }
    }

    /**
     * Fill up the xml type to java class map
     *
     * @param mapping jaxrpc-mapping-file root element.
     */
    private void fillXmlTypeMapping(JavaWsdlMapping mapping) {

        List jxml = mapping.getJavaXmlTypeMappingList();
        for (Iterator i = jxml.iterator(); i.hasNext();) {
            // get each java -> xml type mapping
            JavaXmlTypeMapping jxtm = (JavaXmlTypeMapping) i.next();

            QName xmlName = null;
            String javaName = jxtm.getJavaType();
            Qname rootType = jxtm.getRootTypeQname();
            if (rootType != null) {
                xmlName = rootType.getQName();
            } else {
                xmlName = jxtm.getAnonymousTypeQname().getQName();
            }

            xmlType2javaClassname.put(xmlName, javaName);
        }
    }

    /**
     * @return Returns the XML Element representing this MappingFile (use only for Test).
     */
    public JavaWsdlMapping getXmlJavaWsdlMapping() {
        return javaWSDLMapping;
    }

    /**
     * return the mapping between XML namespaces and Java packages defined in
     * the jaxrpc-mapping file.
     *
     * @return the mapping between XML namespaces and Java packages
     */
    public Map getMappings() {
        return namespacePackageMapping;
    }

    /**
     * Return the package associated with the specified namespaceURI (can be
     * null).
     *
     * @param namespaceURI the namespace key to retrieve the package name
     *
     * @return the package associated with the specified namespaceURI. (null if
     *         namespace not present).
     */
    public String getMapping(String namespaceURI) {
        return (String) namespacePackageMapping.get(namespaceURI);
    }

    /**
     * Return the Java classname representing the xml type.
     *
     * @param xmlType the QName of the xml type
     *
     * @return the Java classname representing the xml type.
     */
    public String getClassname(QName xmlType) {
        return (String) xmlType2javaClassname.get(xmlType);
    }

    /**
     * Return an iterator traversing the list of xmlType mappings.
     *
     * @return an iterator traversing the list of xmlType mappings.
     */
    public Iterator getXmlTypeMappings() {
        return xmlType2javaClassname.keySet().iterator();
    }

    /**
     * Build a string representation of MappingFile
     *
     * @return String representation of the mapping file.
     */
    public String toString() {
        StringBuffer ret = new StringBuffer();

        ret.append("\n" + getClass().getName()); //$NON-NLS-1$
        ret.append("\ngetMappings()=" + namespacePackageMapping); //$NON-NLS-1$
        ret.append("\ngetXmlTypeMappings()=" + xmlType2javaClassname); //$NON-NLS-1$

        return ret.toString();
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return this.namespacePackageMapping.hashCode() + this.xmlType2javaClassname.hashCode();
    }

    /**
     * Return true if the 2 objects are equals in value.
     *
     * @param other the object to compare.
     *
     * @return true if objects are equals in value, else false.
     */
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (other == null) {
            return false;
        }
        if (!(other instanceof MappingFile)) {
            return false;
        }
        MappingFile ref = (MappingFile) other;
        if (!namespacePackageMapping.equals(ref.getMappings())) {
            return false;
        }
        // After all theses tests, the 2 objects are equals in value
        return true;
    }

}
