/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.billing.gui.invoice.stub;

/*
 * InvoiceListBox.java
 *
 * Created on April 3, 2006
 */

 import java.awt.Component;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.util.Collection;
import java.util.Vector;

import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.InvoiceStub;
import lu.tudor.santec.gecamed.billing.gui.BillingModule;
import lu.tudor.santec.gecamed.billing.gui.reminder.InvoiceStubListModel;
import lu.tudor.santec.gecamed.billing.utils.BillingAdminSettings;
import lu.tudor.santec.gecamed.core.gui.utils.TableSorter;
import lu.tudor.santec.i18n.Relocalizable;

//***************************************************************************
//* Class Definition                                                        *
//***************************************************************************

public class GenericInvoiceStubListBox extends JScrollPane implements Relocalizable
    {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private JTable           					m_InvoiceStubTable;
    private GenericInvoiceStubListInterface		m_InvoiceStubs;
    private TableSorter							m_InvoiceStubSorter;
         
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************

    public static final int c_None	     = TableSorter.NOT_SORTED;
    public static final int c_Ascending  = TableSorter.ASCENDING;
    public static final int c_Descending = TableSorter.DESCENDING;
    
    private static int c_CellMargin = 7;
 
    
//***************************************************************************
//* Internal Class Definitions	                                            *
//***************************************************************************

//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************

public GenericInvoiceStubListBox (GenericInvoiceStubListInterface p_ListModel)
    {	
	super ();
    
    m_InvoiceStubs = p_ListModel;
    
    m_InvoiceStubSorter = new TableSorter ();
    m_InvoiceStubSorter.setTableModel(m_InvoiceStubs);
    
    m_InvoiceStubTable = new JTable (m_InvoiceStubSorter);
    m_InvoiceStubTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    m_InvoiceStubTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        
    m_InvoiceStubTable.setColumnSelectionAllowed (false);
    m_InvoiceStubTable.setShowGrid (false);
    
    m_InvoiceStubSorter.setTableHeader(m_InvoiceStubTable.getTableHeader());
    adaptColumns();
    
    this.setViewportView (m_InvoiceStubTable);   
    }

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Primitives		                                                *
//***************************************************************************
//---------------------------------------------------------------------------

public void addListSelectionListener (ListSelectionListener p_Listener)
    {
    ListSelectionModel	l_Selection;	
    
    l_Selection = m_InvoiceStubTable.getSelectionModel();
    l_Selection.addListSelectionListener (p_Listener);
    }

//---------------------------------------------------------------------------

public void removeListSelectionListener (ListSelectionListener p_Listener)
    {
    ListSelectionModel	l_Selection;	
    
    l_Selection = m_InvoiceStubTable.getSelectionModel();
    l_Selection.removeListSelectionListener (p_Listener);
    }

//---------------------------------------------------------------------------

public void addMouseListener (MouseListener p_Listener)
    {
    m_InvoiceStubTable.addMouseListener (p_Listener);
    }    

//---------------------------------------------------------------------------

public void addKeyListener (KeyListener p_Listener)
    {
    m_InvoiceStubTable.addKeyListener (p_Listener);
    }    
 
//---------------------------------------------------------------------------

public int modelIndex (int p_RowInView)
	{
	int	l_ModelRow;
	
	l_ModelRow = p_RowInView;
	
	if (m_InvoiceStubSorter.isSorting())
		{
		l_ModelRow = m_InvoiceStubSorter.modelIndex(l_ModelRow);
		}
	
	return l_ModelRow;
	}

//---------------------------------------------------------------------------

public int viewIndex (int p_RowInModel)
	{
	int	l_ViewRow;
	
	l_ViewRow = p_RowInModel;
	
	if (m_InvoiceStubSorter.isSorting())
		{
		l_ViewRow = m_InvoiceStubSorter.viewIndex(p_RowInModel);
		}
	
	return l_ViewRow;
	}

//---------------------------------------------------------------------------
//Sets the preferred width of the visible column specified by vColIndex. The column
// will be just wide enough to show the column head and the widest cell in the column.
// margin pixels are added to the left and right
// (resulting in an additional width of 2*margin pixels).
//---------------------------------------------------------------------------

public void packColumn (int p_Column, int p_Margin) 
	{
	DefaultTableColumnModel	l_ColumnModel;
	TableColumn 			l_Column;
	TableCellRenderer		l_Renderer;
	Component				l_Component;
	
	int		   				l_Width;
	int						l_ComponentWidth;
    int						l_Row;
	
	l_ColumnModel = (DefaultTableColumnModel)m_InvoiceStubTable.getColumnModel();
	l_Column = l_ColumnModel.getColumn(p_Column);
	l_Width = 0;

    // First step consists in getting width of column header

    l_Renderer = l_Column.getHeaderRenderer();
    if (l_Renderer == null) 
    		{
    		l_Renderer = m_InvoiceStubTable.getTableHeader().getDefaultRenderer();
    		}
    
    l_Component = l_Renderer.getTableCellRendererComponent(m_InvoiceStubTable,
    													    l_Column.getHeaderValue(), 
    													    false, false, 0, 0);
    l_Width = l_Component.getPreferredSize().width;
 
    // Next we're going to iterate through all the rows of this columns, in order to
    // to find the widest one

    for (l_Row=0; l_Row < m_InvoiceStubTable.getRowCount(); l_Row++) 
    		{
    		l_Renderer = m_InvoiceStubTable.getCellRenderer(l_Row, p_Column);
    		
    		if (l_Renderer == null) continue;
       		
    		try {
    			l_Component = l_Renderer.getTableCellRendererComponent(m_InvoiceStubTable, 
    				                                               	   m_InvoiceStubTable.getValueAt(l_Row, p_Column), 
    				                                               	   false, false, l_Row, p_Column);
    			}
    		catch (Exception p_Exception)
    			{
    			// TODO Nasty Workaround
    			// Invoice Renderer sometimes throws unexplicable NullPointerExceptions.
    			// Not catching them results in Table not being properly packed.
    			}
 		
    		if (l_Component != null) 
    			{
    			l_ComponentWidth = l_Component.getPreferredSize().width;   			
    			l_Width = Math.max (l_Width, l_ComponentWidth);	
     			}
     		}

    // Add margin
    l_Width += 2*p_Margin;
   
    // Set the width
    l_Column.setPreferredWidth(l_Width);
	}

//---------------------------------------------------------------------------
//Returns the preferred height of a row.
// The result is equal to the tallest cell in the row.
//---------------------------------------------------------------------------

public void packRow (int p_Row, int p_Margin) 
	{
    int					l_RowHeight;
    int					l_ComponentHeight;
	int					l_Column;
    TableCellRenderer	l_Renderer;
    Component			l_Component;
    
    // Get the current default height for all rows
    l_RowHeight = m_InvoiceStubTable.getRowHeight();

    // Determine highest cell in the row
    for (l_Column = 0; l_Column < m_InvoiceStubTable.getColumnCount(); l_Column++) 
    		{
    		l_Renderer = m_InvoiceStubTable.getCellRenderer(p_Row, l_Column);
    		l_Component = m_InvoiceStubTable.prepareRenderer(l_Renderer, p_Row, l_Column);
    		l_ComponentHeight = l_Component.getPreferredSize().height + 2*p_Margin;
    		l_RowHeight = Math.max (l_RowHeight, l_ComponentHeight);
   		}
    
    if (m_InvoiceStubTable.getRowHeight() != l_RowHeight)
    		m_InvoiceStubTable.setRowHeight (p_Row,l_RowHeight);
	}

//---------------------------------------------------------------------------

private boolean setSelection (int p_Row, boolean p_ScrollIntoView)
	{
	ListSelectionModel	l_Selection;	
	JScrollBar			l_ScrollBar;
	float				l_ScrollValue;
	boolean 			l_Selected = false;
	    
	if ((p_Row >= 0) && (p_Row < m_InvoiceStubTable.getRowCount()))
        {
		l_Selection = m_InvoiceStubTable.getSelectionModel();
		l_Selection.setSelectionInterval (p_Row,p_Row);
			
		if (p_ScrollIntoView)
			{
			l_ScrollBar = getVerticalScrollBar ();
			
			l_ScrollValue  = (float) p_Row / (float) m_InvoiceStubs.getRowCount();
			l_ScrollValue *= (l_ScrollBar.getMaximum() - l_ScrollBar.getMinimum()); 
			
			l_ScrollBar.setValue ((int)l_ScrollValue);
			}
			
		l_Selected = true;
		m_InvoiceStubTable.revalidate();
        }
	   
	return (l_Selected);
	}

//---------------------------------------------------------------------------
/**
 * Method is part of the Relocalizable interface. The method does everything
 * required to reflect changes of active Locale
 */
//---------------------------------------------------------------------------

public void relocalize ()
    {
    // Make sure JTable re-creates columns using re-localized headers
        
    m_InvoiceStubTable.createDefaultColumnsFromModel ();
    }

//***************************************************************************
//* Class Body		                                                    	*
//***************************************************************************

//---------------------------------------------------------------------------

public void setInvoiceStubRenderer (DefaultTableCellRenderer p_Renderer)
	{
    int l_Count;
	
	for (l_Count=0; l_Count < m_InvoiceStubs.getColumnCount(); l_Count++)
		{
		if (m_InvoiceStubs.getColumnClass(l_Count) != null)	
			m_InvoiceStubTable.setDefaultRenderer (m_InvoiceStubs.getColumnClass(l_Count), p_Renderer);
		}
	}

//---------------------------------------------------------------------------

public void setTableCellEditor (TableCellEditor p_CellEditor, int p_Column)
	{
	TableColumn	l_Column;
	
	if ((p_Column >= 0) && p_Column < m_InvoiceStubs.getColumnCount())
		{
		l_Column = m_InvoiceStubTable.getColumnModel().getColumn(0);
		l_Column.setCellEditor (p_CellEditor);		
		}
	}

//---------------------------------------------------------------------------

public JTable getTable ()
	{
	return m_InvoiceStubTable;
	}

//---------------------------------------------------------------------------

public TableSorter getTableSorter ()
	{
	return m_InvoiceStubSorter;
	}

//---------------------------------------------------------------------------

public int getSortColumn ()
	{
	int	l_Column	 = 0;
	boolean	l_Found  = false;
	
	while ( (l_Column < m_InvoiceStubs.getColumnCount()) && !l_Found)
		{
		l_Found = (m_InvoiceStubSorter.getSortingStatus(l_Column) != TableSorter.NOT_SORTED);
		if (!l_Found) l_Column++;
		}
	
	if (!l_Found) l_Column = -1;
		
	return l_Column;
	}

//---------------------------------------------------------------------------

public int getSortDirection (int p_Column)
	{
	int	l_Direction = TableSorter.NOT_SORTED;
	
	if ((p_Column >= 0) && (p_Column < m_InvoiceStubs.getColumnCount()))
		{
		l_Direction = m_InvoiceStubSorter.getSortingStatus(p_Column);
		}
	
	return l_Direction;
	}

//---------------------------------------------------------------------------

public void setSorting (int p_Column, int p_Direction)
	{
	int	l_Direction = TableSorter.NOT_SORTED;
	
	if ((p_Column >= 0) && (p_Column < m_InvoiceStubs.getColumnCount()))
		{
		l_Direction = (p_Direction > 0)?TableSorter.ASCENDING:TableSorter.NOT_SORTED;
		if (l_Direction == TableSorter.NOT_SORTED)
			l_Direction = (p_Direction < 0)?TableSorter.DESCENDING:TableSorter.NOT_SORTED;
	
		m_InvoiceStubSorter.setSortingStatus(p_Column, l_Direction);	
		}
	}

//---------------------------------------------------------------------------

public void setEditable (boolean p_Editable)
	{
	m_InvoiceStubs.setEditable(p_Editable);
	}

//---------------------------------------------------------------------------

public boolean isEditable ()
	{
	return m_InvoiceStubs.isEditable();
	}

//---------------------------------------------------------------------------

public void addInvoiceStub (InvoiceStub p_InvoiceStub)
    {
    if ((m_InvoiceStubs != null) && (p_InvoiceStub != null))
        {
        m_InvoiceStubs.addInvoiceStub (p_InvoiceStub);
        m_InvoiceStubTable.revalidate();
        }
    }

//---------------------------------------------------------------------------

public void removeInvoiceStub (InvoiceStub p_InvoiceStub)
{
    if ((m_InvoiceStubs != null) && (p_InvoiceStub != null))
        {
        m_InvoiceStubs.removeInvoiceStub (p_InvoiceStub);
        m_InvoiceStubTable.revalidate();
        }
    }

//---------------------------------------------------------------------------

public void updateListing (Vector <InvoiceStub> p_InvoiceStubs)
    {
    InvoiceStub  l_InvoiceStub;
    int     	l_StubCount;
    
    if (p_InvoiceStubs == null) return;
        
    for (l_StubCount = 0; l_StubCount < p_InvoiceStubs.size(); l_StubCount++)
        {
    	l_InvoiceStub = p_InvoiceStubs.elementAt(l_StubCount);
            
        if (!this.containsInvoiceStub (l_InvoiceStub)) addInvoiceStub (l_InvoiceStub);
        }
    }

//---------------------------------------------------------------------------

public void removeSelectedInvoiceStubs ()
    {
    int []      l_SelectedRows;
    
    int         l_Selection;
    int			l_ModelRow;
    
    l_Selection = m_InvoiceStubTable.getSelectedRowCount();
    
    if (l_Selection > 0)
        {
        l_SelectedRows    = m_InvoiceStubTable.getSelectedRows ();
       
        for (l_Selection = l_SelectedRows.length - 1; l_Selection >= 0; l_Selection--)
            {
        	l_ModelRow = this.modelIndex (l_SelectedRows [l_Selection]);
        	m_InvoiceStubs.removeInvoiceStubAt (l_ModelRow);
            }
        
        m_InvoiceStubTable.clearSelection();
        m_InvoiceStubTable.revalidate();
        }
    }

//---------------------------------------------------------------------------

public void removeAllInvoiceStubs ()
    {
	m_InvoiceStubs.removeAllInvoiceStubs();
    m_InvoiceStubTable.clearSelection();
    m_InvoiceStubTable.revalidate();
    }

//---------------------------------------------------------------------------

public InvoiceStub getInvoiceStubAt (int p_Row)
	{
	return this.getInvoiceStubAt(p_Row, true);
	}

//---------------------------------------------------------------------------

public InvoiceStub getInvoiceStubAt (int p_Row, boolean p_IsViewRow)
	{
	InvoiceStub l_InvoiceStub;
	int	l_ModelRow;
	
	if (p_IsViewRow) l_ModelRow = this.modelIndex(p_Row);
				else l_ModelRow = p_Row;
	
	l_InvoiceStub = m_InvoiceStubs.getInvoiceStubAt (l_ModelRow);
	
	return l_InvoiceStub;
	}

//---------------------------------------------------------------------------

public void setInvoiceStubAt (InvoiceStub p_InvoiceStub, int p_Row)
	{
	int	l_ModelRow;
	
	l_ModelRow = this.modelIndex(p_Row);
	
	m_InvoiceStubs.setInvoiceStubAt (p_InvoiceStub,l_ModelRow);
	}

//---------------------------------------------------------------------------

public InvoiceStub[] getSelectedInvoiceStubs ()
    {
	InvoiceStub []  l_SelectedInvoiceStubs = null;    
    int []      	l_SelectedRows;   
    int         	l_Selection;
    int				l_ModelRow;
    
    l_Selection = m_InvoiceStubTable.getSelectedRowCount();
    
    if (l_Selection > 0)
        {
        l_SelectedRows    = m_InvoiceStubTable.getSelectedRows ();
        l_SelectedInvoiceStubs = new InvoiceStub [l_Selection];
        
        for (l_Selection = 0; l_Selection < l_SelectedRows.length; l_Selection++)
            {
        	l_ModelRow = this.modelIndex(l_SelectedRows [l_Selection]);
        	l_SelectedInvoiceStubs [l_Selection] = m_InvoiceStubs.getInvoiceStubAt (l_ModelRow);
            }
        }

    return (l_SelectedInvoiceStubs);
    }

//---------------------------------------------------------------------------

public int findInvoiceStub (Integer p_InvoiceId)
    {
    return m_InvoiceStubs.findInvoiceStub (p_InvoiceId);
    }    

//---------------------------------------------------------------------------

public boolean containsInvoiceStub (InvoiceStub p_Invoice)
	{
	return m_InvoiceStubs.containsInvoiceStub (p_Invoice);
	}

//---------------------------------------------------------------------------

public boolean selectInvoiceStub (Integer p_InvoiceId)
    {
    int			l_SelectedRow;
    boolean		l_IsSelected = false;		
	
    l_SelectedRow = m_InvoiceStubs.findInvoiceStub (p_InvoiceId);
    if (l_SelectedRow >= 0)
    	{
    	l_SelectedRow = m_InvoiceStubSorter.viewIndex(l_SelectedRow);
    	l_IsSelected = this.setSelection(l_SelectedRow,true);
    	}
    	
	return l_IsSelected;
    }
  
//---------------------------------------------------------------------------

public void selectInvoiceStubAt (int p_Row)
    {
    this.setSelection(p_Row,false);
    }
  
//---------------------------------------------------------------------------

public boolean selectNextInvoiceStub ()
	{
    int l_SelectedRow	 = 0;
     
    l_SelectedRow = m_InvoiceStubTable.getSelectedRow ();
    if (l_SelectedRow >= 0) 
    	 l_SelectedRow++;
    else l_SelectedRow = 0;
    return (this.setSelection(l_SelectedRow,true));
	}

//---------------------------------------------------------------------------

public boolean selectPreviousInvoiceStub ()
	{
	int l_SelectedRow = 0;
	
	l_SelectedRow = m_InvoiceStubTable.getSelectedRow ();
	if (l_SelectedRow >= 0) l_SelectedRow--;
					   else l_SelectedRow = m_InvoiceStubTable.getRowCount() - 1;
	return (this.setSelection(l_SelectedRow,true));
	}

//---------------------------------------------------------------------------

public void selectFirstInvoiceStub ()
	{
	this.setSelection(0,true);
	}

//---------------------------------------------------------------------------

public void selectLastInvoiceStub ()
	{
	int	l_LastRow;
	
	l_LastRow = m_InvoiceStubTable.getRowCount() - 1;
	this.setSelection(l_LastRow,true);
	}

//---------------------------------------------------------------------------

public InvoiceStub getSelectedInvoiceStub ()
	{
	int     l_SelectedRow		= 0;
    int			l_ModelRow;
	InvoiceStub	l_SelectedInvoice	= null;

	l_SelectedRow = m_InvoiceStubTable.getSelectedRow ();
	if (l_SelectedRow >= 0) 
		{
       	l_ModelRow = this.modelIndex(l_SelectedRow);
		l_SelectedInvoice = m_InvoiceStubs.getInvoiceStubAt(l_ModelRow);
		}
		
	return l_SelectedInvoice;
	}

//---------------------------------------------------------------------------

public void setSelectedInvoiceStub (InvoiceStub p_InvoiceStub)
	{
	int     l_SelectedRow	= 0;
	  
	if (p_InvoiceStub == null) return;
	
	l_SelectedRow = m_InvoiceStubTable.getSelectedRow ();
	if (l_SelectedRow >= 0) 
		{
		l_SelectedRow = this.modelIndex(l_SelectedRow);
		m_InvoiceStubs.setInvoiceStubAt (p_InvoiceStub,l_SelectedRow);
		m_InvoiceStubTable.invalidate();
		}
	}

//---------------------------------------------------------------------------

public void setInvoiceStubs (Collection <InvoiceStub> p_InvoiceStubs)
    {
    m_InvoiceStubs.setInvoiceStubs (p_InvoiceStubs);
    }    
 
//---------------------------------------------------------------------------

public Collection <InvoiceStub> getInvoiceStubs ()
    {
    return m_InvoiceStubs.getInvoiceStubs();
    }    
    
//---------------------------------------------------------------------------

public int getNumberOfInvoiceStubs ()
	{
	return m_InvoiceStubs.getRowCount();
	}

//---------------------------------------------------------------------------

public void packColumns ()
	{
	int l_Column;
	
	for (l_Column=0; l_Column < m_InvoiceStubTable.getColumnCount(); l_Column++)
		{
		packColumn (l_Column,c_CellMargin);
		}
	}

//---------------------------------------------------------------------------

public void packRows ()
	{
	int l_Row;
	
	for (l_Row=0; l_Row < m_InvoiceStubTable.getRowCount(); l_Row++)
		{
		packRow (l_Row,c_CellMargin);
		}
	}

/* ======================================== */
// 		HELP METHODS
/* ======================================== */

private void adaptColumns ()
	{
	}

//***************************************************************************
//* End of Class															*
//***************************************************************************
}
