/*
 * Copyright 2007 Joachim Grueneis
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.castor.xml;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.mapping.MappingLoader;
import org.exolab.castor.util.RegExpEvaluator;
import org.exolab.castor.xml.Introspector;
import org.exolab.castor.xml.NodeType;
import org.exolab.castor.xml.OutputFormat;
import org.exolab.castor.xml.ResolverException;
import org.exolab.castor.xml.Serializer;
import org.exolab.castor.xml.XMLClassDescriptorResolver;
import org.exolab.castor.xml.util.ResolverStrategy;
import org.xml.sax.DocumentHandler;
import org.xml.sax.Parser;
import org.xml.sax.XMLReader;

/**
 * The internal context is meant as center piece providing (and keeping) all information that is
 * required by Marshaller, Unmarshaller, SourceGenerator, MappingTool, SchemaReader and
 * SchemaWriter. It is created, filled with initial data and put into all other parts of Castor by
 * {@link XMLContext}. It is NOT meant to be directly instantiated by user implementations! For all
 * other objects it provides access to Castor state information (e.g. known descriptors) and
 * configuration values.
 * 
 * @author <a href="mailto:jgrueneis At gmail DOT com">Joachim Grueneis</a>
 * @since 1.1.2
 */
public interface InternalContext extends PropertyChangeProvider {

  /**
   * Instructs Castor to load class descriptors from the mapping given.
   * 
   * @param mapping Castor XML mapping (file), from which the required class descriptors will be
   *        derived.
   * @throws MappingException If the {@link Mapping} cannot be loaded and analyzed successfully.
   */
  void addMapping(final Mapping mapping) throws MappingException;

  /**
   * Loads the class descriptor for the class instance specified. The use of this method is useful
   * when no mapping is used, as happens when the domain classes has been generated using the XML
   * code generator (in which case instead of a mapping file class descriptor files will be
   * generated).
   * 
   * @param clazz the class for which the associated descriptor should be loaded.
   * @throws ResolverException in case that resolving the Class fails fatally
   */
  void addClass(final Class<?> clazz) throws ResolverException;

  /**
   * Loads the class descriptor for the class instance specified. The use of this method is useful
   * when no mapping is used, as happens when the domain classes hase been generated using the XML
   * code generator (in which case instead of a mapping file class descriptor files will be
   * generated).
   * 
   * @param clazzes the classes for which the associated descriptor should be loaded.
   * @throws ResolverException in case that resolving the Class fails fatally
   */
  void addClasses(final Class<?>[] clazzes) throws ResolverException;

  /**
   * Loads class descriptors from the package specified. The use of this method is useful when no
   * mapping is used, as happens when the domain classes hase been generated using the XML code
   * generator (in which case instead of a mapping file class descriptor files will be generated).
   * <p>
   * Please note that this functionality will work only if you provide the <tt>.castor.cdr</tt> file
   * with your generated classes (as generated by the XML code generator).
   * <p>
   * 
   * @param packageName The package name for the (descriptor) classes
   * @throws ResolverException If there's a problem loading class descriptors for the given package.
   */
  void addPackage(final String packageName) throws ResolverException;

  /**
   * Loads class descriptors from the packages specified. The use of this method is useful when no
   * mapping is used, as happens when the domain classes hase been generated using the XML code
   * generator (in which case instead of a mapping file class descriptor files will be generated).
   * <p>
   * Please note that this functionality will work only if you provide the <tt>.castor.cdr</tt>
   * files with your generated classes (as generated by the XML code generator).
   * <p>
   * 
   * @param packageNames The package names for the (descriptor) classes
   * @throws ResolverException If there's a problem loading class descriptors for the given package.
   */
  void addPackages(final String[] packageNames) throws ResolverException;

  /**
   * Sets an application-specific {@link XMLClassDescriptorResolver} instance.
   * 
   * @param xmlClassDescriptorResolver the resolver to use
   */
  void setResolver(final XMLClassDescriptorResolver xmlClassDescriptorResolver);

  /**
   * To set properties for marshalling and unmarshalling behavior.
   * 
   * @param propertyName name of the property to set
   * @param value the value to set to
   */
  void setProperty(final String propertyName, final Object value);

  /**
   * To get the value of a specific property.
   * 
   * @param propertyName name of the Property
   * @return the value (Object) of the property
   */
  Object getProperty(final String propertyName);

  /**
   * Returns the naming conventions to use for the XML framework.
   *
   * @return the naming conventions to use for the XML framework
   */
  XMLNaming getXMLNaming();

  /**
   * Returns the naming conventions to use for the XML framework.
   * 
   * @param classLoader the class loader to be used when instantiating a new naming instance
   * @return the naming conventions to use for the XML framework
   * @TODO: Joachim should be synchronized, shouldn't it be??
   */
  XMLNaming getXMLNaming(final ClassLoader classLoader); // -- getXMLNaming

  /**
   * The {@link JavaNaming} instance to be used.
   * 
   * @return {@link JavaNaming} instance to be used.
   */
  JavaNaming getJavaNaming();

  /**
   * Return an XML document parser implementing the feature list specified in the configuration
   * file.
   *
   * @return A suitable XML parser
   */
  Parser getParser();

  /**
   * Returns an XML document parser implementing the requested set of features. The feature list is
   * a comma separated list of features that parser may or may not support. No errors are generated
   * for unsupported features. If the feature list is not null, it overrides the default feature
   * list specified in the configuration file, including validation and Namespaces.
   *
   * @param features The requested feature list, null for the defaults
   * @return A suitable XML parser
   */
  Parser getParser(final String features);

  /**
   * Returns an XML document parser implementing the requested set of features. The feature list is
   * a comma separated list of features that parser may or may not support. No errors are generated
   * for unsupported features. If the feature list is not null, it overrides the default feature
   * list specified in the configuration file, including validation and Namespaces.
   * 
   * @return A suitable XML parser
   */
  XMLReader getXMLReader(); // -- getXMLReader

  /**
   * Returns an XML document parser implementing the requested set of features. The feature list is
   * a comma separated list of features that parser may or may not support. No errors are generated
   * for unsupported features. If the feature list is not null, it overrides the default feature
   * list specified in the configuration file, including validation and Namespaces.
   *
   * @param features the name of feature to set
   * @return A suitable XML parser
   */
  XMLReader getXMLReader(final String features); // -- getXMLReader

  /**
   * Returns the NodeType to use for Java primitives. A null value will be returned if no NodeType
   * was specified, indicating the default NodeType should be used.
   *
   * @return the NodeType assigned to Java primitives, or null if no NodeType was specified.
   **/
  NodeType getPrimitiveNodeType(); // -- getPrimitiveNodeType

  /**
   * Returns a new instance of the specified Regular Expression Evaluator, or null if no validator
   * was specified.
   *
   * @return the regular expression evaluator,
   *
   **/
  RegExpEvaluator getRegExpEvaluator(); // -- getRegExpEvaluator

  /**
   * Returns a default serializer for producing an XML document. The caller can specify an
   * alternative output format, may reuse this serializer across several streams, and may serialize
   * both DOM and SAX events. If such control is not required, it is recommended to call one of the
   * other two methods.
   * 
   * @return A suitable serializer
   */
  Serializer getSerializer();

  /**
   * Returns the default OutputFormat for use with a Serializer.
   *
   * @return the default OutputFormat
   **/
  OutputFormat getOutputFormat(); // -- getOutputFormat

  /**
   * Returns a default serializer for producing an XML document to the designated output stream
   * using the default serialization format.
   *
   * @param output The output stream
   * @return A suitable serializer
   * @throws IOException if instantiation of the serializer fails
   */
  DocumentHandler getSerializer(final OutputStream output) throws IOException;

  /**
   * Returns a default serializer for producing an XML document to the designated output stream
   * using the default serialization format.
   * 
   * @param output The output stream
   * @return A suitable serializer
   * @throws IOException if instantiation of serializer fails
   */
  DocumentHandler getSerializer(final Writer output) throws IOException;

  /**
   * To get the XMLClassdescriptorResolver instance hold in the context.
   * 
   * @return the XMLClassdescriptorResolver instance hold in the context
   */
  XMLClassDescriptorResolver getXMLClassDescriptorResolver();

  /**
   * To get the Introspector assigned to this XMLContext.
   * 
   * @return the Introspector assigned to this XMLContext
   */
  Introspector getIntrospector();

  /**
   * To get the XMLClassDescriptor resolver strategy to be used when resolving classes into class
   * descriptors.
   * 
   * @return the ResolverStrategy to use
   */
  ResolverStrategy getResolverStrategy();

  /**
   * To set the XMLClassDescriptor resolver strategy to be used.
   * 
   * @param resolverStrategy the ResolverStrategy to use
   */
  void setResolverStrategy(final ResolverStrategy resolverStrategy);

  /**
   * To set the {@link MappingLoader} to be used in this Castor session.
   * 
   * @param mappingLoader the {@link MappingLoader} to use
   */
  void setMappingLoader(final MappingLoader mappingLoader);

  /**
   * To get the {@link MappingLoader} specified to be used in this Castor session.
   * 
   * @return the {@link MappingLoader} to use
   */
  MappingLoader getMappingLoader();

  /**
   * To set the {@link JavaNaming}?property.
   * 
   * @param javaNaming the {@link JavaNaming} to use
   */
  void setJavaNaming(final JavaNaming javaNaming);

  /**
   * To set the {@link XMLNaming} property.
   * 
   * @param xmlNaming the {@link XMLNaming} to use
   */
  abstract void setXMLNaming(final XMLNaming xmlNaming);

  /**
   * To set any boolean property.
   * 
   * @param propertyName name of the property to set
   * @param value boolean value to set
   */
  void setProperty(final String propertyName, final boolean value);

  /**
   * Providing access to Boolean properties of the configuration.
   * 
   * @param propertyName name of the property
   * @return null if property is not set or whichever value is set
   */
  Boolean getBooleanProperty(final String propertyName);

  /**
   * Providing access to String properties of the configuration.
   * 
   * @param propertyName name of the property
   * @return null if the property is not set or whichever value is set
   */
  String getStringProperty(final String propertyName);

  /**
   * To set the class loader to be used in all further marshalling, unmarshalling and other actions.
   * 
   * @param classLoader the ClassLoader instance to use
   */
  void setClassLoader(final ClassLoader classLoader);

  /**
   * To set the {@link XMLClassDescriptorResolver} to be used. Be aware, that the
   * XMLClassDescriptorResolver instance holds a descriptor cache!! Maybe change it to have the
   * descriptor cache as part of the context?
   * 
   * @param xmlClassDescriptorResolver the {@link XMLClassDescriptorResolver} to use
   */
  void setXMLClassDescriptorResolver(final XMLClassDescriptorResolver xmlClassDescriptorResolver);

  /**
   * To specify which {@link Introspector}?is to be used.
   * 
   * @param introspector {@link Introspector} to be used
   */
  void setIntrospector(final Introspector introspector);

  /**
   * To get the ClassLoader to use for loading resources.
   * 
   * @return the ClassLoader to use
   */
  ClassLoader getClassLoader();

  /**
   * Get lenient id validation flag.
   * 
   * @return lenient id validation flag
   */
  boolean getLenientIdValidation();

  /**
   * Get lenient sequence order flag.
   * 
   * @return lenient sequence order flag
   */
  boolean getLenientSequenceOrder();

  /**
   * Get load package mapping flag.
   * 
   * @return load package mapping flag
   */
  Boolean getLoadPackageMapping();

  /**
   * To set the load package mapping flag.
   * 
   * @param loadPackageMapping the load package mapping flag
   */
  void setLoadPackageMapping(final Boolean loadPackageMapping);

  /**
   * To get use-introspection flag.
   * 
   * @return use-introspection flag
   */
  Boolean getUseIntrospector();

  /**
   * To set use-introspection flag.
   * 
   * @param useIntrospector use-introspection flag
   */
  void setUseIntrospector(final Boolean useIntrospector);

  /**
   * To get marshalling-validation flag.
   * 
   * @return marshalling-validation flag
   */
  boolean marshallingValidation();

  /**
   * To get strict-element flag.
   * 
   * @return strict-element flag
   */
  boolean strictElements();

}
