package edu.calpoly.csc480.Corral.Area;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;

import com.bcurry.www.swing.*;

import edu.calpoly.csc480.Corral.Agent.*;
import edu.calpoly.csc480.Corral.Tile.*;
import edu.calpoly.csc480.Corral.Seer.*;

abstract public class BaseAreaView extends BasicPanel
{
	static protected final int lineSize = 2;

	public BaseAreaView() {
      super(new GridBagLayout());
      setOpaque(true);
		
      addComponentListener(new ComponentAdapter() {
         public void componentMoved(ComponentEvent e)		{disposeGraphics();}         
         public void componentResized(ComponentEvent e)	{disposeGraphics();}
      });
		
		size = new Dimension();
		lines = new ArrayList();

		lineColor = Color.gray;
		lineStroke = new BasicStroke((float)lineSize);

		meansKilled();
		streamClosed();
	}
	
   public Dimension getMinimumSize()		{return getPreferredSize();}
   public Dimension getPreferredSize()		{return size;}
	
	public BaseArea getDocument()				{return area;}
	public BaseSeerView getOwner()			{return seerView;}

	final public BaseTileView getTileView(Point areaPoint) {
		return tiles[areaPoint.y][areaPoint.x].getView();
	}

	final public Point getTilePoint(Point areaPoint) {
		return getTileView(areaPoint).getLocation();
	}

	public void setDocument(BaseArea area)	{
		this.area = area;
	}

	public void setOwner(BaseSeerView seerView)  {
		this.seerView = seerView;
		this.seer = seerView.getDocument();
	}

	public void setPreferredSize(Dimension preferredSize) {
		super.setPreferredSize(preferredSize);
		disposeGraphics();
	}

	public void streamRead() {
		final Dimension tileSize = new Dimension(12, 12);
		Dimension areaSize;

		tiles    = area.getTiles().getTiles();
		areaSize = area.getTiles().getDimension();
		inferSizes(tileSize, areaSize);
	}

	public void streamClosed() {
		this.tiles = null;
		lines.clear();
		setPreferredSize(new Dimension(1, 1));
	}
	
	public void meansMade() {
		Dimension tileSize, areaSize;
		
		means = area.getMeans();

		tileSize = means.getView().getPreferredSize();
		areaSize = area.getTiles().getDimension();
		inferSizes(tileSize, areaSize);
		
		next();
	}
	
	public void meansKilled() {
		means = null;
	}
	
	public void next() {
		boolean pause;

		if (draw == null) {
			draw = (Graphics2D)getGraphics();
		}

		pause = seer.isPaused();
		seer.pause();

		updateMeans(draw);

		if (!pause) {
			seer.resume();
		}
	}
	
	public void play() {
	}
	
	protected BaseArea area;
	protected BaseMeans means;
	protected BaseSeer seer;
	protected BaseSeerView seerView;

	protected BaseTile tiles[][];	
	protected Dimension tileSize;

	protected java.util.List lines;
	protected Color lineColor;
	protected Stroke lineStroke;
	
	protected Dimension size;
	protected Graphics2D draw;
	
   protected void finalize() throws Throwable {
		disposeGraphics();
	}

   synchronized protected void disposeGraphics() {
      if (draw != null) {
         draw.dispose();
         draw = null;
      }

		packWindow();
   }
	
	protected void inferSizes(Dimension tileSize, Dimension areaSize) {
		inferPreferredSize(tileSize, areaSize);
		inferTileBounds(tileSize, areaSize);
		inferLineBounds(tileSize, areaSize);
	}

	protected void inferPreferredSize(Dimension tileSize, Dimension areaSize) {
		size.width =
		 areaSize.width*tileSize.width +
		 areaSize.width*lineSize + lineSize;
		size.height =
		 areaSize.height*tileSize.height +
		 areaSize.height*lineSize + lineSize;
		
		setPreferredSize(size);
	}

	protected void inferTileBounds(Dimension tileSize, Dimension areaSize) {
		int row, col;
		int x, y, width, height;

		width  = tileSize.width;
		height = tileSize.height;
		
      for (
		 row = 0, y = lineSize;
		 row < areaSize.height;
		 row++, y += lineSize + height) {
	      for (
			 col = 0, x = lineSize;
			 col < areaSize.width;
			 col++, x += lineSize + width) {
				tiles[row][col].getView().setBounds(x, y, width, height);
			}
		}
	}
	
	protected void inferLineBounds(Dimension tileSize, Dimension areaSize) {
		int row, col;
		int x, y;
		int xBeg, yBeg, xEnd, yEnd;
		Line2D line;

		xBeg = yBeg = 0;
		xEnd = size.width - 1;
		yEnd = size.height - 1;

		lines.clear();
		
      for (
		 row = 0, y = 1;
		 row <= areaSize.height;
		 row++, y += lineSize + tileSize.height) {
			line = new Line2D.Float();
			line.setLine(xBeg, y, xEnd, y);
			lines.add(line);
		}

      for (
		 col = 0, x = 1;
		 col <= areaSize.width;
		 col++, x += lineSize + tileSize.width) {
			line = new Line2D.Float();
			line.setLine(x, yBeg, x, yEnd);
			lines.add(line);
		}
	}

   protected void paintComponent(Graphics drawBase) {
      boolean pause;
      Graphics2D draw;
		
      super.paintComponent(drawBase);
		draw = (Graphics2D)drawBase;

		if (tiles != null)  {
			pause = seer.isPaused();
			seer.pause();

			paintTiles(draw);
			paintMeans(draw);
			paintLines(draw);

			if (!pause) {
				seer.resume();
			}
		}
   }

   protected void updateMeans(Graphics2D draw) {
   	if (means != null) {
   		means.getView().update(draw);
   	}
   }

	protected void paintMeans(Graphics2D draw) {
		if (means != null) {
			means.getView().paint(draw);
		}
	}
	
	protected void paintTiles(Graphics2D draw) {
		int row, col;

      for (row = 0; row < tiles.length; row++) {
	      for (col = 0; col < tiles[row].length; col++) {
				tiles[row][col].getView().paint(draw);
			}
      }
  	}

	protected void paintLines(Graphics2D draw) {
      Color oldColor;
		Stroke oldStroke;
		Iterator itr;

		oldColor = draw.getColor();
		oldStroke = draw.getStroke();
		
      draw.setColor(lineColor);
		draw.setStroke(lineStroke);

		itr = lines.iterator();

		while (itr.hasNext()) {
			draw.draw((Shape)itr.next());
		}

		draw.setColor(oldColor);
		draw.setStroke(oldStroke);
  	}
}