package cnp.ew.grid;

import java.awt.*;
import java.util.*;

import cnp.ew.displayer.*;
import cnp.ew.converter.*;
import cnp.ew.scrolling.*;
import cnp.ew.util.*;
import cnp.ew.list.*;
import cnp.ew.properties.*;
import java.io.*;
import cnp.ew.lightweight.*;
import cnp.ew.diagram.*;

public class CpGridPane extends CpVariableCellSizeScrollable
{
    static final Color GRIDLINE_COLOR = Color.lightGray;

    static final int FORMAT_STRING_F = 0;
    static final int HORIZONTAL_ALIGNMENT_F = 1;
    static final int VERTICAL_ALIGNMENT_F = 2;
    static final int FORECOLOR_F = 3;
    static final int BACKCOLOR_F = 4;
    static final int FONTNAME_F = 5;
    static final int FONTSIZE_F = 6;
    static final int BOLD_F = 7;
    static final int ITALIC_F = 8;
    static final int WRAP_F = 9;
    static final int TYPE_F = 10;
    static final int BORDER_F = 11;

    static int NUM_SHEETS = 10;

    CpGridModel[] gridModel;
    int curSheet = 0;

    Hashtable[] lcDict;

    // These just store the width or height of the cols/rows, for now
    public Vector[] columns;
    public Vector[] rows;

    Point cursor = new Point(0, 0);
    Point startSelection = new Point(0, 0);
    Point endSelection = new Point(0, 0);

    Point dragSelPoint, dragSelOffset;

    public Dimension defaultCellExtent = new Dimension(80, 17);
    public Dimension sizeInCells;

    String fileName;
    boolean showGrid = true;
    boolean showSelection = true;

    public CpGridPane(Dimension newSizeInCells)
    {
        sizeInCells = newSizeInCells;
        newDocument(null);
    }

    public void newDocument(Object frame)
    {
        enableDamageRepair(false);
        remove((Vector)getChildren().clone()); // SHOULD HAVE removeAllChildren() in abstract lc
        scrollTo(0, 0);
        selectCell(new Point(0, 0), true);
        enableDamageRepair(true);

        curSheet = 0;
        gridModel = new CpGridModel[NUM_SHEETS];
        rows = new Vector[NUM_SHEETS];
        columns = new Vector[NUM_SHEETS];
        lcDict = new Hashtable[NUM_SHEETS];
        newSheet(curSheet);
    }

    public void selectSheet(int index)
    {
        for (Enumeration e = lcDict[curSheet].keys(); e.hasMoreElements() ;) {
            ((CpLightweightComponent)e.nextElement()).hide(true);
        }
        scrollTo(0, 0);
        selectCell(new Point(0, 0), true);

        curSheet = index;
        if (gridModel[index] == null) {
            newSheet(index);
        }
        for (Enumeration e = lcDict[curSheet].keys(); e.hasMoreElements() ;) {
            ((CpLightweightComponent)e.nextElement()).hide(false);
        }
    }

    public void newSheet(int index)
    {
        gridModel[index] = new CpSparseGrid(sizeInCells);
        rows[index] = new Vector();
        columns[index] = new Vector();
        lcDict[index] = new Hashtable();
        for (int r = 0; r < sizeInCells.height; r++) {
            rows[curSheet].addElement(new CpRow(r, defaultCellExtent.height));
        }
        for (int c = 0; c < sizeInCells.width; c++) {
            columns[curSheet].addElement(new CpRowOrColumn(c, defaultCellExtent.width));
        }
        resize(recomputeSize());
    }


    /********************* VARIABLECELLSIZE SCROLLING INFO ******************/

    public Dimension getSizeInCells()
    {
        return sizeInCells;
    }

    public int getCellHeight(int i)
    {
        return getRowHeight(i);
    }

    public int getCellWidth(int i)
    {
        return getColumnWidth(i);
    }

    /******************* GET/SET *************************/

    public CpRowOrColumn getRowOrColumn(Vector rowsOrColumns, int index)
    {
        CpRowOrColumn cr;
        return (CpRowOrColumn)rowsOrColumns.elementAt(index);
    }

    public int getColumnWidth(int i)
    {
        return getRowOrColumn(columns[curSheet], i).getExtent();
    }

    public int getRowHeight(int i)
    {
        return getRowOrColumn(rows[curSheet], i).getExtent();
    }

    public void setColumnWidth(int i, int w)
    {
        getRowOrColumn(columns[curSheet], i).setExtent(w);
    }

    public void setRowHeight(int i, int h)
    {
        getRowOrColumn(rows[curSheet], i).setExtent(h);
    }


    boolean isClose(int i1, int i2)
    {
        int threshold = 3;
        return (Math.abs(i1 - i2) < threshold);
    }

    /************************** EVENTS *************************/

    public void rowOrColumnSelected(int index, boolean isColumn)
    {
        if (isColumn) {
           selectRange(new Point(index, 0), new Point(index, sizeInCells.height - 1), new Point(index, 0), true);
        } else {
           selectRange(new Point(0, index), new Point(sizeInCells.width - 1, index), new Point(0, index), true);
        }
    }

    public void rowOrColumnSized(int index, boolean isColumn)
    {
        enableDamageRepair(false);
        for (Enumeration e = lcDict[curSheet].keys(); e.hasMoreElements() ;) {
            CpLightweightComponent lc = (CpLightweightComponent)e.nextElement();
            Point p = (Point)lcDict[curSheet].get(lc);
            lc.reshape(cellToPoint(p).x, cellToPoint(p).y, getColumnWidth(p.x) - 1, getRowHeight(p.y) - 1);
        }
        enableDamageRepair(true);
        // Must check for any lcs to resize
        repaint();
    }

	public boolean mouseDown(Event e, int x, int y)
	{
	    Point selectionTopLeft = cellToPoint(startSelection);
	    Point selectionBottomRight = cellToPoint(endSelection);
	    if (isClose(y, selectionTopLeft.y) & ((x > selectionTopLeft.x) & (x < selectionBottomRight.x))) {
	        dragSelPoint = startSelection;
	        dragSelOffset = new Point(endSelection.x - startSelection.x + 1, endSelection.y - startSelection.y + 1);
	        drawXORRect(startSelection, dragSelOffset);
	        return true;
	    }
	    Point temp = pointToCell(x, y);
	    if (temp.x >= sizeInCells.width || temp.y >= sizeInCells.height) {
	        return true;
	    }
	    selectCell(temp, false);
	    return true;
	}

    void drawXORRect(Point cell, Point offset)
    {
        Point glob = getScroller().locationGlobal();
        Graphics g = getComponent().getGraphics();
        g.setColor(Color.white);
        g.setXORMode(Color.black);
        Point p = cellToPoint(cell);
        Point p2 = cellToPoint(new Point(cell.x + offset.x, cell.y + offset.y));
        g.drawRect(p.x, p.y, p2.x - p.x, p2.y - p.y);
        g.setPaintMode();
        g.dispose();
    }

	public boolean mouseDrag(Event e, int x, int y)
	{
	    Point cellHit = pointToCell(x, y);
	    if (cellHit.x >= sizeInCells.width || cellHit.y >= sizeInCells.height) {
	        return true;
	    }

	    if (dragSelPoint != null) {  // Moving cells around
	        if (cellHit != dragSelPoint) {
	            drawXORRect(dragSelPoint, dragSelOffset);
	            dragSelPoint = cellHit;
	            drawXORRect(dragSelPoint, dragSelOffset);
	        }
	        return true;
	    }

        selectRange(cursor, cellHit, cursor, false);
	    return true;
	}

	public boolean mouseUp(Event e, int x, int y)
	{
	    if (dragSelPoint != null) {  // Moving cells around
	        drawXORRect(dragSelPoint, dragSelOffset);
	        dragSelPoint = null;
	        return true;
	    }

	    notifyObservers(CpEvent.GRID_SELECTION_CHANGED, gridModel[curSheet].getCell(cursor));
	    return true;
	}

    public void moveSelectionRight()
    {
        if (cursor.x < sizeInCells.width - 1) {
            selectCell(new Point(cursor.x + 1, cursor.y), true);
        }
    }

    public void moveSelectionLeft()
    {
        if (cursor.x > 0) {
            selectCell(new Point(cursor.x - 1, cursor.y), true);
        }
    }

    public void moveSelectionDown()
    {
        if (cursor.y < sizeInCells.height - 1) {
            selectCell(new Point(cursor.x, cursor.y + 1), true);
        }
    }

    public void moveSelectionUp()
    {
        if (cursor.y > 0) {
            selectCell(new Point(cursor.x, cursor.y - 1), true);
        }
    }

    /*************************** SELECTION ***********************/

	void normalizeSelection(Point p1, Point p2)
	{
	    int x = Math.min(p1.x, p2.x);
	    int x2 = Math.max(p1.x, p2.x);
	    int y = Math.min(p1.y, p2.y);
	    int y2 = Math.max(p1.y, p2.y);
	    startSelection = new Point(x, y);
	    endSelection = new Point(x2, y2);
	}

	public void selectCell(Point p, boolean notify)
	{
	    selectRange(p, p, p, notify);
	}

	public void selectRange(Point p1, Point p2, Point newCursor, boolean notify)
	{
	    Point oldStart = startSelection;
	    Point oldEnd = endSelection;
	    normalizeSelection(p1, p2);
	    if (!((cursor.equals(newCursor)) && (oldStart.equals(startSelection)) && (oldEnd.equals(endSelection)))) {
		    if (gridModel[curSheet].getCell(cursor).inEditMode()) {
		        notifyObservers(CpEvent.GRID_END_EDIT, cursor);
		    }
		    cursor = newCursor;
		    if (notify) {
	            notifyObservers(CpEvent.GRID_SELECTION_CHANGED, gridModel[curSheet].getCell(cursor));
    	    }
	        invalidateRange(oldStart, oldEnd);
	        invalidateRange(startSelection, endSelection);
	        repairDamage();
	    }
	}

    boolean inSelection(int x, int y)
    {
        return ((x >= startSelection.x) & (x <= endSelection.x)) &
            ((y >= startSelection.y) & (y <= endSelection.y)) && !(cursor.x == x && cursor.y == y);
    }

    public Point getSelectionStart()
    {
        return startSelection;
    }

    public Point getSelectionEnd()
    {
        return endSelection;
    }

    public CpGridCell getSelectedCell()
    {
        return gridModel[curSheet].getCell(cursor);
    }

	public String getStringForCell(Point p)
	{
	    return CpRowOrColumn.intToLetters(p.x) + (new Integer(p.y + 1)).toString();
	}

    /**************** GET/SET CELL VALUES ********************/

    /*********** These are sent to programmatically access the grid (like the chart adapter) ****/

    public void toggleGrid()
    {
        showGrid = !showGrid;
        repaint();
    }

    public void showSelection(boolean bool)
    {
        showSelection = bool;
        repaint();
    }

    public void insertSumFunction()
    {
        int endY = -1, startY = 0;
        boolean foundEnd = false;
        for (int i = cursor.y; i >= 0; i--) {
            if (!foundEnd) {
                if (gridModel[curSheet].getCell(cursor.x, i).getObject() != null) {
                    foundEnd = true;
                    endY = i;
                }
            } else {
                if (gridModel[curSheet].getCell(cursor.x, i).getObject() == null) {
                    startY = i + 1;
                    break;
                }
            }
        }
        if (endY > 0) {
            setObjectAsString(cursor, "=sum(" + CpRowOrColumn.intToLetters(cursor.x) + "" + (startY + 1) + ":" + CpRowOrColumn.intToLetters(cursor.x) + "" + (endY + 1) + ")");
        }
    }

    public void sortRows(int sortOrder)
    {
        boolean sortUp = (sortOrder == CpSortable.ASCENDING);
        for (int i = startSelection.y; i <= (endSelection.y - 1); i++) {
            Double maxItem = (Double)gridModel[curSheet].getCell(cursor.x, i).getObject();
            int maxIndex = i;
            for (int j = i + 1; j <= endSelection.y; j++) {
                boolean bigger = maxItem.doubleValue() < ((Double)gridModel[curSheet].getCell(cursor.x, j).getObject()).doubleValue();
                if (sortUp) {
                    bigger = !bigger;
                }
                if (bigger) {
                    maxIndex = j;
                    maxItem = (Double)gridModel[curSheet].getCell(cursor.x, j).getObject();
                }
            }
            Double temp = (Double)gridModel[curSheet].getCell(cursor.x, i).getObject();
            gridModel[curSheet].getCell(cursor.x, i).setObjectAndType(maxItem, CpBasicType.NUMBER, gridModel[curSheet]);
            gridModel[curSheet].getCell(cursor.x, maxIndex).setObjectAndType(temp, CpBasicType.NUMBER, gridModel[curSheet]);
        }
        repaint();
    }


    public void insertLc(CpLightweightComponent lc)
    {
        lc.reshape(cellToPoint(cursor).x, cellToPoint(cursor).y, getColumnWidth(cursor.x) - 1, getRowHeight(cursor.y) - 1);
        add(lc);
        lcDict[curSheet].put(lc, cursor);
    }

    public void setObjectAsString(Point p, String value)
    {
        gridModel[curSheet].getCell(p).setObjectAsString(value, gridModel[curSheet]);
        // Maybe not right, but we dont know how many cells were affected by the change
        repaint();
    }

    public void setObjectAndType(Point p, Object o, CpType type)
    {
        gridModel[curSheet].getCell(p).setObjectAndType(o, type, gridModel[curSheet]);
    }

    public Object getObject(Point p)
    {
        return gridModel[curSheet].getCell(p).getObject();
    }

	public String getObjectAsString(Point p)
	{
	    return gridModel[curSheet].getCell(p).getObjectAsString();
	}

	// FORMATTING APIs    They all look familiar

    public void setType(CpType type)
    {
        setProperty(TYPE_F, startSelection, endSelection, type, 0, false);
    }

	public void setFormatString(String format)
	{
        setProperty(FORMAT_STRING_F, startSelection, endSelection, format, 0, false);
    }

    public void setHorizontalAlignment(int alignment)
    {
        setProperty(HORIZONTAL_ALIGNMENT_F, startSelection, endSelection, null, alignment, false);
    }

    public void setVerticalAlignment(int alignment)
    {
        setProperty(VERTICAL_ALIGNMENT_F, startSelection, endSelection, null, alignment, false);
    }

    public void setForecolor(Color color)
    {
        setProperty(FORECOLOR_F, startSelection, endSelection, color, 0, false);
    }

    public void setBackcolor(Color color)
    {
        setProperty(BACKCOLOR_F, startSelection, endSelection, color, 0, false);
    }

    public void setShouldWrap(boolean bool)
    {
        setProperty(WRAP_F, startSelection, endSelection, null, 0, bool);
    }

	public void setFontName(String name)
	{
        setProperty(FONTNAME_F, startSelection, endSelection, name, 0, false);
    }

    public void setFontSize(int size)
    {
        setProperty(FONTSIZE_F, startSelection, endSelection, null, size, false);
    }

    public void setBold(boolean bool)
    {
        setProperty(BOLD_F, startSelection, endSelection, null, 0, bool);
    }

    public void setItalic(boolean bool)
    {
        setProperty(ITALIC_F, startSelection, endSelection, null, 0, bool);
    }

    public void setBorderType(int borderType)
    {
        if (borderType == CpGridCell.OUTLINE_BORDER || borderType == CpGridCell.THICK_OUTLINE_BORDER) {
            int thickness = 1;
            if (borderType == CpGridCell.THICK_OUTLINE_BORDER) {
                thickness = 3;
            }
            for (int row = startSelection.y; row <= endSelection.y; row++) {
                for (int col = startSelection.x; col <= endSelection.x; col++) {
                    if (col == startSelection.x) {
                        gridModel[curSheet].getCell(col, row).setBorder(CpGridBorderDisplayer.LEFT, thickness, this);
                    }
                    if (col == endSelection.x) {
                        gridModel[curSheet].getCell(col, row).setBorder(CpGridBorderDisplayer.RIGHT, thickness, this);
                    }
                    if (row == startSelection.y) {
                        gridModel[curSheet].getCell(col, row).setBorder(CpGridBorderDisplayer.TOP, thickness, this);
                    }
                    if (row == endSelection.y) {
                        gridModel[curSheet].getCell(col, row).setBorder(CpGridBorderDisplayer.BOTTOM, thickness, this);
                    }
                }
            }
            invalidateRange(startSelection, endSelection);
            repairDamage();
        } else {
            setProperty(BORDER_F, startSelection, endSelection, null, borderType, false);
        }
    }

    // VERY UGLY.  BUT ALL BECAUSE I CANNOT PASS FUNCTIONS!!!!!
    public void setProperty(int function, Point start, Point end, Object arg, int intArg, boolean boolArg)
    {
        for (int row = start.y; row <= end.y; row++) {
            for (int col = start.x; col <= end.x; col++) {
                switch (function) {
                    case TYPE_F : gridModel[curSheet].getCell(new Point(col, row)).setType((CpType)arg, gridModel[curSheet]); break;
                    case FORMAT_STRING_F : gridModel[curSheet].getCell(new Point(col, row)).setFormatString((String)arg); break;
                    case HORIZONTAL_ALIGNMENT_F : gridModel[curSheet].getCell(new Point(col, row)).setHorizontalAlignment(intArg); break;
                    case VERTICAL_ALIGNMENT_F : gridModel[curSheet].getCell(new Point(col, row)).setVerticalAlignment(intArg); break;
                    case FORECOLOR_F : gridModel[curSheet].getCell(new Point(col, row)).setForecolor((Color)arg); break;
                    case BACKCOLOR_F : gridModel[curSheet].getCell(new Point(col, row)).setBackcolor((Color)arg); break;
                    case FONTNAME_F : gridModel[curSheet].getCell(new Point(col, row)).setFontName((String)arg); break;
                    case FONTSIZE_F : gridModel[curSheet].getCell(new Point(col, row)).setFontSize(intArg); break;
                    case BOLD_F : gridModel[curSheet].getCell(new Point(col, row)).setBold(boolArg); break;
                    case ITALIC_F : gridModel[curSheet].getCell(new Point(col, row)).setItalic(boolArg); break;
                    case WRAP_F : gridModel[curSheet].getCell(new Point(col, row)).setShouldWrap(boolArg); break;
                    case BORDER_F : gridModel[curSheet].getCell(new Point(col, row)).setBorderType(intArg); break;
                }
            }
        }
        invalidateRange(startSelection, endSelection);
        repairDamage();
    }

    /**************** These are sent by the gridLc based on the entry field needs  ****/

    public void acceptText()
    {
        gridModel[curSheet].getCell(cursor).acceptText(gridModel[curSheet]);
        notifyObservers(CpEvent.GRID_END_EDIT, cursor);
        // Maybe not right, but we dont know how many cells were affected by the change
        repaint();
    }

	void setStringBeingEdited(String s)
	{
	    gridModel[curSheet].getCell(cursor).setStringBeingEdited(s);
	    invalidateRange(cursor, cursor);
	    repairDamage();
    }

	public String getTextForEditing()
	{
	    return gridModel[curSheet].getCell(cursor).getTextForEditing();
	}



    /*************************** PAINTING **********************************/

	void invalidateRange(Point p1, Point p2)
	{
	    Point pixelPoint1 = cellToPoint(p1);
	    Point pixelPoint2 = cellToPoint(new Point(p2.x + 1, p2.y + 1));
	    // Leave room for the Excel style selection rect
	    damage(new Rectangle(pixelPoint1.x - 3, pixelPoint1.y - 3, pixelPoint2.x - pixelPoint1.x + 6, pixelPoint2.y - pixelPoint1.y + 6));
	}

    public void paint(Graphics g, Rectangle clipRect)
    {
        Point firstCell = pointToCell(clipRect.x, clipRect.y);
        firstCell = new Point(Math.min(firstCell.x, sizeInCells.width - 1), Math.min(firstCell.y, sizeInCells.height - 1));

        //System.out.println("Firstcell = " + firstCell);
        Point firstPixelPoint = cellToPoint(firstCell);
        //System.out.println("Firstpixel = " + firstPixelPoint);

        g.setColor(getBackground());
        g.fillRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);

        int x, y;
        // Draw Grid Lines...
        if (showGrid) {
    		g.setColor(GRIDLINE_COLOR);
    		x = firstPixelPoint.x - 1; // Since lines draw outside their pixel
    		for (int i = firstCell.x; x <= clipRect.x + clipRect.width; i++)
    		{
    		    if (i >= sizeInCells.width) {
    		        g.fillRect(x + 1, clipRect.y, (clipRect.x - x) + clipRect.width, clipRect.height);
    		        g.setColor(Color.gray);
    		        g.drawLine(x, clipRect.y, x, clipRect.y + clipRect.height);
    		        break;
    		    }
    		    x += getColumnWidth(i);
    		    g.drawLine(x, clipRect.y, x, clipRect.y + clipRect.height);
    		}
    		g.setColor(GRIDLINE_COLOR);
    		y = firstPixelPoint.y - 1;  // Since lines draw outside their pixel
    		for (int i = firstCell.y; y <= clipRect.y + clipRect.height; i++)
    		{
    		    if (i >= sizeInCells.height) {
    		        g.fillRect(clipRect.x, y + 1, clipRect.width, (clipRect.y - y) + clipRect.height);
    		        g.setColor(Color.gray);
    		        g.drawLine(clipRect.x, y, x, y);
    		        break;
    		    }
    		    y += getRowHeight(i);
    		    g.drawLine(clipRect.x, y, clipRect.x + clipRect.width, y);
    		}
    	}

        if (showSelection) {
            paintSelection(g);
        }

        y = firstPixelPoint.y;
        Vector row;
        for (int r = firstCell.y; r < sizeInCells.height; r++) {
	        int h = getRowHeight(r);
            x = firstPixelPoint.x;
            CpGridCell cell;
            if (y >= clipRect.y + clipRect.height) {
                return;
            }
            for (int c = firstCell.x; c < sizeInCells.width; c++) {
                int w = getColumnWidth(c);
	            cell = gridModel[curSheet].getCell(new Point(c, r));
                if (x >= clipRect.x + clipRect.width) {
                    break;
                }
	           // THE -1 IS VERY BAD...
                cell.paintIn(this, g, x - 1, y - 1, w + 1, h + 1, inSelection(c, r));
                x += w;
            }
	        y += h;
        }
    }

    protected void paintSelection(Graphics g)
    {

		// Draw Selection Rect
		g.setColor(Color.black);
		g.setXORMode(Color.white);
		Point selTopLeft = cellToPoint(startSelection);
		Point selBottomRight = cellToPoint(endSelection);
		Point cursorPoint = cellToPoint(cursor);
		int selRectLeft = selTopLeft.x - 1;
		int selRectTop = selTopLeft.y - 1;
		int selRectRight = selBottomRight.x + getColumnWidth(endSelection.x) - 1;
		int selRectBottom = selBottomRight.y + getRowHeight(endSelection.y) - 1;
		int selRectWidth = selRectRight - selRectLeft + 1;
		int selRectHeight = selRectBottom - selRectTop + 1;

        g.fillRect(selRectLeft - 1, selRectTop - 1, selRectWidth + 2, selRectHeight + 2);
        g.setPaintMode();

        g.setColor(Color.white);
        g.fillRect(cursorPoint.x + 1, cursorPoint.y + 1, getColumnWidth(cursor.x) - 3, getRowHeight(cursor.y) - 3);
        g.drawRect(selRectLeft + 2, selRectTop + 2, selRectWidth - 5, selRectHeight - 5);
        g.drawRect(selRectRight - 3, selRectBottom - 3, 6, 6);
        g.setColor(Color.black);
        g.fillRect(selRectRight - 2, selRectBottom - 2, 5, 5);

    /*    // Fill the area in black
		g.fillRect(selRectLeft + 3, selRectTop + 3, selRectWidth - 5, selRectHeight - 5);

        // Draw two black lines around selected rect
		g.drawRect(selRectLeft - 1, selRectTop - 1, selRectWidth + 2, selRectHeight + 2);
		g.drawRect(selRectLeft + 1, selRectTop + 1, selRectWidth - 2, selRectHeight - 2);
		selBottomRight = new Point(selRectWidth + selTopLeft.x, selRectHeight + selTopLeft.y);

        // Invert a white area for the cursor cell
		selTopLeft = cellToPoint(cursor);
		int left = 2;
		int top = 2;
		int w = 4;
		int h = 4;
		if (cursor.x == startSelection.x) { left = 3; }
		if (cursor.y == startSelection.y) { top = 3; }
		if (cursor.x == endSelection.x) { w = 5; }
		if (cursor.y == endSelection.y) { h = 5; }
		g.fillRect(selTopLeft.x + left, selTopLeft.y + top, getColumnWidth(cursor.x) - w, getRowHeight(cursor.y) - h);

        // Draw the little sizing dot at bottom right of selection
        g.setPaintMode();
        g.setColor(Color.white);
		g.drawRect(selBottomRight.x - 3, selBottomRight.y - 3, 5, 5);
        g.setColor(Color.black);
		g.fillRect(selBottomRight.x - 2, selBottomRight.y - 2, 5, 5);
		g.setColor(Color.lightGray);
		g.drawLine(selBottomRight.x, selBottomRight.y - 3, selBottomRight.x, selBottomRight.y + 3);
		g.drawLine(selBottomRight.x - 3, selBottomRight.y, selBottomRight.x + 3, selBottomRight.y);
		*/
    }
    /************************** FILE SAVE/OPEN *****************************/

   public void menuOpen(Frame frame) throws IOException
    {
        FileDialog dialog = new FileDialog(frame, "Open", FileDialog.LOAD);
        dialog.show();
        fileName = dialog.getFile();
        frame.setTitle("JavaSheet - " + fileName);
        RandomAccessFile file = new RandomAccessFile(fileName, "rw");
        file.seek(0);

        columns[curSheet] = new Vector();
        int size = file.readInt();
     //   System.out.println("size of columns = " + size);
        for (int i = 0; i < size; i++) {
            columns[curSheet].addElement(new CpRowOrColumn(i, file.readInt()));
        }
        rows[curSheet] = new Vector();
        size = file.readInt();
     //   System.out.println("size of rows = " + size);
        for (int i = 0; i < size; i++) {
            rows[curSheet].addElement(new CpRowOrColumn(i, file.readInt()));
        }
        gridModel[curSheet] = new CpSparseGrid(file);
        file.close();
        repaint();
    }

    public void menuSave(Frame frame) throws IOException
    {
        if (fileName == null) {
            menuSaveAs(frame);
        }
        save();
    }

    public void menuSaveAs(Frame frame) throws IOException
    {
        FileDialog dialog = new FileDialog(frame, "Save As", FileDialog.SAVE);
        dialog.show();
        if (dialog.getFile() != null) {
            fileName = dialog.getFile().substring(0, dialog.getFile().length() - 4); // Stupid thing puts *.* on the end...
            frame.setTitle(fileName);
            save();
        }
    }

    void save() throws IOException
    {
        RandomAccessFile file = new RandomAccessFile(fileName, "rw");

        //System.out.println("Saving GridPane");
        file.writeInt(columns[curSheet].size());
        for (int i = 0; i < columns[curSheet].size(); i++) {
            file.writeInt(((CpRowOrColumn)columns[curSheet].elementAt(i)).getExtent());
        }
        file.writeInt(rows[curSheet].size());
        for (int i = 0; i < rows[curSheet].size(); i++) {
            file.writeInt(((CpRowOrColumn)rows[curSheet].elementAt(i)).getExtent());
        }
        gridModel[curSheet].writeTo(file);
        file.close();
    }

}

