/*
 * WepsTableDataView.java
 *
 * Created on June 9, 2006, 10:07 AM
 */
package usda.weru.util.table;

import com.klg.jclass.table.EditableTableDataModel;
import com.klg.jclass.table.JCCellDisplayEvent;
import com.klg.jclass.table.JCCellDisplayListener;
import com.klg.jclass.table.JCTableDataEvent;
import com.klg.jclass.table.JCTableDataListener;
import com.klg.jclass.table.TableDataModel;
import com.klg.jclass.table.TableDataView;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

/**
 *
 * @author Joseph Levin
 */
public class WepsTableDataView extends TableDataView implements JCCellDisplayListener, MouseListener {

    private static final long serialVersionUID = 1L;

    private List<String> c_columnKeyMap;
    private boolean quickplot;

    /**
     * Creates a new instance of WepsTableDataView
     */
    public WepsTableDataView() {
        super();
        init();
    }

    /**
     *
     * @param quickplot
     */
    protected void setQuickPlot(boolean quickplot) {
        this.quickplot = quickplot;

    }

    /**
     *
     * @return
     */
    protected boolean isQuickPlot() {
        return quickplot;
    }

    @Override
    public boolean isEditable() {
        return quickplot || super.isEditable();
    }

    private void init() {
    }

    /**
     * Return the index of the Column with the specified key.
     * @param key The key of the desired column.
     * @return The index of the desired Column.
     */
    public int getDataColumnIndex(String key) {
        if (c_columnKeyMap == null) {
            createColumnKeyMap();
        }
        return c_columnKeyMap.indexOf(key);
    }
    
    public String getDataColumnKey(int index)
    {
        if (c_columnKeyMap == null) {
            createColumnKeyMap();
        }
        return c_columnKeyMap.get(index);
    }

    private void createColumnKeyMap() {
        //c_columnKeyMap = new ArrayList <String> ();
        c_columnKeyMap = new Vector<String>();
        for (int i = 0; i < dataSource.getNumColumns(); i++) {
            c_columnKeyMap.add(dataSource.getTableColumnLabel(i).toString());
        }
    }

    /**
     *
     * @param rowIndex
     * @param column
     * @return
     */
    public Object getObject(int rowIndex, Column column) {
        return getObject(rowIndex, column.getId());
    }

    /**
     *
     * @param rowIndex
     * @param key
     * @return
     */
    public Object getObject(int rowIndex, String key) {
        int columnIndex = getDataColumnIndex(key);
        if (columnIndex == -1) {
            return null;
        }
        return super.getObject(rowIndex, columnIndex);
    }

    /**
     *
     * @param rowIndex
     * @param columnIndex
     * @return
     */
    @Override
    public Object getObject(int rowIndex, int columnIndex) {
        if (isQuickPlotRow(rowIndex)) {
            if (columnIndex >= getTable().getFrozenColumns()) {
                int val = getMeta().getColumn(columnIndex).isQuickPlotL() ? 1 :
                        getMeta().getColumn(columnIndex).isQuickPlotR() ? 2 : 0;
                return val;
            } else {
                return null;
            }

        }
//        else if (isQuickPlot()){
//            rowIndex--;
//        }

        if (isLabelRow(rowIndex)) {
            //Move -1 --> 0
            rowIndex = rowIndex + 1;
            return getMeta().getColumnLabel(getTable(), rowIndex, columnIndex);

        }
        if (columnIndex < 0 && rowIndex >= getMeta().getLabelRowCount() - 1) {
            return super.getObject(rowIndex, columnIndex);
        }

        Column column = getMeta().getColumn(getDataColumn(columnIndex));
        if (column == null) {
            return null;
        }
        String dataKey = column.getDataKey();
        columnIndex = getDataColumnIndex(dataKey);
        if (columnIndex == -1) {
            return null;
        }
        return super.getObject(rowIndex, columnIndex);
    }

    /**
     *
     * @param columnIndex
     * @return
     */
    @Override
    public Object getTableColumnLabel(int columnIndex) {
        if (columnIndex < 0) {
            return columnIndex;
        }
        Column column = getMeta().getColumn(columnIndex);
        return column.getName();
    }

    /**
     *
     * @param rowIndex
     * @return
     */
    @Override
    public Object getTableRowLabel(int rowIndex) {
        return rowIndex;
    }

    /**
     *
     * @param model
     */
    @Override
    public void setDataSource(TableDataModel model) {
        synchronized(this)
        {
            TableDataModel wrapped = new DataSourceWrapper(model, this);
            super.setDataSource(wrapped);
        }
        //super.setDataSource(model);
    }

    private WepsTableMeta getMeta() {
        return ((WepsTable) table).getMeta();
    }

    /**
     *
     * @param table
     */
    public void setTable(WepsTable table) {
        if (getTable() != null) {
            table.removeMouseListener(this);
        }
        super.setTable(table);
        table.addCellDisplayListener(this);
        table.addMouseListener(this);
    }

    /**
     *
     * @return
     */
    @Override
    public WepsTable getTable() {
        return (WepsTable) table;
    }

    /**
     *
     * @return
     */
    @Override
    public int getNumColumns() {
        return getMeta().getColumnCount();
    }

    /**
     *
     * @param rowIndex
     * @return
     */
    public boolean isLabelRow(int rowIndex) {
        int numberOfLabelRows = getMeta().getLabelRowCount();
        if (quickplot) {
            numberOfLabelRows++;
        }
        rowIndex = rowIndex + 1;    //-1 --> 0
        return (rowIndex < numberOfLabelRows);
    }

    /**
     *
     * @param rowIndex
     * @return
     */
    public boolean isQuickPlotRow(int rowIndex) {
        return quickplot && rowIndex == getMeta().getLabelRowCount() - 1;
    }

    /**
     *
     * @param event
     */
    @Override
    public void cellDisplay(JCCellDisplayEvent event) {
        prepareCellDisplay(event, WepsTableEnum.PREPARE_all);
    }

    /**
     *
     * @param event
     * @param flags
     */
    public void prepareCellDisplay(JCCellDisplayEvent event, int flags) {
        int rowIndex = event.getRow();
        int columnIndex = event.getColumn();
        String unitsSystem = getTable().getUnitsSystem();
        Object o = event.getCellData();
        if (o instanceof String) {
            o = getMeta().parse((String) o, getTable(), rowIndex, columnIndex);
        }
        if (isLabelRow(rowIndex)) {
            return;
        }

        //Else we actually update the data.
        Column column = getMeta().getColumn(columnIndex);
        if (column == null) {
            return;
        }
        if (Helper.bitFlag(flags, WepsTableEnum.PREPARE_adjustments)) {
            o = column.applyAdjustments(o, unitsSystem);
        }

        if (Helper.bitFlag(flags, WepsTableEnum.PREPARE_displayunits)) {
            o = column.applyDisplayUnits(o, unitsSystem);
        }

        if (Helper.bitFlag(flags, WepsTableEnum.PREPARE_limits)) {
            o = column.applyLimits(o, unitsSystem);
        }

        if (Helper.bitFlag(flags, WepsTableEnum.PREPARE_formats)) {
            o = column.applyFormat(o, unitsSystem);
        }

        event.setDisplayData(o);
    }

    /**
     *
     * @return
     */
    @Override
    public int getNumRows() {
        return getMeta().getLabelRowCount() + super.getNumRows() + (isQuickPlot() ? 0 : -1);
    }

    /**
     *
     * @return
     */
    public String getUnitsSystem() {
        return getTable().getUnitsSystem();
    }

    /**
     *
     */
    protected FilteredDataSource c_filteredDataSource;

    /**
     *
     */
    protected List<ColumnFilter> c_columnFilters;

    /**
     *
     * @param filters
     */
    public void addColumnFilter(ColumnFilter... filters) {
        if (c_columnFilters == null) {
            c_columnFilters = new ArrayList<ColumnFilter>();
        }
        c_columnFilters.addAll(Arrays.asList(filters));
        updateColumnFilters();
    }

    /**
     *
     */
    public void clearColumnFilters() {
        if (c_columnFilters != null) {
            c_columnFilters.clear();
        }
        updateColumnFilters();
    }

    private void updateColumnFilters() {
        for (int ci = 0; ci < getMeta().getColumnCount(); ci++) {
            Column column = getMeta().getColumn(ci);

            if (column.isHidden()) {
                continue;
            }

            boolean status = !getTable().isColumnHidden(ci);
            boolean test = test(column);
            if (test != status) {
                getTable().setColumnHidden(ci, !test);
            }
        }
    }
    
    public List<ColumnFilter> getCurrentFilter()
    {
        return c_columnFilters;
    }

    /**
     *
     * @param column
     * @return
     */
    protected boolean test(Column column) {
        if (c_columnFilters == null || c_columnFilters.isEmpty()) {
            return true;
        }
        for (ColumnFilter filter : c_columnFilters) {
            if (filter.acceptColumn(column)) {
                return true;
            }
        }
        return false;
    }

    /**
     *
     * @param filters
     */
    public void addRowFilter(RowFilter... filters) {
        c_filteredDataSource.addRowFilter(filters);
    }

    /**
     *
     */
    public void clearRowFilters() {
        c_filteredDataSource.clearRowFilters();
    }

    /**
     *
     * @param me
     */
    @Override
    public void mouseClicked(MouseEvent me) {
        if (isQuickPlot() && me.getClickCount() == 1 && me.getButton() == MouseEvent.BUTTON1) {
            // rrow is the "real row" in the table (useful for scrollable region)
            //int rrow = getTable().YtoRow(me.getY() + table.getVertSB().getValue());
            // row is the "displayed row" in the table (which is always the "real row" in the frozen headings)
            int row = getTable().YtoRow(me.getY());
            if (isQuickPlotRow(row)) {
                int column = getTable().XtoColumn(me.getX() + table.getHorizSB().getValue());
                Object value = getObject(row, column);
                if (value instanceof Integer) {
                    int plot = (Integer) value;
                    setTableDataItem(plot, row, column);
                }
            }
        }
    }

    /**
     *
     * @param me
     */
    @Override
    public void mousePressed(MouseEvent me) {

    }

    /**
     *
     * @param me
     */
    @Override
    public void mouseReleased(MouseEvent me) {

    }

    /**
     *
     * @param me
     */
    @Override
    public void mouseEntered(MouseEvent me) {

    }

    /**
     *
     * @param me
     */
    @Override
    public void mouseExited(MouseEvent me) {

    }

    class DataSourceWrapper implements EditableTableDataModel {

        private final TableDataModel c_model;
        List<JCTableDataListener> listeners;
//        private WepsTableDataView c_view;

        /**
         *
         * @param model
         * @param view
         */
        public DataSourceWrapper(TableDataModel model, WepsTableDataView view) {
            if (c_filteredDataSource == null) {
                c_filteredDataSource = new FilteredDataSource(model);
            } else {
                c_filteredDataSource.setDataSource(model);
            }
            listeners = new ArrayList<JCTableDataListener>();
            c_model = c_filteredDataSource;
            //          c_view = view;
        }

        /**
         *
         * @return
         */
        @Override
        public int getNumColumns() {
            return c_model.getNumColumns();
        }

        /**
         *
         * @return
         */
        @Override
        public int getNumRows() {
            return c_model.getNumRows();
        }

        /**
         *
         * @param columnIndex
         * @return
         */
        @Override
        public Object getTableColumnLabel(int columnIndex) {
            return c_model.getTableColumnLabel(columnIndex);
        }

        /**
         *
         * @param rowIndex
         * @param columnIndex
         * @return
         */
        @Override
        public Object getTableDataItem(int rowIndex, int columnIndex) {
            rowIndex = rowIndex - getMeta().getLabelRowCount() + (isQuickPlot() ? 0 : 1);
            return c_model.getTableDataItem(rowIndex, columnIndex);
        }

        @Override
        public boolean setTableDataItem(Object o, int rowIndex, int columnIndex) {
            if (isQuickPlotRow(rowIndex)) {
                int plot = o instanceof Integer ? (Integer) o : 0;
                plot ++;
                plot = plot == 3 ? 0 : plot;
                getMeta().getColumn(columnIndex).setQuickPlot(plot);
                JCTableDataEvent event = null;
                for (JCTableDataListener listener : listeners) {
                    if (event == null) {
                        event = new JCTableDataEvent(this, rowIndex, columnIndex, 1, 0, JCTableDataEvent.CHANGE_VALUE);
                    }
                    listener.dataChanged(event);
                }
                return true;
            }
            rowIndex = rowIndex - (getMeta().getLabelRowCount() - 1);
            if (c_model instanceof EditableTableDataModel) {
                return ((EditableTableDataModel) c_model).setTableDataItem(o, rowIndex, columnIndex);
            } else {
                return false;
            }
        }

        /**
         *
         * @param rowIndex
         * @return
         */
        @Override
        public Object getTableRowLabel(int rowIndex) {
            rowIndex = rowIndex - getMeta().getLabelRowCount() + 1;
            return c_model.getTableRowLabel(rowIndex);
        }

        /**
         *
         * @param listener
         */
        @Override
        public void addTableDataListener(JCTableDataListener listener) {
            c_model.addTableDataListener(listener);
            listeners.add(listener);
        }

        /**
         *
         * @param listener
         */
        @Override
        public void removeTableDataListener(JCTableDataListener listener) {
            c_model.removeTableDataListener(listener);
            listeners.remove(listener);
        }
    }

}
