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>
 * Models an abstract element in QDML.
 * An abstract element has no tag attribute, since it doesn't define a particular
 * XML element. (Similarly, an abstract Java class can't be instantiated.)
 * Abstract coins provide a means of refering to the family of beans which implement them.
 * Abstract coins also provide for inheritance of attributes, enums, and ranges by the coins
 * which extend them.
 * </p>
 <pre>
DTD:

&lt;!ELEMENT abstract (<a href="QDMCoin.html#remList">rem*</a>, <a href="#extendor">extends?</a>, <a href="#implementsList">implements*</a>, <a href="#attributes">attributes</a>, <a href="#validList">(enum|range)*</a>)>

&lt;!ATTLIST abstract 
&nbsp;&nbsp;&nbsp;&nbsp;<a href="QDMCoin.html#label">label</a> CDATA #REQUIRED
&nbsp;&nbsp;&nbsp;&nbsp;<a href="QDMCoin.html#generate">generate</a> CDATA "True"
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#validInherited">validInherited</a> CDATA "True"
&nbsp;&nbsp;&nbsp;&nbsp;ID id #IMPLIED
>
 </pre>
 */
public class QDMAbstract extends QDMCoin
	implements QDMElement, QDMData
{
	/**
	 * Models the validInherited attribute on an abstract element.
	 * When false, enums and ranges are not inherited from the coin that this abstract coin extends.
	 */
	public boolean validInherited=true;

	/**
	 * Models an extends element, which is optional.
	 * An abstract coin can extend a bean coin, a text coin, or another abstract coin,
	 * which is named by the extends element.
	 */
	public QDMExtends extendor=null;

	/**
	 * A container for QMImplements objects, which model implements elements.
	 * The implements elements are optional and repeating.
	 * These implements elements name the interface coins which this abstract coin "implements".
	 * (An abstract element, like an abstract Java class, can impliment any number of interfaces.)
	 * 
	 */
	public ArrayList implementsList=new ArrayList();

	/**
	 * Models an attributes element, which is optional.
	 * The attributes element defines the attributes associated with this coin,
	 * as well as various related variables and property methods on the abstract Java class used
	 * to model those attributes.
	 */
	public QDMAttributes attributes=null;

	/**
	 * A container for QMField objects, which model field elements.
	 * The field elements are optional and repeating.
	 * These field elements describe the variables of the abstract Java class which
	 * this abstract element describes.
	 */
	public ArrayList fieldList=new ArrayList();

	/**
	 * A container for QMProperty objects, which model property elements.
	 * The property elements are optional and repeating.
	 * These property elements describe the bean property methods of the abstract Java class which
	 * this abstract element describes.
	 */
	public ArrayList propertyList=new ArrayList();

	/**
	 * <p>
	 * A container for QMEnum and QMRange objects, which model enum and range elements.
	 * The enum and range elements are optional and repeating.
	 * These valid elements are used to describe some of the acceptable text content of text coins which
	 * extend this abstract coin.
	 * </p><p>
	 * The enum and range elements may not be present when the targetClass is present in the
	 * same abstract element.
	 * </p>
	 */
	public ArrayList validList=new ArrayList();

	/**
	 * The QMAbstract, QMText, or QMBean object named by the extends element.
	 * This variable is set when the data model is initialized.
	 */
	public transient QDMCoin extendsCoin=null;

	/**
	 * A container for QMEnum and QMRange objects for this element, 
	 * including enum and range elements defined on abstract and text coins
	 * which this abstract coin extends.
	 * This list is populated when the data model is initialized.
	 */
	public transient ArrayList valids=null;

	public Object clone()
	{
		QDMAbstract rv=(QDMAbstract)super.clone();
		rv.extendor=(QDMExtends)clone(extendor);
		rv.implementsList=clone(implementsList);
		rv.attributes=(QDMAttributes)clone(attributes);
		rv.validList=clone(validList);
		rv.extendsCoin=null;
		rv.valids=null;
		return rv;
	}

	public void buildMaps(Map coinMap, Map contentMap)
		throws SAXException
	{
		int i;
		int s;

		if (attributes==null)
			attributes=new QDMAttributes();

		String l=getLabel();
		if ("".equals(l))
			throw new SAXException(
				"Abstract coin has no label.");
		if (coinMap.containsKey(l))
			throw new SAXException("Duplicate label: "+l);
		coinMap.put(l,this);

		attributes.buildMaps(coinMap,contentMap,this);
	}

	public void init(Map coinMap, Map contentMap)
		throws SAXException
	{
		int i;
		int s;
		QDMCoin c;

		if (extendor!=null)
		{
			extendsCoin=(QDMCoin)coinMap.get(extendor.text);
			if (extendsCoin==null)
				throw new SAXException("Undefined coin: "+extendor.text);
			extendsCoin.extensions.add(this);
		}


		s=implementsList.size();
		for (i=0;i<s;++i)
		{
			String l=((QDMImplements)implementsList.get(i)).text;
			c=(QDMCoin)coinMap.get(l);
			if (c==null)
				throw new SAXException("Undefined coin: "+l);
			c.implementations.add(this);
		}

		attributes.init(coinMap,contentMap,this,extendsCoin);
	}

	public Map getAtts()
		throws SAXException
	{
		return attributes.getAtts();
	}

	/**
	 * Returns  the element or attribute tag name..
	 */
	public String getTag()
	{
		return "";
	}

	public ArrayList getValidList()
		throws SAXException
	{
		if (valids!=null)
			return valids;
		valids=new ArrayList(validList);
		if (extendsCoin==null || !validInherited)
			return valids;
		valids.addAll(((QDMData)extendsCoin).getValidList());
		return valids;
	}
}
