package ckelling.baukasten;

import java.awt.*;


/**
 *	EditableTable.java
 *
 *  Editierbare Tabelle einstellbarer Größe;
 *  benutzt von EditableMemory.
 *
 *	@author		Carsten Kelling
 *	@version	0.3.0, 28.10.96
 */
public class EditableTable extends Canvas
{
    private int         numCols;
    private int         numRows;
    private int			numCells;
    private int			cellWidth;
    private int			cellHeight;
	private Rechner		parent_rechner;
	private EditableMemory_Resource		parent;

	private Rectangle	b; // bounds
	private String		text[];
	private boolean		editable;
	private Font		font;
	private Color		foreground[];
	private Color		background[];

	private Image		cellCache[];
	private Graphics	cellCacheGC[];
	private boolean		cellCacheValid[];
	private Image		imageCache;
	private Graphics	imageCacheGC;
	private boolean		imageCacheValid;
	private Image		backgroundCache;


	public EditableTable(int cols, int rows, int cw, int ch, Rechner rpar, EditableMemory_Resource par)
	{
		numCols			= cols;
		numRows			= rows;
		numCells		= numCols * numRows;
		cellWidth		= cw;
		cellHeight		= ch;
		parent_rechner	= rpar;
		parent			= par;

		b				= new Rectangle(0, 0, numCols * cw, numRows * ch);

		font			= parent_rechner.DIALOGFONT;

		foreground		= new Color[numCells];
		background		= new Color[numCells];
		text			= new String[numCells];
		cellCache		= new Image[numCells];
		cellCacheGC		= new Graphics[numCells];
		cellCacheValid	= new boolean[numCells];
		for (int i = 0; i < numCells; i++)
		{
			foreground[i]		= Color.black;
			background[i]		= parent_rechner.BACKGROUND;
			text[i] 			= new String("");
			cellCache[i]		= parent_rechner.createImage(cellWidth - 4, cellHeight - 4);
			cellCacheGC[i]		= cellCache[i].getGraphics();
			cellCacheGC[i]		.setFont(font);
			cellCacheGC[i]		.setColor(foreground[i]);
			cellCacheValid[i]	= false;
		}
		editable = true;

		imageCache		= parent_rechner.createImage(b.width, b.height);
		imageCacheGC	= imageCache.getGraphics();
		imageCacheValid	= false;

		backgroundCache	= parent_rechner.createImage(b.width, b.height);
		Graphics g = backgroundCache.getGraphics();
		g.setColor(parent_rechner.BACKGROUND);
	    g.fillRect(0, 0, b.width, b.height);
	    int x, y;
	    /**
		for (int row = 0; row < numRows; row++)
			for (int col = 0; col < numCols; col++)
			{
				x = col*cellWidth;
				y = row*cellHeight;
			    g.setColor(parent_rechner.MEDIUM_GREY);
			    g.fillRect(x, 					y, 					cellWidth - 1, 1);
			    g.fillRect(x, 					y, 					1, cellHeight - 1);
			    g.setColor(Color.black);
			    g.fillRect(x + 1, 				y + 1,				cellWidth - 3, 1);
			    g.fillRect(x + 1, 				y + 1,				1, cellHeight - 3);
			    g.setColor(parent_rechner.LIGHT_GREY);
			    g.fillRect(x + 1,				y + cellHeight - 2,	cellWidth - 2, 1);
			    g.fillRect(x + cellWidth - 2,	y + 1, 				1, cellHeight - 3);
			    g.setColor(Color.white);
			    g.fillRect(x, 					y + cellHeight - 1,	cellWidth, 1);
			    g.fillRect(x + cellWidth - 1,	y + 0,				1, cellHeight - 1);
			}
		*/
		int row, col;
		int width = b.width;
		int height = b.height;

	    g.setColor(Color.black);
	    x = 1; y = 1;
		for (row = 0; row < numRows; row++)
		{
			g.fillRect(0, y, width, 1);
			y = y + cellHeight;
		}
		for (col = 0; col < numCols; col++)
		{
			g.fillRect(x, 0, 1, height);
			x = x + cellWidth;
		}

	    g.setColor(parent_rechner.LIGHT_GREY);
	    x = cellWidth - 2; y = cellHeight - 2;
		for (row = 0; row < numRows; row++)
		{
			g.fillRect(0, y, width, 1);
			y = y + cellHeight;
		}
		for (col = 0; col < numCols; col++)
		{
			g.fillRect(x, 0, 1, height);
			x = x + cellWidth;
		}

	    g.setColor(parent_rechner.MEDIUM_GREY);
	    x = 0; y = 0;
		for (row = 0; row < numRows; row++)
		{
			g.fillRect(0, y, width, 1);
			y = y + cellHeight;
		}
		for (col = 0; col < numCols; col++)
		{
			g.fillRect(x, 0, 1, height);
			x = x + cellWidth;
		}

	    g.setColor(Color.white);
	    x = cellWidth - 1; y = cellHeight - 1;
		for (row = 0; row < numRows; row++)
		{
			g.fillRect(0, y, width, 1);
			y = y + cellHeight;
		}
		for (col = 0; col < numCols; col++)
		{
			g.fillRect(x, 0, 1, height);
			x = x + cellWidth;
		}


		super.setBackground(parent_rechner.BACKGROUND);
		super.setForeground(Color.black);
	}

	public void paint(Graphics g)
	{
		if (imageCacheValid == false)
		// Aussehen der EditableTable hat sich geaendert...
		{
            // g.drawImage(imageCache, 0, 0, parent_rechner);
    		// ..., trotzdem das alte Aussehen zuerst herstellen,
    		// um Flackern bis zur Berechnung des neuen zu vermeiden.
            // Nicht mehr notwendig, seit update() korrigiert wurde.

		    imageCacheGC.drawImage(backgroundCache, 0, 0, parent_rechner);

			int x = 0;
			int y = 0;
			int i = 0;
			for (int row = 0; row < numRows; row++)
			{
				for (int col = 0; col < numCols; col++)
			    {
			    	if (cellCacheValid[i] == false)
			    	{
			    		// Aenderungen am Hintergrund der Zelle
			    		// erfolgen in setText() und setBackground().

					    cellCacheGC[i].drawString(text[i], 2, cellHeight - 6);
						cellCacheValid[i] = true;
					}
					imageCacheGC.drawImage(cellCache[i], x + 2, y + 2, parent_rechner);

					i++;
					x = x + cellWidth;
				}
				x = 0;
				y = y + cellHeight;
			}

			imageCacheValid = true;
    		g.drawImage(imageCache, 0, 0, parent_rechner);
    	}
    	else
    	// gespeichertes Abbild ist noch gueltig
    	{
    		g.drawImage(imageCache, 0, 0, parent_rechner);
    	}
    	parent.validate();
	}
	
	public void update(Graphics g)
	{
        paint(g);
	}

	public boolean handleEvent(Event event)
	{
        if ( (event.id == Event.MOUSE_DOWN) && (! event.metaDown()) )
        {
        	if (editable)
        	{
	        	//debug System.out.println("EditableTable (" + b.x + "," + b.y + "): MOUSE_DOWN");
    	    	int col = event.x / cellWidth;
        		int row = event.y / cellHeight;
	        	parent.showInputCell(b.x + col*cellWidth, b.y + row*cellHeight - 1, row*numCols + col);
    	    	// Gewollt und sinnvoll, erst durch cellWidth bzw. cellHeight zu teilen,
        		// dann damit mal zu nehmen: Ausrichtung auf Zellenraster.
        	}
        	return super.handleEvent(event);
        }
        else
        	return super.handleEvent(event);

	} /* end handleEvent */

	public Dimension preferredSize()
	{
		return minimumSize();
	}

	public Dimension minimumSize()
	{
		return new Dimension(b.width, b.height);
	}

	public void move(int x1, int y1)
	{
		b = new Rectangle(x1, y1, b.width, b.height);
		super.move(x1, y1);
	}

	public void reshape(int x1, int y1, int w, int h)
	{
		if ((x1 != b.x) || (y1 != b.y))
			b = new Rectangle(x1, y1, w, h);

		if ((w != b.width) || (h != b.height))
			b = new Rectangle(x1, y1, w, h);

		super.reshape(x1, y1, w, h);
	}

	public void resize(int w, int h)
	{
		if ((w != b.width) || (h != b.height))
			b = new Rectangle(b.x, b.y, w, h);

		super.resize(w, h);
	}

	public void resize(Dimension d)
	{
		resize(d.width, d.height);
	}

	public synchronized void setText(int cell, String str)
	{
		if (! text[cell].equals(str))
		{
			cellCacheValid[cell] = false;
			imageCacheValid = false;
			text[cell] = str;
   			cellCacheGC[cell].setColor(background[cell]);
   			cellCacheGC[cell].fillRect(0, 0, cellWidth - 2, cellHeight - 2);
   			cellCacheGC[cell].setColor(foreground[cell]);
		}
	}

	public String getText(int cell)
	{
		return text[cell];
	}

	public synchronized void setFont(Font f)
	{
		if (! font.equals(f))
		{
			for (int i = 0; i < numCells; i++)
			{
				cellCacheValid[i] = false;
				imageCacheValid = false;
				cellCacheGC[i].setFont(f);
			}
			super.setFont(f);
		}
	}

	public synchronized void setForeground(int cell, Color c)
	{
		if ( (foreground[cell].getGreen() != c.getGreen()) ||
		     (foreground[cell].getRed()   != c.getRed()) ||
		     (foreground[cell].getBlue()  != c.getBlue()) )
		{
			cellCacheValid[cell] = false;
			imageCacheValid = false;
			cellCacheGC[cell].setColor(c);
			foreground[cell] = c;
		}
	}

	public synchronized void setBackground(int cell, Color c)
	{
		if ( (background[cell].getGreen() != c.getGreen()) ||
		     (background[cell].getRed()   != c.getRed()) ||
		     (background[cell].getBlue()  != c.getBlue()) )
		{
			cellCacheValid[cell] = false;
			imageCacheValid = false;
			background[cell] = c;
   			cellCacheGC[cell].setColor(background[cell]);
   			cellCacheGC[cell].fillRect(0, 0, cellWidth - 2, cellHeight - 2);
   			cellCacheGC[cell].setColor(foreground[cell]);
		}
	}

	public void setEditable(boolean b)
	{
		editable = b;
		if (editable == false)
			parent.hideInputCell();
	}
	
	public boolean isEditable()
	{
		return editable;
	}

	public Rectangle bounds()
	{
		return  b;
	}

	public Rectangle bounds(int cell)
	// bounding rectangle of a cell
	{
		int row = cell / numCols;
		int col = cell % numCols;
		return new Rectangle(b.x + col*cellWidth, b.y + row*cellHeight, cellWidth, cellHeight);
	}
	
	public int whichCell(Point p)
	// in welcher Zelle liegt dieser Punkt?
	{
    	int col = p.x / cellWidth;
		int row = p.y / cellHeight;
    	return row*numCols + col;
	}
	
	
} /* end EditableTable */
