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

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
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.SGIDrawingElementConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIVisible;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.figure.java2d.SGIElementGroupConstants;

import org.w3c.dom.Document;
import org.w3c.dom.Element;


/**
 * Base class for the group of the drawing elements.
 * This object has an array of drawing elements.
 * 
 */
public abstract class SGElementGroup
	implements SGIElementGroupConstants, SGIDrawingElementConstants, SGIVisible, SGIDisposable
{

	/**
	 * 
	 */
	protected SGDrawingElement[] mDrawingElementArray = null;



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



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



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



	/**
	 * 
	 * @return
	 */
	public SGElementGroup()
	{
		super();
	}


	/**
	 * 
	 */
	public void dispose()
	{
		this.mColorList.clear();
		this.mColorList = null;
		
		if( this.mDrawingElementArray!=null )
		{
			SGDrawingElement[] array = this.mDrawingElementArray;
			for( int ii=0; ii<array.length; ii++ )
			{
				array[ii].dispose();
			}
			this.mDrawingElementArray = null;
			array = null;
		}
	}


	/**
	 * 
	 * @return
	 */
	public boolean initDrawingElement( final int num )
	{
		SGDrawingElement[] array = new SGDrawingElement[num];
		for( int ii=0; ii<num; ii++ )
		{
			array[ii] = this.getDrawingElementInstance();
		}
		this.mDrawingElementArray = array;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	protected abstract SGDrawingElement getDrawingElementInstance();


	/**
	 * 
	 * @return
	 */
	public SGDrawingElement[] getDrawingElementArray()
	{
		return this.mDrawingElementArray;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setPropertiesOfDrawingElements()
	{
		return true;
	}


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


	/**
	 * 
	 */
	public boolean setMagnification( final float ratio )
	{
		if( ratio < 0.0 )
		{
			throw new IllegalArgumentException("ratio < 0.0");
		}
		mMagnification = ratio;
		
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				this.mDrawingElementArray[ii].setMagnification(ratio);
			}
		}

		return true;
	}


	/**
	 * 
	 */
	public boolean addColor( final Color color )
	{
		if( color==null )
		{
			throw new IllegalArgumentException("color==null");
		}
		mColorList.add(color);

		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				this.mDrawingElementArray[ii].addColor( color );
			}
		}

		return true;
	}


	/**
	 * 
	 */
	public boolean setColor( final Color color )
	{
		if( color==null )
		{
			throw new IllegalArgumentException("color==null");
		}

		mColorList.clear();
		mColorList.add(color);
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				this.mDrawingElementArray[ii].setColor( color );
			}
		}

		return true;
	}



	/**
	 * 
	 */
	public boolean setColor( final List list )
	{
		if( list==null )
		{
			throw new IllegalArgumentException("list==null");
		}
		if( list.size()==0 )
		{
			throw new IllegalArgumentException("list.size()==0");
		}

		mColorList = new ArrayList(list);
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				this.mDrawingElementArray[ii].setColor( list );
			}
		}
		
		return true;
	}


	/**
	 * 
	 */
	public Color getColor( final int index )
	{
		if( mColorList == null )
		{
			return null;
		}

		if( index >= mColorList.size() )
		{
			new ArrayIndexOutOfBoundsException("index >= mColorList.size()");
		}

		return (Color)mColorList.get(index);
	}


	/**
	 * 
	 */
	public ArrayList getColorList()
	{
		return mColorList;
	}


	/**
	 * 
	 */
	public boolean zoom( float ratio )
	{
		this.mMagnification = ratio;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				this.mDrawingElementArray[ii].zoom(ratio);
			}
		}

		return true;
	}



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


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


	/**
	 * 
	 */
	public boolean contains( final int x, final int y )
	{
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				if( this.mDrawingElementArray[ii].isVisible() == false )
				{
					continue;
				}
				if( this.mDrawingElementArray[ii].contains(x,y) )
				{
					return true;
				}
			}
		}
		return false;
	}




	/**
	 * 
	 */
	public boolean paintElement( final Graphics2D g2d )
	{
		return this.paintElement( g2d, null );
	}



	/**
	 * 
	 */
	public abstract boolean paintElement(
		final Graphics2D g2d, final Rectangle2D clipRect );


	/**
	 * 
	 */
	public abstract SGDrawingElement getDrawingElement();


	/**
	 * 
	 */
	public boolean setProperty( final SGDrawingElement element )
	{
		this.setVisible( element.isVisible() );
		this.setColor( element.getColorList() );

		return true;
	}


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


	/**
	 * 
	 * @param document
	 * @return
	 */
	public Element createElement( final Document document )
	{
		Element el = document.createElement( this.getTagName() );
		if( this.writeProperty(el) == false )
		{
			return null;
		}
		return el;
	}
	
	
	/**
	 * 
	 */
	public abstract boolean writeProperty( final Element el );


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

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


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

		ElementGroupProperties ep = (ElementGroupProperties)p;

		ep.setVisible( this.isVisible() );
		ep.setColor( new ArrayList( this.mColorList ) );

		return true;
	}


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

		ElementGroupProperties ep = (ElementGroupProperties)p;

		final Boolean b = ep.isVisible();
		if( b==null )
		{
			return false;
		}

		final ArrayList cList = ep.getColorList();
		if( cList==null )
		{
			return false;
		}

		this.setVisible( b.booleanValue() );
		this.setColor( cList );

		return true;		
	}


	/**
	 * 
	 */
	public static class ElementGroupProperties extends SGProperties
	{
		private boolean mVisible;
		private ArrayList mColorList = new ArrayList();

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

		public void dispose()
		{
			this.mColorList.clear();
			this.mColorList = null;
		}

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

			if( ( obj instanceof ElementGroupProperties ) == false ) return false;

			ElementGroupProperties p = (ElementGroupProperties)obj;

			if( this.mVisible!=p.mVisible ) return false;
			if( this.mColorList.equals(p.mColorList) == false ) return false;

			return true;
		}


		public Boolean isVisible()
		{
			return Boolean.valueOf( this.mVisible );
		}

		public ArrayList getColorList()
		{
			return new ArrayList( this.mColorList );
		}

		public void setVisible( final boolean b )
		{
			this.mVisible = b;
		}


		public void setColor( final Color cl )
		{
			this.mColorList.clear();
			this.mColorList.add(cl);
		}

		public void setColor( final ArrayList list )
		{
			if( list==null )
			{
				throw new IllegalArgumentException("list==null");
			}
			this.mColorList.clear();
			this.mColorList.addAll( list );
		}

	}



}

