content: /*
   * @(#)AbstractDrawingState.java
   *
   * Copyright 2002 EGANTT LLP. All rights reserved.
   * PROPRIETARY/QPL. Use is subject to license terms.
   */
  
  package com.egantt.model.drawing.state;
  
  import java.awt.Point;
  import java.awt.Rectangle;
  import java.awt.Shape;
  import java.awt.geom.Point2D;
  import java.util.ArrayList;
  import java.util.EventObject;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  
  import com.egantt.model.drawing.DrawingState;
  import com.egantt.model.drawing.axis.AxisView;
  import com.egantt.model.drawing.axis.view.event.ViewEvent;
  import com.egantt.model.drawing.axis.view.event.ViewListener;
  import com.egantt.model.drawing.part.event.DrawingPartEvent;
  import com.egantt.model.drawing.part.event.DrawingPartListener;
  import com.egantt.model.drawing.state.event.DrawingStateEvent;
  import com.egantt.model.drawing.state.event.DrawingStateListener;
  
  /**
    * The simplest implementation of a DrawingState notifies the container
    * that a repaint has occured
    */
  public abstract class AbstractDrawingState implements DrawingState
  {
  	protected DrawingPartListener drawingPartListener = new LocalDrawingPartListener();
  	protected ViewListener viewListener = new LocalViewListener();
  	protected List<DrawingStateListener> stateListeners = new ArrayList<DrawingStateListener>(1); // assumes 1x manager
  	protected List<AxisView> viewListeners = new ArrayList<AxisView>(4); // 4x(3D), 3x(Fake3D), 2x(2D)
  
  	protected Map <Object, Shape>bounds = new HashMap<Object, Shape>();
  
  	//___________________________________________________________________________
  
  	public synchronized boolean put(Object key, AxisView axisView)
  	{
  		return addViewListener(axisView);
  	}
  
  	public synchronized boolean put(Object key, Shape bounds)
  	{
  		return this.bounds.put(key, bounds) == null;
  	}
  
  	public boolean contains(Object key)
  	{
  		return this.bounds.containsKey(key);
  	}
  
  	// _________________________________________________________________________
  
  	public Object getValueAt(Point _location) {
  		return getValueAt(_location, 2, 2);
  	}
  	
  	public Object getValueAt(Point _location, int xOffset, int yOffset)
  	{
  		Point2D location = new Point2D.Double(_location.getX(), _location.getY());
  		
  		Rectangle locationBounds = new Rectangle(_location.x - xOffset, _location.y - yOffset, xOffset * 2, yOffset * 2) ;
  		for (Iterator iter = this.bounds.entrySet().iterator(); iter.hasNext();)
  		{
  			Map.Entry entry = (Map.Entry) iter.next();
  
  			Shape shape = (Shape) entry.getValue();
  			if (!shape.getBounds().intersects(locationBounds))
  				continue;
  			
  			if (shape.contains(location) || shape.intersects(locationBounds))
  				return entry.getKey();
  		}
  		return null;
  	}
  
  	// _________________________________________________________________________
  
  	public void initialise()
  	{
  		clearAxisListeners();
  		clearBounds();
  	}
  
  	public void terminate()
  	{
  	}
  
  	// __________________________________________________________________________
  
  	public boolean addDrawingStateListener(DrawingStateListener listener)
  	{
  		return stateListeners.add(listener);
  	}
  
  	public boolean removeDrawingStateListener(DrawingStateListener listener)
  	{
  	   return stateListeners.remove(listener);
  	}
  
  	// __________________________________________________________________________
  
  	protected synchronized boolean addViewListener(AxisView axisView)
  	{
  		return viewListeners.add(axisView) && axisView.addViewListener(viewListener);
  	}
  
  	protected synchronized boolean removeViewListener(AxisView axisView)
  	{
  		return axisView.removeViewListener(viewListener) && viewListeners.remove(viewListener);
  	}
  
  	// __________________________________________________________________________
  
  	protected synchronized void clearAxisListeners()
  	{
  		// clear axis listeners
  		for (Iterator iter = viewListeners.iterator(); iter.hasNext();)
  		{
  		   AxisView axisView = (AxisView) iter.next();
  			axisView.removeViewListener(viewListener);
  		   iter.remove();
  		}
  	}
  
  	//___________________________________________________________________________
  
  	protected synchronized void clearBounds()
  	{
  		this.bounds.clear();
  	}
  
  	//___________________________________________________________________________
  
  	protected void fireChanged(EventObject e)
  	{
  		// use the real propogation ID, we never generated anything we are just
  		// forwarding it on behalf of another object is this the right thing?
  		DrawingStateEvent event = new DrawingStateEvent(e.getSource());
  		for (Iterator iter = stateListeners.iterator(); iter.hasNext();)
  		   ((DrawingStateListener) iter.next()).stateChanged(event);
  	}
  
  	/**
  	  * listens to n Axises
  	  */
  	protected class LocalViewListener implements ViewListener
  	{
  		public void stateChanged(ViewEvent event)
  		{
  		   fireChanged(event);
  		}
  	}
  
  	//___________________________________________________________________________
  
  	/**
  	  * Listens to n drawings
  	  */
  	protected class LocalDrawingPartListener implements DrawingPartListener
  	{
  		public void stateChanged(DrawingPartEvent event)
  		{
  		   fireChanged(event);
  		}
  	}
  }
  