package jp.riken.brain.ni.samuraigraph.figure;

import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.List;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGIDisposable;
import jp.riken.brain.ni.samuraigraph.base.SGIVisible;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import org.w3c.dom.Document;
import org.w3c.dom.Element;


/**
 * Base class for the set of the groups of drawing elements.
 * This object has an array of drawing element groups.
 * 
 */
public abstract class SGElementGroupSet implements SGIVisible, SGIDisposable
{

	/**
	 * 
	 */
	protected ArrayList mDrawingElementGroupList = new ArrayList();


	/**
	 * 
	 */
	protected float mMagnification = 1.0f;


	/**
	 * 
	 */
	protected boolean mVisibleFlag = true;



	/**
	 * 
	 */
	public SGElementGroupSet()
	{
		super();
	}


	/**
	 * 
	 */
	public void dispose()
	{
		ArrayList list = this.mDrawingElementGroupList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)list.get(ii);
			group.dispose();
		}
		
		this.mDrawingElementGroupList.clear();
		this.mDrawingElementGroupList = null;
		list = null;
	}


	public ArrayList getElementGroupList()
	{
		return new ArrayList( this.mDrawingElementGroupList );
	}


	/**
	 * 
	 */
	public ArrayList getDrawingElementList()
	{
		ArrayList list = new ArrayList();
		ArrayList groupList = new ArrayList( this.mDrawingElementGroupList );
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)groupList.get(ii);
			SGDrawingElement dElement = group.getDrawingElement();
			list.add( dElement );
		}

		return list;
	}



	/**
	 * 
	 */
	public boolean moveElementsToFront( final SGElementGroup group )
	{
		ArrayList groupList = this.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			if( group.equals(groupList.get(ii)) )
			{
				groupList.remove(ii);
				break;
			}
		}
		groupList.add(groupList.size(),group);

		return true;
	}


	/**
	 * 
	 */
	public boolean moveElementsToBack( final SGElementGroup group )
	{
		ArrayList groupList = this.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			if( group.equals(groupList.get(ii)) )
			{
				groupList.remove(ii);
				break;
			}
		}
		groupList.add(0,group);

		return true;
	}


	/**
	 * 
	 */
	public boolean removeElements( final SGElementGroup group )
	{
		ArrayList groupList = this.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			if( group.equals(groupList.get(ii)) )
			{
				groupList.remove(ii);
				return true;
			}
		}

		return false;
	}



	/**
	 * 
	 * @return
	 */
	public void setVisible( final boolean b )
	{
		this.mVisibleFlag = b;
	}


	/**
	 * 
	 */
	public boolean isVisible()
	{
		return this.mVisibleFlag;
	}


	/**
	 * 
	 * @return
	 */
	public float getMagnification()
	{
		return this.mMagnification;
	}


	/**
	 * 
	 */
	public boolean setMagnification( final float mag )
	{
		this.mMagnification = mag;
		ArrayList list = this.mDrawingElementGroupList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)list.get(ii);
			group.setMagnification(mag);
		}

		return true;
	}



	/**
	 * 
	 */
	public boolean zoom( final float mag )
	{
		this.mMagnification = mag;
		ArrayList list = this.mDrawingElementGroupList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)list.get(ii);
			group.zoom(mag);
		}

		return true;
	}



	/**
	 * 
	 */
	public abstract boolean addDrawingElementGroup( final int type );


	/**
	 * 
	 */
	public abstract void paintGraphics2D( final Graphics2D g2d );


	/**
	 * 
	 */
	public boolean contains( final int x, final int y )
	{
		ArrayList list = this.mDrawingElementGroupList;
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			SGElementGroup group = (SGElementGroup)list.get(ii);
			if( group.isVisible() == false )
			{
				continue;
			}

			if( group.contains(x,y) )
			{
				return true;
			}
		}

		return false;
	}


	/**
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public SGElementGroup getElementGroupAt( final int x, final int y )
	{
		ArrayList list = this.mDrawingElementGroupList;
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			SGElementGroup group = (SGElementGroup)list.get(ii);
			if( group.isVisible() == false )
			{
				continue;
			}
			if( group.contains( x, y ) )
			{
				return group;
			}
		}		

		return null;
	}


//	/**
//	 * 
//	 */
//	public abstract boolean addDrawingElementGroup( final SGDrawingElement element );



	/**
	 * 
	 * @return
	 */
	public abstract String getTagName();


	/**
	 * 
	 */
	public abstract boolean writeProperty( final Element el );


	/**
	 * 
	 * @param document
	 * @return
	 */
	public Element createElement( final Document document )
	{
		Element el = document.createElement( this.getTagName() );
		if( this.writeProperty(el) == false )
		{
			return null;
		}
		
		for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)this.mDrawingElementGroupList.get(ii);
			String tagName = group.getTagName();
			Element elGroup = document.createElement(tagName);
			if( group.writeProperty(elGroup) == false )
			{
				return null;
			}
			el.appendChild(elGroup);
		}
		return el;
	}

	
	/**
	 * 
	 */
	public abstract boolean onDrawingElement( final int x, final int y );



	/**
	 * 
	 */
	public boolean setProperties( final SGProperties p )
	{
		if( ( p instanceof ElementGroupSetProperties ) == false )
		{
			return false;
		}

		ElementGroupSetProperties ep = (ElementGroupSetProperties)p;
		
		this.setVisible( ep.visible );

		return true;
	}


	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		ElementGroupSetProperties p = new ElementGroupSetProperties();
		if( this.getProperties(p) == false ) return null;
		return p;
	}


	/**
	 * 
	 */
	public boolean getProperties( final SGProperties p )
	{
		if( ( p instanceof ElementGroupSetProperties ) == false ) return false;

		ElementGroupSetProperties gp = (ElementGroupSetProperties)p;
		gp.visible = this.isVisible();

		return true;
	}




	/**
	 * 
	 */
	public SGProperties getWholeProperties()
	{
		WholeProperties wp = new WholeProperties();
		if( this.getWholeProperties(wp) == false ) return null;
		return wp;
	}


	/**
	 * 
	 */
	public boolean getWholeProperties( final SGProperties p )
	{
		if( ( p instanceof WholeProperties ) == false ) return false;

		WholeProperties wp = (WholeProperties)p;
		wp.mElementGroupSetProperties = (ElementGroupSetProperties)this.getProperties();
		(wp.mElementGroupPropertiesList).clear();
		for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
		{
			SGElementGroup group = (SGElementGroup)this.mDrawingElementGroupList.get(ii);
			(wp.mElementGroupPropertiesList).add( group.getProperties() );
		}

		return true;
	}


	/**
	 * 
	 */
	public boolean setWholeProperties( final SGProperties p )
	{
		if( ( p instanceof WholeProperties ) == false ) return false;

		WholeProperties wp = (WholeProperties)p;

		if( this.setProperties( wp.mElementGroupSetProperties ) == false ) return false;

		List list = wp.mElementGroupPropertiesList;
		if( this.mDrawingElementGroupList.size()!=list.size() )
		{
			return false;
		}

		for( int ii=0; ii<list.size(); ii++ )
		{
			SGProperties ep = (SGProperties)list.get(ii);
			SGElementGroup group = (SGElementGroup)this.mDrawingElementGroupList.get(ii);
			if( group.setProperties(ep) == false ) return false;
		}

		return true;
	}



	/**
	 * @author  okumura
	 */
	public static class WholeProperties extends SGProperties
	{

		private ElementGroupSetProperties mElementGroupSetProperties;
		private List mElementGroupPropertiesList = new ArrayList();


		public WholeProperties()
		{
			super();
		}


		public void dispose()
		{
			this.mElementGroupSetProperties.dispose();
			this.mElementGroupSetProperties = null;

			List list = this.mElementGroupPropertiesList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGProperties p = (SGProperties)list.get(ii);
				p.dispose();
			}
			this.mElementGroupPropertiesList.clear();
			this.mElementGroupPropertiesList = null;
			list = null;
		}

		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{

			if( ( obj instanceof WholeProperties ) == false )
			{
				return false;
			}

			WholeProperties p = (WholeProperties)obj;

			if( p.mElementGroupSetProperties.equals(this.mElementGroupSetProperties) == false )
			{
				return false;
			} 


			if( p.mElementGroupPropertiesList.equals(this.mElementGroupPropertiesList) == false )
			{
				return false;
			} 

			return true;

		}


		public SGProperties getElementGroupSetProperties()
		{
			return this.mElementGroupSetProperties;
		}

		public List getElementGroupPropertiesList()
		{
			return new ArrayList( this.mElementGroupPropertiesList );
		}


		/**
		 * 
		 */
		public String toString()
		{
			String str = new String("[");
			str += this.mElementGroupSetProperties.toString();
			str += this.mElementGroupPropertiesList.toString();
			str += new String("]");

			return str;
		}


	}




	/**
	 * 
	 */
	public static class ElementGroupSetProperties extends SGProperties
	{

		boolean visible;


		public ElementGroupSetProperties()
		{
			super();
		}


		public void dispose()
		{
			
		}

		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{

			if( ( obj instanceof ElementGroupSetProperties ) == false )
			{
				return false;
			}

			ElementGroupSetProperties p = (ElementGroupSetProperties)obj;

			if( p.visible != this.visible ) return false; 

			return true;

		}


		/**
		 * 
		 */
		public String toString()
		{
			String str = new String("[");
			str += new String("visible="+visible+", ");
			str += new String("]");

			return str;
		}
		
	}




}
