package com.jxml.quick.model.qdml;
import com.jxml.quick.ocm.*;
import com.jxml.quick.*;
import org.xml.sax.*;
import java.util.*;
import java.io.*;

/**
 * <p>
 * A model for the qdml element, which is the root element of the QDML binding schema.
 * Every QDML document contains exactly one qdml element, which is the top-level (or outer-most)
 * element of the document.
 * </p>
 <pre>
DTD:

&lt;!ELEMENT qdml (<A href="#includes">include*</A>, <a href="#excludeses">excludes*</a>, <A href="#coins">(interface|abstract|text|bean|link)*</A>)&gt;
&lt;!ATTLIST qdml
    <a href="#root">root</a> CDATA #REQUIRED
    <a href="#SYSTEM">SYSTEM</a> CDATA #IMPLIED
    <a href="#PUBLIC">PUBLIC</a> CDATA #IMPLIED
    ID id #IMPLIED
&gt;
 </pre>

 */
public class QDMQDML extends QDMCloneable
{
	/**
	 * <p>
	 * Models the attribute root, a required attribute on the qdml element.
	 * The root attribute must uniquely name the coin which specifies the top-level element
	 * (or elements) of the document type being defined by this QDML document.
	 * </p><p>
	 * Note that any coin which implements or extends the coin named by root can
	 * be used as a root element.
	 * </p>
	 */
	public String root="";

	/**
	 * <p>
	 * Models the attribute SYSTEM, an optional attribute on the qdml element.
	 * The SYSTEM attribute is a fully qualified URL, typically the URL of the DTD
	 * for the type of document which this QDML document implements.
	 * </p>	 */
	public String SYSTEM="";

	/**
	 * <p>
	 * Models the attribute PUBLIC, an optional attribute on the qdml element.
	 * The PUBLIC attribute is a URI naming the document type being defined.
	 * </p>
	 */
	public String PUBLIC="";

	/**
	 * <p>
	 * A container for the Strings which model include elements, which are optional and repeating.
	 * During initialization of the model, the coins found in the QDML documents named by these Strings
	 * are included in the effective content of this QDML document.
	 * When coins with the same (otherwise) unique label or tag are found in more than one document,
	 * the last coin included is used. And when an included coin has the same name as a coin in this document,
	 * the coin in this document is chosen.
	 * </p><p>
	 * Inclusion is a recursive process, allowing for indirect inclusion to any depth.
	 * </p>
	 */
	public ArrayList includes=new ArrayList();

	/**
	 * <p>
	 * A container for the objects which model excludes elements, which are optional and repeating.
	 * During initialization of the model, any coins that have been included which are named by an excludes
	 * element are dropped.
	 * </p><p>
	 * The coins in a QDML document are not effected by the excludes elements in that, or any included, document.
	 * </p>
	 */
	public ArrayList excludeses=new ArrayList();

	/**
	 * <p>
	 * A container for the objects which model the coins elements, which are optional and repeating.
	 * (Coin elements are interface, abstract, text, bean, and link.)
	 * </p><p>
	 * This container is uneffected by the initialization process--it contains only coins defined in the
	 * current document.
	 * </p>
	 */
	public ArrayList coins=new ArrayList();

	/**
	 * <p>
	 * A table of all the coins in the document, along with the coins of all included documents.
	 * Entries are ordered/keyed by each coin's unique label or tag name.
	 * This table is populated when the data model is initialized.
	 * </p>
	 */
	public transient TreeMap coinMap=null;

	/**
	 * <p>
	 * A table of all the contentModels.
	 * Entries are ordered/keyed by each contentModel's unique label.
	 * (ContentModel elements are item, sequence, and selection.)
	 * This table is populated when the data model is initialized.
	 * </p>
	 */
	public transient TreeMap contentMap=null;

	/**
	 * Returns a deep copy of this object, but in an uninitialized form.
	 */
	public Object clone()
	{
		QDMQDML rv=(QDMQDML)super.clone();
		rv.includes=clone(includes);
		rv.excludeses=clone(excludeses);
		rv.coins=clone(coins);
		rv.coinMap=null;
		rv.contentMap=null;
		return rv;
	}

	/**
	 * <p>
	 * Initializes the data model.
	 * The init method on the QDMQDML object must be called explicitly by the
	 * application which uses this data model. The init and buildMaps on
	 * the subordinate objects are called in turn.
	 * </p><p>
	 * This is a thread-safe method, allowing multiple applications to share the
	 * same data model. This is also a recursive method, calling init on all included
	 * QDML documents in turn.
	 * </p>
	 */
	public synchronized void init()
		throws SAXException, IOException
	{
		if (coinMap==null)
		{
			coinMap=new TreeMap();
			contentMap=new TreeMap();

			buildMaps(coinMap,contentMap);

			Collection col=coinMap.values();
			Iterator it=col.iterator();
			while(it.hasNext())
			{
				QDMCoin c=(QDMCoin)it.next();
				c.init(coinMap,contentMap);
			}
		}
	}

	/**
	 * <p>
	 * Builds the maps.
	 * This method is called during initialization of the data model.
	 * </p>
	 */
	public void buildMaps(Map coinMap, Map contentMap)
		throws SAXException
	{
		int s;
		int i;

		s=includes.size();
		for (i=0;i<s;++i)
		{
			QDMQDML incl=(QDMQDML)includes.get(i);
			QDMQDML deepClone=(QDMQDML)incl.clone();
			deepClone.buildMaps(coinMap,contentMap);
		}

		s=excludeses.size();
		for (i=0;i<s;++i)
		{
			QDMExcludes excl=(QDMExcludes)excludeses.get(i);
			excl.buildMaps(coinMap,contentMap);
		}

		s=coins.size();
		for (i=0;i<s;++i)
		{
			QDMCoin c=(QDMCoin)coins.get(i);
			c.buildMaps(coinMap,contentMap);
		}
	}
}
