import java.awt.*;
import java.beans.*;
import java.awt.event.*;
import javax.swing.Action;

public class TableView extends java.awt.Panel  
{
	protected TableController controller;
	protected TableRepresentation table;
	protected LabelField[] topLabel, sideLabel;
	protected CellField[][] cell;
	protected boolean labelsVisible = true, square = true;
	protected int xIncrement = 20;
	
	protected final int yIncrement = 16;
	protected final int xOffset = 4, yOffset = 4;
	protected final int xLabel = 20;
	protected final int xLabelSpace = xLabel + 4, 
		yLabelSpace = yIncrement + 4;
	
	public TableView(TableRepresentation t, int maxChars, boolean lbls,
		boolean sq, TableController c)
	{
		//{{INIT_CONTROLS
		setLayout(null);
		//}}

		table = t;
		xIncrement = maxChars * 5 + 15;
		labelsVisible = lbls;
		square = sq;
		controller = c;
		int size = table.getSize();

		TopLabelActionListener topLabelActionListener = 
			new TopLabelActionListener();
		SideLabelActionListener sideLabelActionListener = 
			new SideLabelActionListener();
		TopLabelFocusListener topLabelFocusListener = 
			new TopLabelFocusListener();
		SideLabelFocusListener sideLabelFocusListener = 
			new SideLabelFocusListener();
		CellActionListener cellActionListener = new CellActionListener();
		CellFocusListener cellFocusListener = new CellFocusListener();

		// labels
		topLabel = new LabelField[size];
		sideLabel = new LabelField[size];
		for (int i = 0; i < size; i++)
		{
			topLabel[i] = new LabelField(i, table.label[i]);
			sideLabel[i] = new LabelField(i, table.label[i]);
			topLabel[i].setFont(new Font("Dialog", Font.PLAIN, 10));
			sideLabel[i].setFont(new Font("Dialog", Font.PLAIN, 10));
			add(topLabel[i]);
			add(sideLabel[i]);
			topLabel[i].addActionListener(topLabelActionListener);
			sideLabel[i].addActionListener(sideLabelActionListener);
			topLabel[i].addFocusListener(topLabelFocusListener);
			sideLabel[i].addFocusListener(sideLabelFocusListener);
		}
		
		// cells
		cell = new CellField[size][size];
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
			{
				if (i == j)
				{
					cell[i][j] = new CellField(i, j, "=");
					cell[i][j].setEditable(false);
				}
				else
					cell[i][j] = new 
						CellField(i, j, table.cell[i][j].toString());
				cell[i][j].setFont(new Font("Dialog", Font.PLAIN, 10));
				add(cell[i][j]);
				cell[i][j].addActionListener(cellActionListener);
				cell[i][j].addFocusListener(cellFocusListener);
			}
			
		layoutFields();

		//{{REGISTER_LISTENERS
		//}}
	}

	//{{DECLARE_CONTROLS
	//}}

	class TopLabelActionListener implements java.awt.event.ActionListener
	{
		public void actionPerformed(java.awt.event.ActionEvent event)
		{
			LabelField source = (LabelField)event.getSource();
			labelChanged(source);
		}
	}

	class TopLabelFocusListener implements java.awt.event.FocusListener
	{
		public void focusGained(java.awt.event.FocusEvent event)
		{
		}

		public void focusLost(java.awt.event.FocusEvent event)
		{
			if (!event.isTemporary())
			{
				LabelField source = (LabelField)event.getSource();
				labelChanged(source);
			}
		}
	}
	
	class SideLabelActionListener implements java.awt.event.ActionListener
	{
		public void actionPerformed(java.awt.event.ActionEvent event)
		{
			LabelField source = (LabelField)event.getSource();
			labelChanged(source);
		}
	}

	class SideLabelFocusListener implements java.awt.event.FocusListener
	{
		public void focusGained(java.awt.event.FocusEvent event)
		{
		}

		public void focusLost(java.awt.event.FocusEvent event)
		{
			if (!event.isTemporary())
			{
				LabelField source = (LabelField)event.getSource();
				labelChanged(source);
			}
		}
	}
	
	protected void labelChanged(LabelField source)
	{
		controller.labelChanged(source.getI(), source.getText());
	}
	
	class CellActionListener implements java.awt.event.ActionListener
	{
		public void actionPerformed(java.awt.event.ActionEvent event)
		{
			CellField source = (CellField)event.getSource();
			cellChanged(source);
		}
	}

	class CellFocusListener implements java.awt.event.FocusListener
	{
		public void focusGained(java.awt.event.FocusEvent event)
		{
		}

		public void focusLost(java.awt.event.FocusEvent event)
		{
			if (!event.isTemporary())
			{
				CellField source = (CellField)event.getSource();
				cellChanged(source);
			}
		}
	}

	protected void cellChanged(CellField source)
	{
		int x = source.getX();
		int y = source.getY();
			cell[y][x].setText(table.cell[y][x].toString());
			controller.cellChanged(x, y, source.getText());
	}

	public void setLabelsVisible(boolean b)
	{
		labelsVisible = b;
		layoutFields();
	}
	
	public void setSquare(boolean b)
	{
		square = b;
		layoutFields();
	}

	public void setLabel(int i, String s)
	{
		sideLabel[i].setText(s);
		topLabel[i].setText(s);
	}
	
	public void updateCell(int i, int j)
	{
		cell[i][j].setText(table.cell[i][j].toString());
		cell[j][i].setText(table.cell[j][i].toString());
	}

	protected void layoutFields()
	{
		int xo = xOffset + (labelsVisible ? xLabelSpace : 0)
					- (square ? 0 : xIncrement);
		int yo = yOffset + (labelsVisible ? yLabelSpace : 0);
		int size = table.getSize();
		
		// overall size
		setSize(xo + size * xIncrement + xOffset,
			yo + size * yIncrement + yOffset);

		// labels
		if (labelsVisible)
		{
			if (square)
			{
				for (int i = 0; i < size; i++)
				{
					topLabel[i].setVisible(true);
					topLabel[i].setBounds(xo + i * xIncrement, yOffset,
						xLabel, yIncrement);
					sideLabel[i].setVisible(true);
					sideLabel[i].setBounds(xOffset, yo + i * yIncrement,
						xLabel, yIncrement);
				}
			}
			else
			{
				for (int i = 0; i < size; i++)
				{
					topLabel[i].setVisible(false);
					sideLabel[i].setVisible(true);
					sideLabel[i].setBounds(
						(i == 0 ? xOffset : xo + i * xIncrement),
						yo + i * yIncrement,
						xLabel, yIncrement);
				}
			}
		}
		else
		{
			for (int i = 0; i < size; i++)
			{
				topLabel[i].setVisible(false);
				sideLabel[i].setVisible(false);
			}
		}
		
		// cells
		if (square)
		{
			for (int i = 0; i < size; i++)
				for (int j = 0; j < size; j++)
				{
					cell[i][j].setVisible(true);
					cell[i][j].setBounds(xo + j * xIncrement, 
						yo + i * yIncrement,
						xIncrement, yIncrement);
				}
		}
		else
		{
			for (int i = 0; i < size; i++)
				for (int j = 0; j < i + 1; j++)
					cell[i][j].setVisible(false);
			for (int i = 0; i < size; i++)
				for (int j = i + 1; j < size; j++)
				{
					cell[i][j].setVisible(true);
					cell[i][j].setBounds(xo + j * xIncrement, 
						yo + i * yIncrement,
						xIncrement, yIncrement);
				}
		}
	}
	
	public void update()
	{
		int size = table.getSize();
		
		for (int i = 0; i < size; i++)
		{
			topLabel[i].setText(table.label[i]);
			sideLabel[i].setText(table.label[i]);
		}
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
				cell[i][j].setText(
					(i == j ? "=" : table.cell[i][j].toString()));
	}
}