/*
Copyright (c) 2002-2008, Dennis M. Sosnoski.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of JiBX nor the names of its contributors may be used
   to endorse or promote products derived from this software without specific
   prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.jibx.runtime;

import java.util.Map;

import org.jibx.runtime.impl.StringIntHashMap;

/**
 * Binding factory interface definition. This interface is implemented by the
 * binding factory class generated by each binding definition. All binding
 * factory instances are guaranteed to be threadsafe and reusable.
 *
 * @author Dennis M. Sosnoski
 */
public interface IBindingFactory
{
    /** Current binary version number. This is a byte-ordered value, allowing
     for two levels of major and two levels of minor version. */
    static final int CURRENT_VERSION_NUMBER = 0x00030000;
    
    /** Current distribution file name. This is filled in by the Ant build
     process to match the current distribution. */
    static final String CURRENT_VERSION_NAME = "jibx_1_2_5_SNAPSHOT";
    
    /** Mask for portions of version number that effect compatibility. */
    static final int COMPATIBLE_VERSION_MASK = 0xFFFF0000;
    
    /** Abstract mapping details index for mapping (type or class) name. */
    static final int ABMAP_MAPPINGNAME_INDEX = 0;
    
    /** Abstract mapping details index for class name. */
    static final int ABMAP_CLASSNAME_INDEX = 1;
    
    /** Abstract mapping details index for new instance creation method. */
    static final int ABMAP_CREATEMETH_INDEX = 2;
    
    /** Abstract mapping details index for unmarshalling complete method. */
    static final int ABMAP_COMPLETEMETH_INDEX = 3;
    
    /** Abstract mapping details index for marshalling prepare method. */
    static final int ABMAP_PREPAREMETH_INDEX = 4;
    
    /** Abstract mapping details index for attribute presence test method. */
    static final int ABMAP_ATTRPRESMETH_INDEX = 5;
    
    /** Abstract mapping details index for attribute unmarshalling method. */
    static final int ABMAP_ATTRUMARMETH_INDEX = 6;
    
    /** Abstract mapping details index for attribute marshalling method. */
    static final int ABMAP_ATTRMARMETH_INDEX = 7;
    
    /** Abstract mapping details index for content presence test method. */
    static final int ABMAP_CONTPRESMETH_INDEX = 8;
    
    /** Abstract mapping details index for content unmarshalling method. */
    static final int ABMAP_CONTUMARMETH_INDEX = 9;
    
    /** Abstract mapping details index for content marshalling method. */
    static final int ABMAP_CONTMARMETH_INDEX = 10;
    
    /** Number of abstract mapping details. */
    static final int ABMAP_COUNT = 11;
    
    /**
     * Create marshalling context instance.
     *
     * @return created marshalling context instance
     * @throws JiBXException if error creating context
     * @throws UnsupportedOperationException if marshalling not supported
     * by binding
     */
    IMarshallingContext createMarshallingContext() throws JiBXException;
    
    /**
     * Create unmarshalling context instance.
     *
     * @return created unmarshalling context instance
     * @throws JiBXException if error creating context
     * @throws UnsupportedOperationException if unmarshalling not supported
     * by binding
     */
    IUnmarshallingContext createUnmarshallingContext() throws JiBXException;
    
    /**
     * Get version number for binding compiler used.
     *
     * @return version number of code used to compile binding
     */
    int getCompilerVersion();
    
    /**
     * Get distribution name for binding compiler used.
     *
     * @return name of distribution for binding compiler
     */
    String getCompilerDistribution();
    
    /**
     * Get the name of this binding.
     *
     * @return name
     */
    String getBindingName();
    
    /**
     * Get the major version number for this binding.
     *
     * @return major version
     */
    int getMajorVersion();
    
    /**
     * Get the minor version number for this binding.
     *
     * @return minor version
     */
    int getMinorVersion();
    
    /**
     * Get hash for binding. The computed hash value is based on all the values
     * returned by all the methods of this interface, with the exception of the
     * {@link #getMarshallerClass(int)} and {@link #getUnmarshallerClass(int)}
     * methods returning <code>Class</code> objects.
     *
     * @return hash
     */
    int getHash();
    
    /**
     * Get namespaces defined in mapping. The returned array is indexed by the
     * namespace index number used when marshalling.
     *
     * @return array of namespaces defined in binding (<code>null</code> if not
     * an output binding)
     */
    String[] getNamespaces();
    
    /**
     * Get initial prefixes for namespaces defined in mapping. The returned
     * array is indexed by the namespace index number used when marshalling.
     * Note that these are only the first prefixes associated with each
     * namespace; it's possible to reuse the namespace in the binding with a
     * different prefix.
     *
     * @return array of prefixes for namespaces defined in binding
     * (<code>null</code> if not an output binding)
     */
    String[] getPrefixes();
    
    /**
     * Get mapped class names (or type names, in the case of abstract mappings).
     * Returns array of fully-qualified class and/or type names, ordered by
     * index number of the class.
     *
     * @return array of class names
     */
    String[] getMappedClasses();

    /**
     * Get map from fully-qualified class name to the index number of the class
     * used for accessing the arrays of class names. The value returned is the
     * index for the class in the arrays returned by {@link
     * #getMappedClasses()}, {@link #getMarshallerClasses()}, and {@link
     * #getUnmarshallerClasses()}, and can also be used as input for {@link
     * #getMarshallerClass(int)} and {@link #getUnmarshallerClass(int)}.
     *
     * @return map from fully-qualified class name to index number
     */
    StringIntHashMap getClassIndexMap();
    
    /**
     * Get namespaces of elements corresponding to mapped classes. The returned
     * array uses the same ordering as the result of the {@link
     * #getMappedClasses} call. Entries in the array are <code>null</code> if
     * there is no element for a class or the element is in the default
     * namespace.
     *
     * @return array of element namespaces
     */
    String[] getElementNamespaces();
    
    /**
     * Get names of elements corresponding to mapped classes. The returned array
     * uses the same ordering as the result of the {@link #getMappedClasses}
     * call. Entries in the array are <code>null</code> if there is no element
     * for a class.
     *
     * @return array of element names
     */
    String[] getElementNames();
    
    /**
     * Get marshaller class names. The returned array uses the same ordering as
     * the result of the {@link #getMappedClasses} call. Entries in the array
     * are <code>null</code> if there is no marshaller class for the mapping.
     *
     * @return array of class names
     */
    String[] getMarshallerClasses();
    
    /**
     * Get unmarshaller class names. The returned array uses the same ordering
     * as the result of the {@link #getMappedClasses} call. Entries in the array
     * are <code>null</code> if there is no unmarshaller class for the mapping.
     *
     * @return array of class names
     */
    String[] getUnmarshallerClasses();
    
    /**
     * Get mapped class index from type name for abstract non-base mappings
     * included in the binding. This is intended to allow identifying and using
     * abstract mappings (basically type mappings) at runtime. The method only
     * returns a non-negative result if the "force-classes" option is used
     * for the binding definition (since otherwise no marshaller/unmarshaller
     * classes are created for abstract non-base mappings).
     *
     * @param type fully-qualified class or type name
     * @return mapping index for type, or <code>-1</code> if type is not an
     * abstract non-base mapping
     */
    int getTypeIndex(String type);
    
    /**
     * Get the classes used by the binding. Every class which includes code
     * generated by the binding compiler for this binding or any precompiled
     * base binding is included in the returned array. If {@link
     * #verifyBaseBindings()} has not already been invoked it will be invoked by
     * this call.
     *
     * @return fully-qualified class names
     * @throws JiBXException on base binding verification error
     */
    String[] getBindingClasses() throws JiBXException;
    
    /**
     * Get the linkage information for global abstract mappings included in the
     * binding. The returned array has a primary (first index) dimension of 11
     * and a secondary (second index) dimension equal to the number of global
     * abstract mappings. The different index values for the first index give
     * the following information:
     * <ul>
     * <li>0 - mapping name (type or class)</li>
     * <li>1 - class name</li>
     * <li>2 - new instance creation method (<code>null</code> if none)</li>
     * <li>3 - unmarshalling complete method (<code>null</code> if none)</li>
     * <li>4 - prepare for marshalling method (<code>null</code> if none)</li>
     * <li>5 - attribute presence test method (<code>null</code> if none)</li>
     * <li>6 - attribute unmarshaller method (<code>null</code> if none)</li>
     * <li>7 - attribute marshaller method (<code>null</code> if none)</li>
     * <li>8 - content presence test method (<code>null</code> if none)</li>
     * <li>9 - content unmarshaller method (<code>null</code> if none)</li>
     * <li>10 - content marshaller method (<code>null</code> if none)</li>
     * </ul>
     * The method specifications are in the form of fully qualified class names
     * and method signatures. The methods are only intended for use by the
     * binding compiler when working with a precompiled binding.
     *
     * @return method information array
     */
    String[][] getAbstractMappings();
    
    /**
     * Get the indexes of the namespaces used by an abstract mapping.
     *
     * @param index abstract mapping index, corresponding to the abstract
     * mapping information returned by {@link #getAbstractMappings()}.
     * @return namespace indexes, empty array if none
     */
    int[] getAbstractMappingNamespaces(int index);
    
    /**
     * Get the mapping from element local name to class indexes. If a local name
     * is only used with a single namespace, the value for that name is an
     * <code>Integer</code> giving the index of the class mapped to the name; if
     * the local name is used with multiple namespaces, the value for that name
     * is an array with multiple <code>int</code> class indexes, for every class
     * mapped to the name.
     *
     * @return map from local name to class index array
     */
    Map getUnmarshalMap();
    
    /**
     * Get the unmarshaller class for a mapping. This can only be used for
     * global mappings.
     *
     * @param index unmarshaller class index
     * @return unmarshaller class, or <code>null</code> if unable to load class
     */
    Class getUnmarshallerClass(int index);
    
    /**
     * Get the marshaller class for a mapping. This can only be used for global
     * mappings.
     *
     * @param index marshaller class index
     * @return marshaller class, or <code>null</code> if unable to load class
     */
    Class getMarshallerClass(int index);
    
    /**
     * Get the names of the separately-compiled base bindings used by this
     * binding.
     *
     * @return binding names
     */
    String[] getBaseBindings();
    
    /**
     * Verify that separately-compiled base bindings used by this binding can be
     * loaded and are compatible with the base bindings used when this binding
     * was compiled.
     * 
     * @throws JiBXException on verification failure
     */
    void verifyBaseBindings() throws JiBXException;
    
    /**
     * Get the names of the binding factory classes for the separately-compiled
     * base bindings used by this binding.
     *
     * @return binding factory fully-qualified class names
     */
    String[] getBaseBindingFactories();
    
    /**
     * Get a map from full-qualified binding factory names to an array of
     * <code>int</code> values used to convert namespace indexes in that binding
     * to this binding. If the binding uses the same namespaces as this binding
     * (or a subset of the same namespaces, with the same index values) there is
     * no entry in the map.
     *
     * @return map to namespace index translation
     */
    Map getNamespaceTranslationTableMap();
    
    /**
     * Load a class. This first tries to load the specified class using the
     * classloader that loaded the binding factory instance, then tries the
     * thread context classloader, then finally tries the classloader used to
     * load core runtime classes.
     *
     * @param name fully qualified class name
     * @return loaded class, or <code>null</code> if class not found
     */
    Class loadClass(String name);
}