/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: ExportTable.java
 *
 * Copyright (c) 2003, Static Free Software. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.user.ncc;

import java.awt.Color;
import java.awt.Component;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventObject;

import javax.swing.BorderFactory;
import javax.swing.JEditorPane;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.CellEditorListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

abstract class ExportTable extends JTable 
implements PropertyChangeListener, ActionListener {
    // constants
    static final int MAXROWS = 200;
    static final int WIDTHMARGIN = 11;
    static final int HEIGHTMARGIN = 16;
    static final int LINEHEIGHT = 17;
    static final int SCRLBARHEIGHT = 17;
    static final int MAX_VISIBLE_LINES = 6;
    
    protected static final String RED = "red";
    protected static final String GREEN = "green";

    // GUI variables
    protected int height;
    protected int numCols;
    protected int[][] cellPrefHeights;
    protected int[][] cellPrefWidths;
    protected JPopupMenu cellPopup;
    protected String clipboard;
            
    // data holders
    protected NccGuiInfo result;
 
    public ExportTable(NccGuiInfo res, int cols) {
        result = res;
        numCols = cols;
    }
    
    protected void setup() {
        setDefaultRenderer(JScrollPane.class, new CellRenderer());
        setDefaultEditor(JScrollPane.class, new CellEditor());
        setCellSelectionEnabled(true);
        setColumnSelectionAllowed(true);
        setRowSelectionAllowed(true);
        setGridColor(Color.GRAY);
        setBorder(BorderFactory.createEmptyBorder());
        addMouseMotionListener(new CellMouseMotionAdapter());
        createCellPopup();

        cellPrefHeights = new int[height][numCols];
        cellPrefWidths = new int[height][numCols];
        for (int row = 0; row<height; row++) 
            for (int col=0; col<numCols; col++)
                cellPrefHeights[row][col] = HEIGHTMARGIN;
    }
    
    void adjustRowHeights() {
        int colWidth[] = new int[numCols];
        for (int col=0; col<numCols; col++)
            colWidth[col] = getColumnModel().getColumn(col).getWidth();

        for (int row = 0; row < height; row++) {
            int oldHeight = getRowHeight(row);
            int newHeight = 0, pref = HEIGHTMARGIN;
            for (int col=0; col<numCols; col++) {    
                pref = cellPrefHeights[row][col];
                // if cell requires a horizontal scrollbar
                if (colWidth[col] < cellPrefWidths[row][col])
                    pref += SCRLBARHEIGHT;
                newHeight = Math.max(newHeight, pref);                
            }
            if (newHeight != oldHeight)
                setRowHeight(row, newHeight);
        }
        doLayout();
    }
    
    public void propertyChange(PropertyChangeEvent e) {
        if (e.getPropertyName().equals("width")) {
            adjustRowHeights();
        }
    }

    /* (non-Javadoc)
     * Action Listener interface (for popup menus)
     */
    public void actionPerformed(ActionEvent e) {
        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
        // copy text prepared during popup to clipboard
        StringSelection ss = new StringSelection(clipboard);
        cb.setContents(ss,ss);                    
    }

    protected void createCellPopup() {
        cellPopup = new JPopupMenu();
        JMenuItem menuItem = new JMenuItem("Copy Cell Text To Clipboard");
        menuItem.addActionListener(this);
        cellPopup.add(menuItem);
    }
}

class CellMouseAdapter extends MouseAdapter {
    public int lastClick = -1;
    private ExportTable parent;
    public CellMouseAdapter(ExportTable parent) { this.parent = parent; }
    public void mousePressed(MouseEvent e) {
        lastClick = e.getButton();
        if (! (e.getButton() == MouseEvent.BUTTON2 
            || e.getButton() == MouseEvent.BUTTON3)
            || ! (e.getSource() instanceof JEditorPane))
            return;
                       
        Document doc = ((JEditorPane)e.getSource()).getDocument();
        try {
            parent.clipboard = doc.getText(0, doc.getLength()).trim();
        } catch (BadLocationException e1) {
            System.out.println("Text cannot be retrieved due to bad locale");
        }
        parent.cellPopup.show(e.getComponent(), e.getX(), e.getY());
    }
}

class CellMouseMotionAdapter extends MouseMotionAdapter {
    public void mouseMoved(MouseEvent e) {
        JTable aTable =  (JTable)e.getSource();
        int row = aTable.rowAtPoint(e.getPoint());
        int column = aTable.columnAtPoint(e.getPoint());
        aTable.editCellAt(row, column);
    }
}

abstract class ExportTableModel extends AbstractTableModel implements HyperlinkListener {
    protected final String LSEP = System.getProperty("line.separator");  
    
    protected ExportTable parent;
    protected int height;
    protected int numCols;
    protected JScrollPane[][] panes;
    protected Insets insets = new Insets(0,0,0,0);
    protected CellMouseAdapter mouseAdapter;
    
    public ExportTableModel(ExportTable parent) {
        super();
        this.parent = parent;
        height = parent.height;
        numCols = parent.numCols;
        mouseAdapter = new CellMouseAdapter(parent);        
        panes = new JScrollPane[height][numCols];     
    }
    
    /* (non-Javadoc)
     * @see javax.swing.table.TableModel#getColumnCount()
     */
    public int getColumnCount() { return numCols; }
    public int getRowCount()    { return height; }

    public abstract String getColumnName(int col);

    public Object getValueAt(int row, int col) {
        return panes[row][col];
    }

    public Class<?> getColumnClass(int c) {
        return JScrollPane.class;
    }

    public boolean isCellEditable(int row, int col) {
        return true;
    }

    public void setValueAt(Object value, int row, int col) {
        panes[row][col] = (JScrollPane)value;
    }
    
    public void hyperlinkUpdate(HyperlinkEvent event) {
        if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED
                && mouseAdapter.lastClick == MouseEvent.BUTTON1) {
            highlight(Integer.parseInt(event.getDescription()));
        }
    }

    protected abstract void highlight(int index);
}

class CellRenderer implements TableCellRenderer { 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int col){
        return (JScrollPane)value;
    }
}

class CellEditor implements TableCellEditor {
    public Component getTableCellEditorComponent(JTable table, Object value, 
                                  boolean isSelected, int row, int column) {
        return (JScrollPane)table.getModel().getValueAt(row, column);
    }

    public Object getCellEditorValue() { return null; }
    public boolean isCellEditable  (EventObject eo) { return true; }
    public boolean shouldSelectCell(EventObject so) { return true; }
    public boolean stopCellEditing ()               { return true; }

    public void cancelCellEditing() {}
    public void addCellEditorListener(CellEditorListener el) {}
    public void removeCellEditorListener(CellEditorListener el) {}
}

