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

/**
 * Models the element access, which represents a family of elements in QJML.
 * This family of elements define the implimentation of the relationship between
 * an element and its attributes or an element and its element content.
 */
public abstract class QMAccess extends QMCloneable
{
	/**
	 * Models the name attribute of a field or property element.
	 * The name element specifies the variable or property name used by the Java class
	 * being described.
	 * The name attribute is required for field and property elements and is not
	 * a part of other access elements.
	 */
	public String name="";

	/**
	 * Models the size attribute of an access element.
	 * The size attribute specifies of an array or indexed property.
	 * The size attribute has a default value of -1.
	 */
	public int size=-1;

	/**
	 * Models the coin attribute of an access element.
	 * The coin attribute names a coin element in the same QJML document, or in an included document.
	 * The identified coin describes the element or family of elements being accessed.
	 * The coin attribute is optional.
	 * When the access element is held by an item and the schema attribute is not set on that item element,
	 * then the value of the coin attribute on that item element is used as a default value.
	 */
	public String coin="";

	/**
	 * Models the key attribute on an access element.
	 * The key attribute names a field or property element.
	 * This attribute is required when kind is set to map,
	 * optional when kind is set to array, list, or indexed,
	 * and should not be set when kind is not set.
	 */
	public String key="";

	/**
	 * <p>
	 * Models the kind attribute.
	 * The kind attribute is optional, but is limited to the following values:
	 * <ul>
	 * <li>
	 * array -- The item is an array.
	 * </li>
	 * <li>
	 * list -- The item is a java.util.List.
	 * </li>
	 * <li>
	 * map -- The item is a java.util.Map.
	 * </li>
	 * <li>
	 * indexed -- The item is an indexed property.
	 * </li>
	 * </ul>
	 * </p>
	 */
	public String kind="";

	/**
	 * References the QMCoin object named by the coin attribute.
	 * This variable is set when the data model is initialized.
	 */
	public transient QMCoin mCoin=null;

	/**
	 * References the QMField or QMProperty object named by the key attribute.
	 * This variable is set when the data model is initialized.
	 */
	public transient QMAccess keyAccess=null;

	/**
	 * Matching inherited access
	 */
	public transient QMAccess ia=null;

	/**
	 * Returns a deep copy of this object, but in an uninitialized form.
	 */
	public Object clone()
	{
		QMAccess rv=(QMAccess)super.clone();
		rv.mCoin=null;
		rv.keyAccess=null;
		return rv;
	}

	/**
	 * Builds the maps.
	 * This method is called during initialization of the data model.
	 */
	public void buildMaps(Map coinMap, Map contentMap, QMCoin myCoin)
		throws SAXException
	{
	}

	/**
	 * Add accessor.
	 */
	public void addAccessor(Map coinMap, Map contentMap, QMCoin myCoin)
		throws SAXException
	{
	}

	/**
	 * Munge info from two accessors which should be identical.
	 */
	public void munge()
	{
		if (size!=ia.size)
			if (size==-1)
				size=ia.size;
			else if (ia.size==-1)
				ia.size=size;
		if (!coin.equals(ia.coin))
			if ("".equals(coin))
				coin=ia.coin;
			else if ("".equals(ia.coin))
				ia.coin=coin;
		if (!key.equals(ia.key))
			if ("".equals(key))
				key=ia.key;
			else if ("".equals(ia.key))
				ia.key=key;
		if (!kind.equals(ia.kind))
			if ("".equals(kind))
				key=ia.key;
			else if ("".equals(ia.kind))
				ia.kind=kind;
	}

	/**
	 * Resolve references, inheritance.
	 * This method is called during initialization of the data model.
	 */
	public void init(Map coinMap, Map contentMap, QMCoin myCoin, QMContentModel contentModel)
		throws SAXException
	{
		if ("".equals(coin))
		{
			if (contentModel instanceof QMItem)
			{
				QMItem item=(QMItem)contentModel;
				if (!"".equals(item.coinName) && "".equals(item.schema) && "".equals(kind))
				{
					QMCoin namedCoin=(QMCoin)coinMap.get(item.coinName);
					if (namedCoin!=null && namedCoin instanceof QMLink)
					{
						QMLink namedLink=(QMLink)namedCoin;
						coin=namedLink.coin;
						if (ia!=null)
							ia.coin=coin;	// inherit up!
					}
					else if ((namedCoin instanceof QMText)
						 && "idref".equals(((QMText)namedCoin).type))
						;
					else

						coin=item.coinName;


				}
			}
		}
		if ("".equals(coin))
			if ("".equals(key))
				return;
			else
				throw new SAXException("Key is set to "+key+", but the coin attribute has not been set.");
		mCoin=(QMCoin)coinMap.get(coin);
		if (mCoin==null)
			throw new SAXException("Undefined coin: "+this.coin);
		// process key
		if ("".equals(key))
			return;
		keyAccess=mCoin.getAccessor(coinMap,key);
		if (keyAccess==null)
			throw new SAXException("Key accessor "+key+" is not defined on "+coin);
	}

	/**
	 * Return the name of the Java class of the element named by the coin attribute.
	 */
	public String getClassName()
		throws SAXException
	{
		if (mCoin!=null)
			return mCoin.getClassName();
		if ("list".equals(kind))
			return "java.util.ArrayList";
		if ("map".equals(kind))
			return "java.util.HashMap";
		return "java.lang.Object";
	}
}
