/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2007 Approximatrix, LLC
 *  http://www.approximatrix.com
 *  
 *  This program 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.
 *
 *  This program 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.approximatrix.draco.general.ui;

import java.util.Vector;

import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.DefaultListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.JTableHeader;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;


public class JCSelectTable extends JTable implements MouseListener {

	public JCSelectTable() {
		super();
		this.setSelectionModel(new NotQuiteDefaultListSelectionModel());
		initializeHeaders();
	}

	public JCSelectTable(TableModel arg0) {
		super(arg0);
		this.setSelectionModel(new NotQuiteDefaultListSelectionModel());
		initializeHeaders();
	}

	public JCSelectTable(TableModel arg0, TableColumnModel arg1) {
		super(arg0, arg1);
		this.setSelectionModel(new NotQuiteDefaultListSelectionModel());
		initializeHeaders();
	}

	public JCSelectTable(TableModel arg0, TableColumnModel arg1,
			ListSelectionModel arg2) {
		super(arg0, arg1, arg2);
		this.setSelectionModel(arg2);
		initializeHeaders();
	}

	public JCSelectTable(int arg0, int arg1) {
		super(arg0, arg1);
		this.setSelectionModel(new NotQuiteDefaultListSelectionModel());
		initializeHeaders();
	}

	public JCSelectTable(Vector arg0, Vector arg1) {
		super(arg0, arg1);
		this.setSelectionModel(new NotQuiteDefaultListSelectionModel());
		initializeHeaders();
	}

	public JCSelectTable(Object[][] arg0, Object[] arg1) {
		super(arg0, arg1);
		this.setSelectionModel(new NotQuiteDefaultListSelectionModel());
		initializeHeaders();
	}

	private void initializeHeaders() {
		unconfigureEnclosingScrollPane();

        JTableHeader h = super.getTableHeader();
        h.addMouseListener(this);
        super.setTableHeader(h);

        configureEnclosingScrollPane();
	}
	
	public void mousePressed(MouseEvent e) {
		
	}
	
	public void mouseReleased(MouseEvent e) {
		
	}
	
	public void mouseEntered(MouseEvent e) {
		
	}
	
	public void mouseExited(MouseEvent e) {
		
	}
	
	public void mouseClicked(MouseEvent e)
	{
	    JTableHeader header = this.getTableHeader();

	    TableColumnModel columns = header.getColumnModel();
	    
	    if (!columns.getColumnSelectionAllowed())
	        return;

	    int column = header.columnAtPoint(e.getPoint());

	    if (column == -1)
	        return;

	    int count = this.getRowCount();

	    if (count != 0)
	        this.setRowSelectionInterval(0, count - 1);

	    ListSelectionModel selection = columns.getSelectionModel();

	    if (e.isShiftDown())
	    {
	        int anchor = selection.getAnchorSelectionIndex();
	        int lead = selection.getLeadSelectionIndex();

	        if (anchor != -1)
	        {
	            boolean old = selection.getValueIsAdjusting();
	            selection.setValueIsAdjusting(true);

	            boolean anchorSelected = selection.isSelectedIndex(anchor);

	            if (lead != -1)
	            {
	                if (anchorSelected)
	                    selection.removeSelectionInterval(anchor, lead);
	                else
	                    selection.addSelectionInterval(anchor, lead);
	                // The latter is quite unintuitive.
	            }

	            if (anchorSelected)
	                selection.addSelectionInterval(anchor, column);
	            else
	                selection.removeSelectionInterval(anchor, column);

	            selection.setValueIsAdjusting(old);
	        }
	        else
	            selection.setSelectionInterval(column, column);
	    }
	    else if (e.isControlDown())
	    {
	        if (selection.isSelectedIndex(column))
	            selection.removeSelectionInterval(column, column);
	        else
	            selection.addSelectionInterval(column, column);
	        
	    }
	    else
	    {
	        selection.setSelectionInterval(column, column);
	    }
	    
	    ((NotQuiteDefaultListSelectionModel)this.getSelectionModel()).fireValueChanged(false);
	}
	
	
	private class NotQuiteDefaultListSelectionModel extends DefaultListSelectionModel {
		
		public NotQuiteDefaultListSelectionModel() {
			super();
		}
		
		public void fireValueChanged(boolean isAdjusting) {
			Runnable doLater = new Runnable() {
	            public void run() {
	            	ListSelectionListener[] temp = getListSelectionListeners();
	            	for(int i=0;i<temp.length;i++) {
	    				temp[i].valueChanged(new ListSelectionEvent(NotQuiteDefaultListSelectionModel.this,0,1,false));
	    			}
	            }
	        };
	        SwingUtilities.invokeLater(doLater);
		}
	}
	
    // Converts a visible column index to a column index in the model.
    // Returns -1 if the index does not exist.
    public int toModelIndex(int vColIndex) {
        if (vColIndex >= this.getColumnCount()) {
            return -1;
        }
        return this.getColumnModel().getColumn(vColIndex).getModelIndex();
    }
    
    // Converts a column index in the model to a visible column index.
    // Returns -1 if the index does not exist.
    public int toViewIndex(int mColIndex) {
        for (int c=0; c<this.getColumnCount(); c++) {
            if (this.getColumnModel().getColumn(c).getModelIndex() == mColIndex) {
                return c;
            }
        }
        return -1;
    }
	
    // Converts a visible column index to a column index in the model.
    // Returns -1 if the index does not exist.
    public int[] toModelIndex(int[] vColIndex) {
    	if(vColIndex == null) return null;
    	
    	int[] return_val = new int[vColIndex.length];
    	for(int i=0;i<return_val.length;i++)
    		return_val[i] = toModelIndex(vColIndex[i]);
    	
        return return_val;
    }
    
    // Converts a column index in the model to a visible column index.
    // Returns -1 if the index does not exist.
    public int[] toViewIndex(int[] mColIndex) {
    	if(mColIndex == null) return null;
    	
    	int[] return_val = new int[mColIndex.length];
    	for(int i=0;i<return_val.length;i++)
    		return_val[i] = toViewIndex(mColIndex[i]);
    	
        return return_val;
    }
    
}
