/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : TableForInputInterface.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */
package ciss.phase_viewer.primitiveguis.tableforinputinterface;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.text.DecimalFormat;
import java.util.EventListener;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import org.apache.log4j.Logger;

import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.common.CheckBoxTableCellRenderer;
import ciss.phase_viewer.common.Command;
import ciss.phase_viewer.common.ConstParameters;
import ciss.phase_viewer.common.ExcelAdapter;
import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.inputinterface.InputInterfaceEntryChangeListener;
import ciss.phase_viewer.inputinterface.inputinterfacetable.InputInterfaceTableColumns;
import ciss.phase_viewer.inputinterface.inputinterfacetable.InputInterfaceTableSpec;
import ciss.phase_viewer.inputinterface.inputinterfacetable.InputInterfaceTableSpecManager;
import ciss.phase_viewer.inputinterface.inputinterfacetable.RightClickItems;
import ciss.phase_viewer.primitiveguis.ToolTippedCombo;

public class TableForInputInterface extends JTable implements ItemListener,
        ActionListener, CaretListener, PopupMenuListener {
    private static Logger logger = Logger
            .getLogger(TableForInputInterface.class.getName());

    private String[] idents;
    private Vector tableData;

    private String[] inputSpecifications;
    private InputInterface inputInterface;
    private InputInterfaceTableSpecManager manager;
    private InputInterfaceTableSpec tableSpec;
    private InputInterfaceTableColumns[] tableCols;
    private int[] mapSpecCol;
    private EventListener eventListener;

    private JPanel panel;

    private CheckBoxTable cbtable;

    private DecimalFormat formater = ciss.phase_viewer.common.ConstParameters.formater;

    private boolean non_tabular = false;
    private boolean row_oriented = false;
    private String[] row_oriented_columns;

    private int columnIndex = 0;

    private AtomCoords coords;

    public TableForInputInterface(String[] inputSpecifications,
            InputInterface inputInterface, int[] mapSpecCol,
            EventListener eventListener) {
        super();
        this.inputSpecifications = inputSpecifications;
        this.inputInterface = inputInterface;
        this.mapSpecCol = mapSpecCol;
        this.eventListener = eventListener;
        this.columnIndex = 0;

        init();
        createAll();
    }

    public TableForInputInterface(AtomCoords coords,
            String[] inputSpecifications, InputInterface inputInterface,
            int[] mapSpecCol, EventListener eventListener) {
        super();
        this.coords = coords;
        this.inputSpecifications = inputSpecifications;
        this.inputInterface = inputInterface;
        this.mapSpecCol = mapSpecCol;
        this.eventListener = eventListener;
        this.columnIndex = 0;

        init();
        createAll();
    }

    public TableForInputInterface(String[] inputSpecifications,
            InputInterface inputInterface, EventListener eventListener) {
        super();
        this.inputSpecifications = inputSpecifications;
        this.inputInterface = inputInterface;
        this.eventListener = eventListener;
        this.columnIndex = 0;

        init();
        createAll();
    }

    public TableForInputInterface(String[] inputSpecifications,
            InputInterface inputInterface, int[] mapSpecCol,
            EventListener eventListener, int columnIndex) {
        super();
        this.inputSpecifications = inputSpecifications;
        this.inputInterface = inputInterface;
        this.mapSpecCol = mapSpecCol;
        this.eventListener = eventListener;
        this.columnIndex = columnIndex;

        init();
        createAll();
    }

    private Font cellFont;

    public TableForInputInterface(String[] inputSpecifications,
            InputInterface inputInterface, int[] mapSpecCol,
            EventListener eventListener, int columnIndex, java.awt.Font cellFont) {
        super();
        this.inputSpecifications = inputSpecifications;
        this.inputInterface = inputInterface;
        this.mapSpecCol = mapSpecCol;
        this.eventListener = eventListener;
        this.columnIndex = columnIndex;
        this.cellFont = cellFont;

        init();
        createAll();
    }

    public TableForInputInterface(String[] inputSpecifications,
            InputInterface inputInterface, EventListener eventListener,
            int columnIndex) {
        super();
        this.inputSpecifications = inputSpecifications;
        this.inputInterface = inputInterface;
        this.eventListener = eventListener;
        this.columnIndex = columnIndex;

        init();
        createAll();
    }

    public void itemStateChanged(ItemEvent e) {
        Command command = (Command) e.getSource();
        command.execute(e);
    }

    public void actionPerformed(ActionEvent e) {
        Command command = (Command) e.getSource();
        command.execute(e);
    }

    public void caretUpdate(CaretEvent e) {
        Command command = (Command) e.getSource();
        command.execute(e);
    }

    public void popupMenuCanceled(PopupMenuEvent e) {
    }

    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
        Command command = (Command) e.getSource();
        command.execute(e);
    }

    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    }

    private TableModelListener[] tlisteners;

    public void removeListeners() {
        tlisteners = ((DefaultTableModel) getModel()).getTableModelListeners();
        if (tlisteners != null) {
            for (int i = 0; i < tlisteners.length; i++) {
                ((DefaultTableModel) getModel())
                        .removeTableModelListener(tlisteners[i]);
            }
        }
    }

    public void restoreListeners() {
        if (tlisteners != null) {
            for (int i = 0; i < tlisteners.length; i++) {
                ((DefaultTableModel) getModel())
                        .addTableModelListener(tlisteners[i]);
            }
        }
    }

    /**
     * このテーブルは, 'ApplyToAll'コンポーネントを含む際はtableheader+apply_to_all table+table
     * という按配にパネルに配備されたものを生成する. そのパネルへの参照を取得するメソッド.
     * 
     * @return このクラスが作成する全てのコンポーネントを配備したパネル.
     */
    public JPanel getPanel() {
        createPanel();
        return this.panel;
    }

    /**
     * このテーブルに意味のあるデータが含まれているか否か検査する.
     * 
     * @param ignore
     *            無視するカラムの列はtrueと指定 (全てのカラムを見る場合はnullを渡す).
     * @return 意味のあるデータが存在する場合true.
     */
    public boolean hasData(boolean[] ignore) {
        boolean hasdata = false;
        TableModel model = (TableModel) getModel();
        int icol = model.getColumnCount();
        int irow = model.getRowCount();
        for (int i = 0; i < irow; i++) {
            for (int j = 0; j < icol; j++) {
                if (ignore != null && ignore[j]) {
                    continue;
                }
                String data = (String) model.getValueAt(i, j);
                if (data != null && data.trim().length() != 0) {
                    hasdata = true;
                    continue;
                }
            }
        }
        return hasdata;
    }

    private void init() {
        logger.debug("at init(): " + inputSpecifications[0]);
        ExcelAdapter ea = new ExcelAdapter(this);

        this.manager = this.inputInterface.getInputInterfaceTableSpecManager();
        if (manager != null) {
            tableSpec = manager.getTableSpec(inputSpecifications[0],
                    columnIndex);
            if (tableSpec != null) {
                tableCols = tableSpec.getTableColumns();
            } else {
                return;
            }
        }

        if (mapSpecCol == null && tableCols != null) {
            int len = tableCols.length;
            this.mapSpecCol = new int[len];
            for (int i = 0; i < len; i++) {
                mapSpecCol[i] = i;
            }
        }

        non_tabular = tableSpec.nonTabular();
        if (non_tabular) {
            row_oriented = tableSpec.isRowOriented();
            row_oriented_columns = tableSpec.getColumnNamesForNonTabularData();
        }

        panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        setModel(getTableModel());
        revalidate();
        repaint();
        if (eventListener instanceof ListSelectionListener) {
            getSelectionModel().addListSelectionListener(
                    (ListSelectionListener) eventListener);
        }
    }

    private boolean isColumnEmpty(int rowIndex) {
        for (int j = 1; j < ConstParameters.COLNAME_ATOM.length; j++) {
            String length = (String) getModel().getValueAt(rowIndex, j);
            if (length == null || length.trim().length() != 0) {
                return false;
            }
        }
        return true;
    }

    private void createAll() {
        if (manager != null && inputInterface != null) {
            int[] inds = getApplyToAllIndices();
            if (inds != null && inds.length != 0) {
                logger.debug("creating checkbox table...");
                logger.debug("column count... " + getColumnCount());
                logger.debug("indices...");
                for (int i = 0; i < inds.length; i++) {
                    logger.debug(new Integer(inds[i]));
                }
                cbtable = new CheckBoxTable(inds, getModel().getColumnCount());
            }

            createTable();
            createPanel();
        }
    }

    private void createPanel() {
        panel.removeAll();
        int row = getRowCount();
        if (row == 1 && getModel() instanceof TableModelForNonTabularData) {
            panel.setLayout(new GridLayout(2, 1));
        } else {
            panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        }
        panel.add(this.getTableHeader());
        if (cbtable != null) {
            panel.add(cbtable);
        }
        panel.add(this);
        logger.debug("tableheader..." + getTableHeader());
        logger.debug("inputspec: " + inputSpecifications[0]);
    }

    private int[] getApplyToAllIndices() {
        Vector indvec = new Vector();
        for (int i = 0; i < mapSpecCol.length; i++) {
            logger.debug("cols: " + tableCols[mapSpecCol[i]]);
            if (tableCols[mapSpecCol[i]].hasApplytoAll()) {
                indvec.addElement(new Integer(i));
            }
        }

        if (indvec == null || indvec.size() == 0) {
            return null;
        }

        int[] ret = new int[indvec.size()];
        for (int i = 0; i < indvec.size(); i++) {
            ret[i] = ((Integer) indvec.elementAt(i)).intValue();
        }

        return ret;
    }

    /**
     * 引数で表されるカラムのエディターを最新に. 差し当たり, Non-tabular な場合は対応しない.
     * 
     * @param col
     *            最新にしたいカラムのインデックス.
     */
    public void updateCellEditor(int col) {
        if (non_tabular) {
            return;
        }
        if (col < getColumnCount()) {
            TableColumn colu = getColumnModel().getColumn(col);
            setCellEditor(colu, tableCols[mapSpecCol[col]], col);
        }
    }

    private void createTable() {
        int numCols = getColumnCount();

        ColumnHeaderToolTips toolTips = new ColumnHeaderToolTips();
        for (int i = 0; i < numCols; i++) {
            TableColumn col = getColumnModel().getColumn(i);
            if (!non_tabular) {
                setCellEditor(col, tableCols[mapSpecCol[i]], i);
                setToolTip(toolTips, col, tableCols[mapSpecCol[i]]);
            } else {
                setEditorsAndRenderes();
            }
        }

        addMouseListener(new RowMouseListener());

        setTableHeader(new TableHeader(this, tableCols, mapSpecCol));
        getTableHeader().addMouseMotionListener(toolTips);
        logger.debug("done creating table for: " + inputSpecifications[0]);
    }

    class MyTableCellRenderer extends DefaultTableCellRenderer {
        public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row,
                int column) {
            Component cell = super.getTableCellRendererComponent(table, value,
                    isSelected, hasFocus, row, column);
            if (cellFont != null)
                cell.setFont(cellFont);
            return cell;
        }
    }

    private void setEditorsAndRenderes() {
        DefaultTableCellRenderer dtcr = new MyTableCellRenderer();
        dtcr.setHorizontalAlignment(JLabel.CENTER);
        DefaultTableCellRenderer dtcr2 = new MyTableCellRenderer();
        JTextField tf = new JTextField();
        tf.setEditable(false);
        JTextField tf2 = new JTextField();
        tf2.setEditable(true);
        DefaultCellEditor dce = new DefaultCellEditor(tf);
        DefaultCellEditor dce2 = new DefaultCellEditor(tf2);

        int icol = this.getModel().getColumnCount();

        columnModel.getColumn(0).setCellRenderer(dtcr);
        columnModel.getColumn(0).setCellEditor(dce);

        int rowStart = 1;
        for (int i = rowStart; i < icol; i++) {
            columnModel.getColumn(i).setCellRenderer(dtcr2);
            columnModel.getColumn(i).setCellEditor(dce2);
        }
    }

    private void setToolTip(ColumnHeaderToolTips toolTips, TableColumn col,
            InputInterfaceTableColumns tableCol) {
        String toolTip = tableCol.getToolTip();
        if (toolTip != null && toolTip.trim().length() != 0) {
            toolTips.setToolTip(col, tableCol.getToolTip());
        }
    }

    private void setCellEditor(TableColumn col,
            InputInterfaceTableColumns tableCol, int colnum) {
        String type = tableCol.getCellEditor();
        String defaultValue = tableCol.getDefaultValue();
        logger.debug("default value: " + defaultValue);
        boolean editable = tableCol.isEditable();

        if (type.equals(InputInterfaceTableColumns.TEXT_FIELD)) {
            JTextField textField = null;
            if (tableCol.hasApplytoAll()) {
                textField = new TextFieldApplyToAll(defaultValue, cbtable,
                        this, colnum, this);
            } else {
                textField = new JTextField(defaultValue);
            }
            textField.setEnabled(editable);
            col.setCellEditor(new DefaultCellEditor(textField));
        } else if (type.equals(InputInterfaceTableColumns.COMBO_BOX)) {
            ToolTippedCombo combo = null;
            if (!validChoices(tableCol.getChoices())) {
                if (tableCol.hasApplytoAll()) {
                    col.setCellEditor(new DefaultCellEditor(
                            new TextFieldApplyToAll(defaultValue, cbtable,
                                    this, colnum, this)));
                } else {
                    col.setCellEditor(new DefaultCellEditor(new JTextField()));
                }
                return;
            }
            if (tableCol.hasApplytoAll()) {
                combo = new ComboBoxApplyToAll(tableCol.getChoices(), cbtable,
                        this, colnum, this);
            } else {
                combo = new ToolTippedCombo(tableCol.getChoices());
                String[] tips = new String[tableCol.getChoices().length];
                for (int i = 0; i < tableCol.getChoices().length; i++) {
                    tips[i] = tableCol.getToolTipAssociatedWithChoice(i);
                }
                combo.setToolTips(tips);
            }
            // combo.setEnabled(editable);
            combo.setEditable(editable);
            col.setCellEditor(new DefaultCellEditor(combo));
        } else if (type.equals(InputInterfaceTableColumns.CHECK_BOX)) {
            JCheckBox checkBox = null;
            if (tableCol.hasApplytoAll()) {
                checkBox = new CheckBoxApplyToAll(false, cbtable, this, colnum,
                        this);
            } else {
                checkBox = new JCheckBox("",
                        new Boolean(defaultValue).booleanValue());
            }
            checkBox.setEnabled(editable);
            checkBox.setHorizontalAlignment(JLabel.CENTER);
            col.setCellEditor(new DefaultCellEditor(checkBox));
            col.setCellRenderer(new CheckBoxTableCellRenderer());
        }
    }

    private boolean validChoices(String[] test) {
        if (test == null || test.length == 0) {
            return false;
        }

        if (test.length == 1 && test[0].trim().length() == 0) {
            return false;
        }

        return true;
    }

    protected void doApplyToAll(Object selectedItem, int colInd) {
        int numRow = getRowCount();
        int numCols = getColumnCount();
        DefaultTableModel mod = (DefaultTableModel) getModel();
        ((TableModelForInputInterface) mod)
                .notifyInputInterfaceChangeListeners(false);
        int swi = numRow - 1;
        if (swi < 0) {
            swi = 0;
        }
        for (int i = 0; i < numRow; i++) {
            int nullCount = 0;
            for (int j = 0; j < numCols; j++) {
                Object obj = getModel().getValueAt(i, j);
                if (obj == null) {
                    nullCount++;
                    continue;
                }
                if (obj.toString().trim().length() == 0) {
                    nullCount++;
                    continue;
                }
            }

            if (nullCount == numCols) {
                ((TableModelForInputInterface) mod)
                        .notifyInputInterfaceChangeListeners(true);
                mod.setValueAt(mod.getValueAt(0, 0), 0, 0);
                logger.debug("done 'apply_to_all'");
                return;
            }

            logger.debug("setting " + selectedItem + " at " + i + ", " + colInd);
            mod.setValueAt(selectedItem, i, colInd);
        }
        ((TableModelForInputInterface) mod)
                .notifyInputInterfaceChangeListeners(true);
        mod.setValueAt(mod.getValueAt(0, 0), 0, 0);
    }

    public void updateAll() {
        setModel(getTableModel());
        revalidate();
        repaint();
        createAll();
    }

    private Vector tableRightClickListeners;

    public void addTableRightClickListener(TableRightClickListener listener) {
        if (tableRightClickListeners == null) {
            tableRightClickListeners = new Vector();
        }
        tableRightClickListeners.addElement(listener);
    }

    protected void deleteColumn(int col) {
        int[] tmp = new int[mapSpecCol.length - 1];
        int icount = 0;
        for (int i = 0; i < mapSpecCol.length; i++) {
            if (i != col) {
                tmp[icount] = mapSpecCol[i];
                icount++;
            }
        }

        mapSpecCol = new int[tmp.length];
        for (int i = 0; i < mapSpecCol.length; i++) {
            mapSpecCol[i] = tmp[i];
        }

        setModel(getTableModel());
        revalidate();
        repaint();
        createAll();
    }

    protected void addColumn(String name) {
        int addInd = -1;
        for (int i = 0; i < tableCols.length; i++) {
            if (tableCols[i].getName().equals(name)) {
                addInd = i;
                break;
            }
        }

        int[] tmp = new int[mapSpecCol.length + 1];
        for (int i = 0; i < mapSpecCol.length; i++) {
            tmp[i] = mapSpecCol[i];
        }
        tmp[mapSpecCol.length] = addInd;

        mapSpecCol = new int[mapSpecCol.length + 1];
        for (int i = 0; i < mapSpecCol.length; i++) {
            mapSpecCol[i] = tmp[i];
        }
        inputInterface
                .removeInputInterfaceEntryChangeListener((InputInterfaceEntryChangeListener) getModel());
        setModel(getTableModel());
        revalidate();
        repaint();

        createAll();
    }

    private TableModelForInputInterface getTableModel() {
        TableModelForInputInterface tmfi = null;
        if (coords == null) {
            tmfi = TableModelForInputInterface.getInstance(inputSpecifications,
                    inputInterface, mapSpecCol, eventListener, non_tabular,
                    columnIndex);
        } else {
            tmfi = TableModelForInputInterface.getInstance(coords,
                    inputSpecifications,
                    inputInterface.getInputInterfaceTableSpecManager(),
                    mapSpecCol, eventListener, this);
        }
        tmfi.setParentTable(this);
        return tmfi;
    }

    /**
     * a mouse listener to catch a specific row.
     * 
     * @author KOGA, Junichiro
     */
    class RowMouseListener extends MouseAdapter {
        JPopupMenu popup;

        protected RowMouseListener() {
        }

        public void mousePressed(MouseEvent e) {
            if (inputInterface.getInputInterfaceTableSpecManager()
                    .getTableSpec(inputSpecifications[0]).getRightClickItems() == null) {
                return;
            }
            processClick(e);
        }

        private void processClick(MouseEvent e) {
            if (e.getButton() == MouseEvent.BUTTON3) {
                popup = new JPopupMenu();
                RightClickItems[] items = inputInterface
                        .getInputInterfaceTableSpecManager()
                        .getTableSpec(inputSpecifications[0])
                        .getRightClickItems();
                createMenu(e, items);
                if (popup.getComponentCount() > 0) {
                    popup.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        }

        private void createMenu(MouseEvent e, RightClickItems[] items) {
            for (int i = 0; i < items.length; i++) {
                popup.add(new RightClickMenu(e, items[i]));
            }
        }
    }

    /**
     * a JMenuItem on right click of cell.
     */
    class RightClickMenu extends JMenuItem {
        private MouseEvent me;
        private String name;

        protected RightClickMenu(MouseEvent me, RightClickItems item) {
            super(item.getText());
            setToolTipText(item.getToolTip());
            this.me = me;
            this.name = item.getName();
            init();
        }

        private void init() {
            addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    doRightClickItem(me, name);
                }
            });
        }

        private void doRightClickItem(MouseEvent e, String name) {
            logger.debug("clicked item");
            logger.debug("you're at row: " + rowAtPoint(e.getPoint()));
            if (tableRightClickListeners == null) {
                return;
            }
            for (int i = 0; i < tableRightClickListeners.size(); i++) {
                ((TableRightClickListener) tableRightClickListeners
                        .elementAt(i)).tableRightClicked(e.getPoint(), name);
            }
        }
    }

    /**
     * custom table header.
     * 
     * @author KOGA, Junichiro
     */
    class TableHeader extends JTableHeader implements Command {
        private Logger logger = Logger.getLogger(TableHeader.class.getName());
        private TableColumnModel model;
        private InputInterfaceTableColumns[] columns;
        private TableForInputInterface table;
        int[] map;

        protected TableHeader(TableForInputInterface table,
                InputInterfaceTableColumns[] columns, int[] map) {
            super(table.getColumnModel());
            this.table = table;
            this.model = table.getColumnModel();
            this.columns = columns;
            this.map = map;
            addMouseListener(new ColumnHeaderMouseListener());
            // setDefaultRenderer(new MyTableCellRenderer());
        }

        public void execute(EventObject e) {
            if (e instanceof MouseEvent) {
                MouseEvent me = (MouseEvent) e;
                logger.debug("at: tableheader...");
                if (me.getButton() == MouseEvent.BUTTON3) {
                    logger.debug("right-clicked table header...");
                    showMenu((MouseEvent) e);
                }
            }
        }

        private void showMenu(MouseEvent e) {
            JPopupMenu popup = new JPopupMenu();
            int numCol = model.getColumnCount();
            for (int i = 0; i < columns.length; i++) {
                if (columns[i].isHideable()) {
                    ColumnHeaderCheckBox item = new ColumnHeaderCheckBox(table,
                            columns[i].getName(), true);
                    boolean vis = false;
                    for (int j = 0; j < numCol; j++) {
                        if (((String) model.getColumn(j).getHeaderValue())
                                .equalsIgnoreCase(columns[i].getName().trim())) {
                            vis = true;
                            break;
                        }
                    }
                    item.setState(vis);
                    popup.add(item);
                }
            }
            if (popup.getComponentCount() > 0) {
                popup.show(e.getComponent(), e.getX(), e.getY());
            }
        }

    }

    /**
     * JCheckBoxMenuItem for the column headers.
     * 
     * @author KOGA, Junichiro,
     */
    class ColumnHeaderCheckBox extends JCheckBoxMenuItem {
        private boolean column_visible = true;
        private TableForInputInterface table;

        protected ColumnHeaderCheckBox(TableForInputInterface table,
                String title, boolean column_visible) {
            super(title);
            this.column_visible = column_visible;
            this.table = table;
            addActionListener(new ColumnHeaderCheckBoxListener(title));
        }

        class ColumnHeaderCheckBoxListener implements ActionListener {
            private String name;

            protected ColumnHeaderCheckBoxListener(String name) {
                this.name = name;
            }

            public void actionPerformed(ActionEvent e) {
                int col = table.getColumnCount();

                if (!getState()) {
                    for (int i = 0; i < col; i++) {
                        if (table.getColumnName(i).equals(name)) {
                            table.deleteColumn(i);
                            return;
                        }
                    }
                } else {
                    table.addColumn(name);
                }
            }
        }

    }

    /**
     * a mouse listener for class 'TableForInputInterface'
     * 
     * @author KOGA, Junichiro
     */
    class ColumnHeaderMouseListener extends MouseAdapter {
        /** Creates a new instance of ColumnHeaderMouseListener */
        protected ColumnHeaderMouseListener() {
        }

        public void mousePressed(MouseEvent e) {
            Command command = (Command) e.getSource();
            command.execute(e);
        }
    }

    /**
     * a class to show tooltip text for the column header.
     * 
     * @author KOGA, Junichiro
     */
    class ColumnHeaderToolTips extends MouseMotionAdapter {

        TableColumn curCol;

        // Maps TableColumn objects to tooltips
        Map tips = new HashMap();

        // If tooltip is null, removes any tooltip text.
        public void setToolTip(TableColumn col, String tooltip) {
            if (tooltip == null) {
                tips.remove(col);
            } else {
                tips.put(col, tooltip);
            }
        }

        public void mouseMoved(MouseEvent evt) {
            TableColumn col = null;
            JTableHeader header = (JTableHeader) evt.getSource();
            JTable table = header.getTable();
            TableColumnModel colModel = table.getColumnModel();
            int vColIndex = colModel.getColumnIndexAtX(evt.getX());

            if (vColIndex >= 0) {
                col = colModel.getColumn(vColIndex);
            }

            if (col != curCol) {
                header.setToolTipText((String) tips.get(col));
                curCol = col;
            }
        }

    }

    interface CheckBoxTableListener {
        void checkBoxChecked(int index);
    }

    class CheckBoxTable extends JTable {
        private int[] indeces;
        private int numcols = 0;
        private Vector listeners;

        public CheckBoxTable(int[] indeces, int numcols) {
            super();
            this.indeces = indeces;
            this.numcols = numcols;
            init();
        }

        void addListener(CheckBoxTableListener listener) {
            if (listeners == null)
                listeners = new Vector();
            listeners.add(listener);
        }

        private JCheckBox[] checkBoxes;

        boolean isSelected(int colind) {
            Component comp = ((DefaultCellEditor) getColumnModel().getColumn(
                    colind).getCellEditor()).getComponent();
            if (!(comp instanceof JCheckBox)) {
                return false;
            }
            return ((JCheckBox) comp).isSelected();
        }

        private void init() {
            setSelectionForeground(Color.white);
            setSelectionBackground(Color.white);
            setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

            TableColumn column;
            setModel(new DefaultTableModel(1, numcols));
            revalidate();
            repaint();

            JCheckBox checkBox = new JCheckBox(ConstParameters.APPLY_TO_ALL);
            checkBox.setHorizontalAlignment(JLabel.CENTER);
            checkBox.setSelected(false);
            DefaultCellEditor editorCB = new DefaultCellEditor(checkBox);

            checkBoxes = new JCheckBox[indeces.length];
            for (int i = 0; i < indeces.length; i++) {
                if (i >= getColumnCount()) {
                    break;
                }

                checkBoxes[i] = new CheckBoxTableCellRenderer(
                        ConstParameters.APPLY_TO_ALL);

                getColumnModel().getColumn(indeces[i]).setCellRenderer(
                        new CheckBoxTableCellRenderer(
                                ConstParameters.APPLY_TO_ALL));
                getColumnModel().getColumn(indeces[i]).setCellEditor(editorCB);

                checkBox.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        if (listeners != null)
                            for (int i = 0; i < listeners.size(); i++)
                                ((CheckBoxTableListener) listeners.get(i))
                                        .checkBoxChecked(getSelectedColumn());
                    }
                });
            }

            JTextField tf = new JTextField("");
            tf.setEnabled(false);
            DefaultCellEditor editorTF = new DefaultCellEditor(tf);

            for (int i = 0; i < numcols; i++) {
                column = this.getColumnModel().getColumn(i);
                // column.setPreferredWidth(100);
                boolean is_cb = false;
                for (int j = 0; j < indeces.length; j++) {
                    if (indeces[j] == i) {
                        is_cb = true;
                        break;
                    }
                }
                if (!is_cb) {
                    getColumnModel().getColumn(i).setCellEditor(editorTF);
                }
            }

        }

    }

    class ComboBoxApplyToAll extends ToolTippedCombo implements Command {
        private Logger logger = Logger.getLogger(ComboBoxApplyToAll.class
                .getName());

        private JTable cbTable;
        private TableForInputInterface dataTable;
        private int lookAt;

        public ComboBoxApplyToAll(String[] list, JTable cbTable,
                TableForInputInterface dataTable, int lookAt,
                EventListener listener) {
            super(list);
            super.addPopupMenuListener((PopupMenuListener) listener);
            this.cbTable = cbTable;
            this.dataTable = dataTable;
            this.lookAt = lookAt;
        }

        public void execute(EventObject e) {
            logger.debug("cbtable: " + cbTable);
            logger.debug("cbtable.getModel(): " + cbTable.getModel());
            logger.debug("cbtable.getModel.getValueAt(0,lookAt): "
                    + cbTable.getModel().getValueAt(0, lookAt));
            try {
                Object obj = cbTable.getModel().getValueAt(0, lookAt);
                if (obj == null) {
                    logger.debug("obj is null at " + lookAt);
                    return;
                }
                if (((Boolean) obj).booleanValue() && this.isPopupVisible()) {
                    // if ( ((Boolean)
                    // cbTable.getModel().getValueAt(0,lookAt)).booleanValue() )
                    // {
                    dataTable.doApplyToAll(getSelectedItem(), lookAt);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

    }

    class CheckBoxApplyToAll extends JCheckBox implements Command,
            CheckBoxTableListener {
        private Logger logger = Logger.getLogger(CheckBoxApplyToAll.class
                .getName());

        private JTable cbTable;
        private TableForInputInterface dataTable;
        private int lookAt;

        public CheckBoxApplyToAll(boolean onoff, JTable cbTable,
                TableForInputInterface dataTable, int lookAt,
                EventListener listener) {
            super();
            super.setSelected(onoff);
            super.addActionListener((ActionListener) listener);
            this.cbTable = cbTable;
            this.dataTable = dataTable;
            this.lookAt = lookAt;
            ((CheckBoxTable) cbTable).addListener(this);
        }

        public void execute(EventObject e) {
            // try {
            // Object obj = cbTable.getModel().getValueAt(0,lookAt);
            // if ( obj == null ) {
            // logger.debug("obj is null at "+lookAt);
            // return;
            // }
            // if ( ((Boolean) obj).booleanValue() ) {
            // dataTable.doApplyToAll(new Boolean(isSelected()),lookAt);
            // }
            // } catch(Exception ex) {
            // ex.printStackTrace();
            // }
        }

        public void checkBoxChecked(int index) {
            if (this.lookAt == index)
                dataTable.doApplyToAll(
                        ((CheckBoxTable) cbTable).isSelected(this.lookAt),
                        this.lookAt);
        }

    }

    class TextFieldApplyToAll extends JTextField implements Command {
        private Logger logger = Logger.getLogger(CheckBoxApplyToAll.class
                .getName());

        private JTable cbTable;
        private TableForInputInterface dataTable;
        private int lookAt;

        public TextFieldApplyToAll(String text, JTable cbTable,
                TableForInputInterface dataTable, int lookAt,
                EventListener listener) {
            super(text);
            super.addCaretListener((CaretListener) listener);
            this.cbTable = cbTable;
            this.dataTable = dataTable;
            this.lookAt = lookAt;
        }

        public void execute(EventObject e) {
            try {
                Object obj = cbTable.getModel().getValueAt(0, lookAt);
                if (obj == null) {
                    logger.debug("obj is null at " + lookAt);
                    return;
                }
                if (((Boolean) obj).booleanValue()) {
                    String tmp = getText();
                    if (tmp != null) {
                        dataTable.doApplyToAll(tmp, lookAt);
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

}
