package cnp.ew.list;

import java.awt.*;
import java.util.*;
import cnp.ew.util.*;
import cnp.ew.displayer.*;
import cnp.ew.converter.*;
import cnp.ew.properties.*;
import cnp.ew.lightweight.*;

    /* Note:  In a columnar list presenter model, the displayer must not be null.  If someone
        wants a null displayer, they should just use a regular ListBox  */

public class CpColumnarListPane extends CpListPane
{
    Vector columnModels = new Vector();
    CpColumnModel columnBeingEdited;
    boolean cellSelect;

    public void setColumnModels(Vector newColumnModels)
    {
        columnModels = newColumnModels;
    }

    void recomputeSize()
    {
        Dimension newSize = new Dimension(getWidth(), listModel.getSize() * getCellSize().height);
        if (newSize.height != size().height || newSize.width != size().width) {
            resize(new Dimension(getWidth(), listModel.getSize() * getCellSize().height));
            getScroller().scrollableSized();
        }
    }
    public int getWidth()
    {
        int width = 0;
        for (int columnIndex = 0; columnIndex < columnModels.size(); columnIndex++) {
            CpColumnModel column = (CpColumnModel)columnModels.elementAt(columnIndex);
            width += column.getExtent();
        }
        return Math.max(width, getScroller().size().width);
    }

    public void update(CpObservable o, int facet, Object arg)
    {
        switch (facet) {
            case CpEvent.COLUMN_SIZED : {
                if (indexBeingEdited >= 0) {
                    enableDamageRepair(false);
                    editor.reshape(getEditorRect(editor, indexBeingEdited, columnBeingEdited));
                    enableDamageRepair(true);
                }
                recomputeSize();
                repaint();
                break;
            }
            case CpEvent.COLUMN_SELECTED : {
                removeEditor();
                sortColumn(((Integer)arg).intValue());
                break;
            }
        }
        super.update(o, facet, arg);
    }

    void sortColumn(int columnId)
    {
        CpColumnModel column = (CpColumnModel)columnModels.elementAt(columnId);
        boolean sortUp = column.sortAscending;
        column.sortAscending = !column.sortAscending;
        for (int i = 0; i < (listModel.getSize() - 1); i++) {
            CpListItem maxItem = (CpListItem)listModel.getItem(i);
            int maxIndex = i;
            for (int j = i + 1; j < listModel.getSize(); j++) {
                boolean bigger = maxItem.isLessThan((CpListItem)listModel.getItem(j), column.getProperty());
                if (sortUp) {
                    bigger = !bigger;
                }
                if (bigger) {
                    maxIndex = j;
                    maxItem = (CpListItem)listModel.getItem(j);
                }
            }
            CpListItem temp = (CpListItem)listModel.getItem(i);
            listModel.setItem(i, maxItem);
            listModel.setItem(maxIndex, temp);

        }
        repaint();
    }

    public void setCellSelect(boolean bool)
    {
        cellSelect = bool;
    }

    public void paintItemIn(int i, Graphics g, int x, int y, int w, int h)
    {
        CpModelSelectableDisplayable tempDisplayer;
        CpToStringConverter tempConverter;
        CpColumnModel column;
        int curX = 0;
        int columnWidth;

        if (listModel == null) {
            return;
        }
        if (cellSelect && selectionModel.isSelected(i)) {
            Rectangle visibleRect = getVisibleRect();
            g.setColor(new Color(0, 0, 128));
            g.fillRect(visibleRect.x, y, visibleRect.width, h);
            if (shouldShowFocusForIndex(i)) {
                CpFocusRect.drawFocusRect(g, visibleRect.x, y, visibleRect.width, h, CpFocusRect.yellowFocusColor);
            }
        }
        for (int columnIndex = 0; columnIndex < columnModels.size(); columnIndex++) {
            column = (CpColumnModel)columnModels.elementAt(columnIndex);
            columnWidth = column.getExtent();


            if ((curX + columnWidth > x) && (curX < x + w)) {   // Only draw if that column is in the cliprect
                Object model;
                if (i >= listModel.getSize()) {
                    model = null;
                } else {
                    model = listModel.getProperty(i, column.getProperty());
                }
                if (column.displayer == null) {
                    if (displayer == null) {
                        if (listModel.getDisplayer(i, column.getProperty()) == null) {
                            tempDisplayer = (CpModelSelectableDisplayable)model;
                            tempDisplayer.setIsSelected(selectionModel.isSelected(i));
                            setShowFocusIfNecessary(tempDisplayer, i);
                            tempDisplayer.paintIn(this, g, curX, y, columnWidth, h);
                            curX += columnWidth;
                            continue;
                        } else {
                            tempDisplayer = listModel.getDisplayer(i, column.getProperty());
                        }
                    } else {
                        tempDisplayer = displayer;
                    }
                } else {
                    tempDisplayer = column.displayer;
                }

                if (column.converter == null) {
                    if (converter == null) {
                        // Ted commented out.  Added this functionality in constructor of columnModel, which sets the converter based on the default
                       // if (listModel.getConverter(i, column.getProperty()) == null) {
                            tempConverter = null;
                       // } else {
                      //      tempConverter = listModel.getConverter(i, column.getProperty());
                       // }
                    } else {
                        tempConverter = converter;
                    }
                } else {
                    tempConverter = column.converter;
                }

                setupDisplayer(i, tempDisplayer); // This is subclassed in treeLPM to set indentLevel, etc.  KINda weird.

                if (tempConverter == null) {
                    tempDisplayer.setModel(model);
                } else {
                    tempDisplayer.setModel(tempConverter.convert(model));
                }

                if (!cellSelect) {
                    setShowFocusIfNecessary(tempDisplayer, i);
                }

                tempDisplayer.setIsSelected(selectionModel.isSelected(i));
                // If editing don't draw
            //    if (!(column == columnBeingEdited && i == indexBeingEdited)) {
                    tempDisplayer.paintIn(this, g, curX, y, columnWidth, h);
            //    }
            }
            curX += columnWidth;
        }
    }

    public void setupDisplayer(int index, CpModelSelectableDisplayable tempDisplayer)
    {
        // This is subclassed in treeLPM to set indentLevel, etc.  KINda weird.
    }

    public String textFor(int i)
    {
        CpColumnModel column;

        for (int columnIndex = 0; columnIndex < columnModels.size(); columnIndex++) {
            column = (CpColumnModel)columnModels.elementAt(columnIndex);
            if (column.getIsKeyboardMatchText()) {
                return column.converter.convert(listModel.getProperty(i, column.getProperty()));
            }
        }
        return null;
    }

    public Rectangle getEditorRect(CpEditor e, int index, CpColumnModel column)
    {
        int editorY = cellToPoint(0, index).y;
        Dimension editorPreferred = editor.preferredSize();
        // center vert
        editorY += (getCellHeight(index) - Math.max(editorPreferred.height, getCellHeight(index))) / 2;
    //    editorY -= 4;
        int editorX = xForColumn(column) ;

        ((CpAbstractLc)e).setBorderStyle(BORDER_LINE);
        e.setHorizontalAlignment(column.getAlignment());
        e.setVerticalAlignment(CpAlignable.ALIGN_CENTER);
/*        if (column.getAlignment() == CpAlignable.ALIGN_RIGHT) {
            editorX = editorX + column.getExtent() - editorPreferred.width;
        }
        if (column.getAlignment() == CpAlignable.ALIGN_CENTER) {
            editorX = editorX + (column.getExtent() - editorPreferred.width / 2);
        }
        */
        return new Rectangle(editorX, editorY, column.getExtent() /*editorPreferred.width*/, Math.max(editorPreferred.height, getCellHeight(index)));
    }

    public void removeEditor()
    {
        if (indexBeingEdited >= 0) {
            listModel.setProperty(indexBeingEdited, columnBeingEdited.getProperty(), editor.getObject());
            notifyObservers(CpEvent.LIST_ITEM_EDITED, editor.getObject());
            remove(editor);
            indexBeingEdited = -1;
            columnBeingEdited = null;
            repaint();
        }
    }

    public void select(int index, CpColumnModel column, int modifiers)
    {
        if (indexBeingEdited == index && columnBeingEdited != column) {
            removeEditor();
        }
     //   System.out.println("selected = " + selectionModel.isSelected(index) + " isEditable = " + column.isEditable + " ed is Null = " + (column.editor == null));
        if (selectionModel.isSelected(index) && column.isEditable && column.editor != null && (modifiers == CpSelectionModel.NORMAL_SELECT)) {
          //  System.out.println("column = " + column.title + " + editor = " + column.editor);
            editor = column.editor;
            editor.setObject(listModel.getProperty(index, column.getProperty()));
            editor.reshape(getEditorRect(editor, index, column));
            indexBeingEdited = index;
            columnBeingEdited = column;
            damageLine(index);
            add(editor);
            editor.requestFocus();
        } else {
            removeEditor();
            selectionModel.select(index, modifiers);
        }
    }

    public void itemHit(int index, int modifiers, int x)
    {
        if (index < 0 || index >= listModel.getSize()) {
            return;
        }

        columnForX(x).itemHit(this, index, modifiers, x);
    }

    CpColumnModel columnForX(int x)
    {
        CpColumnModel column;
        int curX = 0;
        for (int columnIndex = 0; columnIndex < columnModels.size(); columnIndex++) {
            column = (CpColumnModel)columnModels.elementAt(columnIndex);
            if (x < curX + column.getExtent()) {
                return column;
            }
            curX += column.getExtent();
        }
        return null;
    }

    int xForColumn(CpColumnModel column)
    {
        CpColumnModel c;
        int curX = 0;
        for (int i = 0; i < columnModels.size(); i++) {
            c = (CpColumnModel)columnModels.elementAt(i);
            if (column == c) {
                return curX;
            }
            curX += c.getExtent();
        }
        return curX;
    }
}

