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

/**
 * Models the property element in QJML.
 * The property element defines a pair of methods which constitute a Java Bean Property.
 <pre>
DTD:

&lt;!ELEMENT property EMPTY>

&lt;!ATTLIST property 
&nbsp;&nbsp;&nbsp;&nbsp;<a href="QMAccess.html#name">name</a> CDATA #IMPLIED
&nbsp;&nbsp;&nbsp;&nbsp;<a href="QMAccess.html#kind">kind</a> (array|list|map|indexed) #IMPLIED
&nbsp;&nbsp;&nbsp;&nbsp;<a href="QMAccess.html#size">size</a> CDATA "-1"
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#inherited">inherited</a> (get|set|both) CDATA #IMPLIED
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#initializer">initializer</a> CDATA #IMPLIED
&nbsp;&nbsp;&nbsp;&nbsp;<a href="QMAccess.html#coin">coin</a> CDATA #IMPLIED
&nbsp;&nbsp;&nbsp;&nbsp;<a href="QMAccess.html#key">key</a> CDATA #IMPLIED
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#abst">abstract</a> CDATA "True"
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#read">read</a> CDATA "True"
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#write">write</a> CDATA "True"
&nbsp;&nbsp;&nbsp;&nbsp;ID id #IMPLIED
>
 </pre>
 */
public class QMProperty extends QMAccess
{
	/**
	 * Models the initializer attribute on the property element.
	 * This attribute provides the text used to generate initialization code for the initial value of the property--
	 * useful when generating Java code from a QJML file.
	 * The initializer attribute is optional.
	 */
	public String initializer="";

	/**
	 * Models the abstract attribute on the property element.
	 * When true, the property methods are abstract--this can only be used on an abstract coin,
	 * which is to say on an abstract Java class.
	 * The abstract attribute defaults to false.
	 */
	public boolean abst=false;

	/**
	 * Models the read attribute on the property element.
	 * When true, the property has a get method.
	 * The read attribute defaults to true.
	 */
	public boolean read=true;

	/**
	 * Models the write attribute on the property element.
	 * When true, the property has a set method.
	 * The write attribute defaults to true.
	 */
	public boolean write=true;

	public transient QMCoin myCoin=null;

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

	/**
	 * Add accessor.
	 */
	public void addAccessor(Map coinMap, Map contentMap, QMCoin myCoin)
		throws SAXException
	{
		if ("".equals(name))
			return;
		HashMap accessors=myCoin.accessors;
		String rKey="get_"+name;
		String wKey="set_"+name;
		QMProperty rP=(QMProperty)accessors.get(rKey);
		QMProperty wP=(QMProperty)accessors.get(wKey);
		if (read)
		{
			if((rP==null) 
			|| (!abst && rP.abst))
				accessors.put(rKey,this);
			if (!write && (wP!=null))
			{
				if (abst!=wP.abst)
					throw new SAXException("mixing abstract and non-abstract properties: "+name);
			}
		}
		if (write)
		{
			if((wP==null) 
			|| (!abst && wP.abst))
				accessors.put(wKey,this);
			if (!read && (rP!=null))
			{
				if (abst!=rP.abst)
					throw new SAXException("mixing abstract and non-abstract properties: "+name);
			}
		}
	}

	/**
	 * Munge info from two accessors which should be identical.
	 */
	public void munge()
	{
		super.munge();
		QMProperty a=(QMProperty)ia;
		if (!initializer.equals(a.initializer))
			if ("".equals(initializer))
				initializer=a.initializer;
			else if ("".equals(a.initializer))
				a.initializer=initializer;
	}

	/**
	 * 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(name))
		{
			if (read)
			{
				ia=myCoin.getAccessor(coinMap,"get_"+name);
				if (ia==this)
					ia=null;
				if (ia!=null)
				{
					munge();
				}
			}
			if (write)
			{
				ia=myCoin.getAccessor(coinMap,"set_"+name);
				if (ia==this)
					ia=null;
				if (ia!=null)
				{
					munge();
				}
			}
		}
		super.init(coinMap,contentMap,myCoin,contentModel);
	}

	/**
	 * Returns true when the names are equal and the abstract properties are equal
	 */
	public boolean equals(Object o)
	{
		if (o instanceof QMProperty)
		{
			QMProperty p=(QMProperty)o;
			return (abst==p.abst) && (name.equals(p.name));
		}
		else
			return false;
	}
}
