/*******************************************************************************
 * 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.agenda.gui.widgets;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;

import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.AgendaCalendar;
import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.Appointment;
import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.AppointmentType;
import lu.tudor.santec.gecamed.agenda.ejb.session.beans.AppointmentManagerBean;
import lu.tudor.santec.gecamed.agenda.ejb.session.interfaces.AppointmentManager;
import lu.tudor.santec.gecamed.agenda.gui.AgendaModule;
import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedGuiUtils;
import lu.tudor.santec.gecamed.core.gui.utils.LineColorCellRenderer;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import bizcal.util.DateUtil;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

/**
 * Dialog to find appointments in the database. It looks fro keywords entered in the textfield on top.
 * 
 * The dialog can be in two different states.
 * STATE_SEARCH, in this state, the "ENTER" action will perform the
 * search for the appointemnts.
 * STATE_OPEN, in this state, the "ENTER" action will open the selected
 * appointment in the list, and close the dialog.
 * 
 * The state is switched to STATE_SEARCH when the text in the searchField has been modified.
 * When the arrow key up/down have been pressed, the state is switched to STATE_OPEN, or
 * if the selection in the JTable has changed.
	
 * 
 * @author martin.heinemann@tudor.lu
 * 18.01.2008
 * 09:46:42
 *
 *
 * @version
 * <br>$Log: AppointmentSearchDialog.java,v $
 * <br>Revision 1.19  2014-02-21 08:45:10  ferring
 * <br>Search also for selected, not only for checked calendars
 * <br>
 * <br>Revision 1.18  2013-12-27 18:08:19  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.17  2013-07-15 06:18:35  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.16  2012-04-24 14:02:13  troth
 * <br>Remove same warnings.
 * <br>
 * <br>Revision 1.15  2011-09-22 13:29:50  hermen
 * <br>- changed transparencies in appointmentlist renderer
 * <br>- fixed new column problem im appointmentfinder
 * <br>
 * <br>Revision 1.14  2011-04-05 08:43:15  troth
 * <br>fix some warnings
 * <br>
 * <br>Revision 1.13  2010-03-03 15:46:47  troth
 * <br>add logger warning
 * <br>
 * <br>Revision 1.12  2008-09-25 09:42:27  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.11  2008-05-27 09:22:30  hermen
 * <br>fixed nullpointer if searching with no callendar selected
 * <br>
 * <br>Revision 1.10  2008-03-11 17:17:11  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.9  2008-01-18 16:09:05  heinemann
 * <br>code cleanup and java doc
 * <br>
 *   
 */
public class AppointmentSearchDialog extends GECAMedBaseDialog implements ActionListener, MouseListener, KeyListener, DocumentListener, ListSelectionListener {

	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger
			.getLogger(AppointmentSearchDialog.class.getName());
	
	// ======================================================

	
	private static final int STATE_SEARCH = 1;
	private static final int STATE_OPEN   = 2;
	
	
	
	private int actionState = STATE_SEARCH; 
	
	
	private static final long serialVersionUID = 1L;
	private AgendaModule agendaModule;
	private JTextField searchField;
	private JButton searchButton;
	private JTable table;
	private AppointmentManager aManager;
	private AppointmentTableModel tableModel;
	private JPanel mainPanel;
	
	/**
	 * @param parent
	 */
	public AppointmentSearchDialog(AgendaModule parent) {
		super(Translatrix.getTranslationString("Agenda.searchAppointment"));
		this.agendaModule = parent;
		this.mainPanel = new JPanel();
		this.mainPanel.setLayout(new BorderLayout(4,4));
		this.mainPanel.setBackground(GECAMedColors.c_GECAMedBackground);
		
		CellConstraints cc = new CellConstraints();
		JPanel searchPanel = new JPanel(new FormLayout(
				"3dlu, pref, 3dlu, pref:grow, 3dlu, pref",
		"3dlu, fill:pref, 3dlu"));
		searchPanel.setOpaque(false);
		searchPanel.setBorder(new TitledBorder(Translatrix.getTranslationString("Agenda.searchAppointment")));
		
		searchPanel.add(new JLabel(Translatrix.getTranslationString("Agenda.searchString")), cc.xy(2,2));
		
		this.searchField = new JTextField();
		this.searchField.addActionListener(this);
		this.searchField.addKeyListener(this);
		this.searchField.getDocument().addDocumentListener(this);
		searchPanel.add(searchField, cc.xy(4,2));
		
		this.searchButton = new JButton(Translatrix.getTranslationString("core.search"));
		this.searchButton.addActionListener(this);
		searchPanel.add(searchButton, cc.xy(6,2));
		
		this.add(searchPanel, BorderLayout.NORTH);
		
		this.tableModel = new AppointmentTableModel();
		this.table = new JTable(tableModel);
		this.table.addMouseListener(this);
		AppointmentRenderer renderer = new AppointmentRenderer(this.tableModel);
		this.table.getColumnModel().getColumn(0).setCellRenderer(renderer);
		this.table.getColumnModel().getColumn(1).setCellRenderer(renderer);
		this.table.getColumnModel().getColumn(2).setCellRenderer(renderer);
		this.table.getColumnModel().getColumn(3).setCellRenderer(renderer);

		this.table.getColumnModel().getColumn(0).setMinWidth(110);
		this.table.getColumnModel().getColumn(0).setMaxWidth(110);
		this.table.getColumnModel().getColumn(1).setMinWidth(30);
		this.table.getColumnModel().getColumn(1).setMaxWidth(30);
		this.table.getColumnModel().getColumn(2).setMinWidth(100);
		this.table.getColumnModel().getColumn(2).setMaxWidth(100);
		this.table.setRowHeight(32);
		this.table.setAutoscrolls(true);
		this.table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		this.table.addKeyListener(this);
		/* ------------------------------------------------------- */
		// selection listener to switch the state
		this.table.getSelectionModel().addListSelectionListener(this);
		
		
		JScrollPane jsp = new JScrollPane(this.table);
		jsp.setOpaque(false);
		jsp.getViewport().setOpaque(false);
		jsp.setBorder(new TitledBorder(Translatrix.getTranslationString("Agenda.searchResults")));
		this.add(jsp, BorderLayout.CENTER);
		/* ------------------------------------------------------- */
		
		this.okButton.addActionListener(this);
		this.cancelButton.addActionListener(this);
		/* ------------------------------------------------------- */
		
		aManager = (AppointmentManager)
		ManagerFactory.getRemote(AppointmentManagerBean.class);
	}
	
	/**
	 * 
	 */
	public void showDialog() {
		/* ================================================== */
		this.tableModel.setAppointments(null);
		this.searchField.setText("");
		this.searchField.requestFocus();
		
		actionState = STATE_SEARCH;
		
		this.setSize(650,500);
		this.setLocationRelativeTo(agendaModule);
		this.setVisible(true);
		/* ================================================== */
	}

	/* (non-Javadoc)
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		/* ================================================== */
		if (e.getSource().equals(this.searchButton) || e.getSource().equals(searchField)) {
			/* ------------------------------------------------------- */
			if (STATE_SEARCH == actionState)
				search();
			else
				if (STATE_OPEN == actionState)
					agendaModule.setDate(getSelectedAppointment().getStartDate());
					
			/* ------------------------------------------------------- */
		} else if (e.getSource().equals(this.cancelButton)) {
			this.setVisible(false);
		} else if (e.getSource().equals(this.okButton)) {
			try {
				agendaModule.setDate(getSelectedAppointment().getStartDate());				
			} catch (Exception ee) {}
			this.setVisible(false);
		}
		/* ================================================== */
	}
	
	private Appointment getSelectedAppointment() {
		int row = this.table.getSelectedRow();
		return this.tableModel.getAppointment(row);
	}

	
	private void search ()
	{
		Collection<AgendaCalendar> checkedCalendars = agendaModule.getCheckedCalendars();
		AgendaCalendar selectedCalendar = agendaModule.getSelectedCalendar();
		
		
		if (checkedCalendars == null)
			checkedCalendars = new ArrayList<AgendaCalendar>(1);
		
		if (selectedCalendar != null)
			checkedCalendars.add(selectedCalendar);
		
		if (!checkedCalendars.isEmpty())
		{
			try
			{
				Collection<Appointment> appointments = aManager.searchAppointments(checkedCalendars, "%" + searchField.getText() + "%");
				if (appointments != null)
					this.tableModel.setAppointments(appointments);
				else
					this.tableModel.setAppointments(new ArrayList<Appointment>());
			}
			catch (Exception e)
			{
				logger.log(Level.WARN, "Error searching appointments: " + e.getLocalizedMessage(), e);
			}
		}
	}

	public void mouseClicked(MouseEvent e) {
		if (e.getClickCount() >= 2) {
			try {
				agendaModule.setDate(getSelectedAppointment().getStartDate());				
			} catch (Exception ee) {}
		}
	}

	public void mouseEntered(MouseEvent e) {}

	public void mouseExited(MouseEvent e) {}

	public void mousePressed(MouseEvent e) {}

	public void mouseReleased(MouseEvent e) {}

	
	// ========================================================================================
	// key listener methods for the searchfield
	// the arrow keys wil lbe piped to the table
	// ========================================================================================
	
	public void keyPressed(KeyEvent e) {
		/* ====================================================== */
		if (searchField.equals(e.getSource())) {
			/* ------------------------------------------------------- */
			if (KeyEvent.VK_DOWN == e.getKeyCode()) {
				try {
					int row = table.getSelectedRow();
					table.setRowSelectionInterval(row+1, row+1);
					actionState = STATE_OPEN;
				} catch (Exception ee) {
				}
				
			} else
				if (KeyEvent.VK_UP == e.getKeyCode()) {
					try {
						int row = table.getSelectedRow();
						table.setRowSelectionInterval(row-1, row-1);
						actionState = STATE_OPEN;
					} catch (Exception ee) {
					}
				}
			/* ------------------------------------------------------- */
		}
		if (table.equals(e.getSource())) {
			/* ------------------------------------------------------- */
//			System.out.println("ENTER");
			if (KeyEvent.VK_ENTER == e.getKeyCode()) {
				e.consume();
				
			}
			/* ------------------------------------------------------- */
		}
		/* ====================================================== */
	}

	public void keyReleased(KeyEvent e) {
		if (table.equals(e.getSource())) {
			/* ------------------------------------------------------- */
			if (KeyEvent.VK_ENTER == e.getKeyCode()) {
				e.consume();
				searchButton.doClick();
			}
			/* ------------------------------------------------------- */
		}
	}
	public void keyTyped(KeyEvent e) {
		if (table.equals(e.getSource())) {
			/* ------------------------------------------------------- */
			if (KeyEvent.VK_ENTER == e.getKeyCode()) {
				e.consume();
			}
			/* ------------------------------------------------------- */
		}
	}
	
	
	// ========================================================================================
	// document listener methods for the searchfield
	// the state will be switched
	// ========================================================================================

	public void changedUpdate(DocumentEvent e) {
		/* ====================================================== */
		actionState = STATE_SEARCH;
		/* ====================================================== */
	}
	public void insertUpdate(DocumentEvent e) {
		/* ====================================================== */
		actionState = STATE_SEARCH;
		/* ====================================================== */
	}
	public void removeUpdate(DocumentEvent e) {
		/* ====================================================== */
		actionState = STATE_SEARCH;
		/* ====================================================== */
	}
	
	// ========================================================================================
	// selection listener method for the JTable
	// the state will be switched
	// ========================================================================================

	public void valueChanged(ListSelectionEvent e) {
		/* ====================================================== */
		if (tableModel.getRowCount() > 0)
			actionState = STATE_OPEN;
		table.scrollRectToVisible(table.getCellRect(table.getSelectedRow(),0,true));
		/* ====================================================== */
	}
	
	
	/**
	 * @author johannes.hermen(at)tudor.lu
	 * 02.08.2007
	 * 15:48:42
	 *
	 *
	 * @version
	 * <br>$Log: AppointmentSearchDialog.java,v $
	 * <br>Revision 1.19  2014-02-21 08:45:10  ferring
	 * <br>Search also for selected, not only for checked calendars
	 * <br>
	 * <br>Revision 1.18  2013-12-27 18:08:19  donak
	 * <br>Cleanup of imports
	 * <br>
	 * <br>Revision 1.17  2013-07-15 06:18:35  ferring
	 * <br>logging changed
	 * <br>
	 * <br>Revision 1.16  2012-04-24 14:02:13  troth
	 * <br>Remove same warnings.
	 * <br>
	 * <br>Revision 1.15  2011-09-22 13:29:50  hermen
	 * <br>- changed transparencies in appointmentlist renderer
	 * <br>- fixed new column problem im appointmentfinder
	 * <br>
	 * <br>Revision 1.14  2011-04-05 08:43:15  troth
	 * <br>fix some warnings
	 * <br>
	 * <br>Revision 1.13  2010-03-03 15:46:47  troth
	 * <br>add logger warning
	 * <br>
	 * <br>Revision 1.12  2008-09-25 09:42:27  heinemann
	 * <br>fixed copyrights
	 * <br>
	 * <br>Revision 1.11  2008-05-27 09:22:30  hermen
	 * <br>fixed nullpointer if searching with no callendar selected
	 * <br>
	 * <br>Revision 1.10  2008-03-11 17:17:11  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.9  2008-01-18 16:09:05  heinemann
	 * <br>code cleanup and java doc
	 * <br>
	 * <br>Revision 1.8  2007-12-17 14:59:59  heinemann
	 * <br>plugins and file store and open
	 * <br>
	 * <br>Revision 1.7  2007-11-20 08:58:54  hermen
	 * <br>moved Managerfactory to core.utils and refactured code to use ManagerFactory instead of context.lookup
	 * <br>
	 * <br>Revision 1.6  2007-10-22 09:58:14  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.5  2007/08/09 14:10:34  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 *   
	 */
	public class AppointmentTableModel extends AbstractTableModel  {

		private static final long serialVersionUID = 1L;
		
		private ArrayList<Appointment> data = new ArrayList<Appointment>();
		
//		private DateFormat dateTime = new SimpleDateFormat("dd.MM.yy HH:mm", Translatrix.getLocale());
//		private DateFormat date = new SimpleDateFormat("EEE dd.MM.yy", Translatrix.getLocale());
//		private DateFormat time = new SimpleDateFormat("HH:mm", Translatrix.getLocale());
		
		private DateFormat dateTime = GECAMedGuiUtils.getDateTimeFormat(false);
		private DateFormat date = GECAMedGuiUtils.getDateFormat(false);
		private DateFormat time = GECAMedGuiUtils.getTimeFormat(false);
		
		private String[] columnNames = {
			Translatrix.getTranslationString("bizcal.date"),
			Translatrix.getTranslationString("bizcal.type"),
			Translatrix.getTranslationString("bizcal.calendar"),
			Translatrix.getTranslationString("bizcal.desc")
		};
		
		private Class<?>[] columnClasses = {
			String.class,
			Integer.class,
			Integer.class,
			String.class
		};
		

		public int getColumnCount() {
			return columnNames.length;
		}
		
		@Override
		public Class<?> getColumnClass(int columnIndex) {
			return columnClasses[columnIndex];
		}

		public int getRowCount() {
			return data.size();
		}

		@Override
		public String getColumnName(int column) {
			return columnNames[column];
		}

		public Object getValueAt(int rowIndex, int columnIndex) {
			
			Appointment e = data.get(rowIndex);
			if (e == null) 
				return null;
			
			switch (columnIndex) {
			case 0:
				String str = "";
				try {
						if (DateUtil.isSameDayOfYear(e.getStartDate(), e.getEndDate())) {
							String d = date.format(e.getStartDate());
							d = d.substring(0,1).toUpperCase() + d.substring(1);
							str = "<html><b>" + d + "</b><br>" + time.format(e.getStartDate()) + " - " + time.format(e.getEndDate());
						} else {
							str = "<html><b>" + dateTime.format(e.getStartDate()) + "</b><br>" + dateTime.format(e.getEndDate());
						}
						
					} catch (Exception e1) {
						logger.log(Level.WARN, "listmodel dateformating creation failed", e1);
					}
				return str;
			case 1:
				return e.getTypeId();
			case 2:
				return e.getCalendarId();
			case 3:
				return "<html><b>" 
					+ (e.getSummary()!=null?e.getSummary():"") 
					+ "</b><br>" + (e.getDescription()!=null?e.getDescription():"");
			default:
				break;
			}
			return null;
		}
		
		public void setAppointments(Collection<Appointment> app) {
			if (app != null)
				this.data = new ArrayList<Appointment>(app);
			else
				this.data = new ArrayList<Appointment>();
			fireTableDataChanged();
		}

		public Appointment getAppointment(int row) {
			try {
				return data.get(row);				
			} catch (Exception e) {
			}
			return null;
		}

	}

	/**
	 * @author johannes.hermen(at)tudor.lu
	 * 02.08.2007
	 * 15:48:13
	 *
	 *
	 * @version
	 * <br>$Log: AppointmentSearchDialog.java,v $
	 * <br>Revision 1.19  2014-02-21 08:45:10  ferring
	 * <br>Search also for selected, not only for checked calendars
	 * <br>
	 * <br>Revision 1.18  2013-12-27 18:08:19  donak
	 * <br>Cleanup of imports
	 * <br>
	 * <br>Revision 1.17  2013-07-15 06:18:35  ferring
	 * <br>logging changed
	 * <br>
	 * <br>Revision 1.16  2012-04-24 14:02:13  troth
	 * <br>Remove same warnings.
	 * <br>
	 * <br>Revision 1.15  2011-09-22 13:29:50  hermen
	 * <br>- changed transparencies in appointmentlist renderer
	 * <br>- fixed new column problem im appointmentfinder
	 * <br>
	 * <br>Revision 1.14  2011-04-05 08:43:15  troth
	 * <br>fix some warnings
	 * <br>
	 * <br>Revision 1.13  2010-03-03 15:46:47  troth
	 * <br>add logger warning
	 * <br>
	 * <br>Revision 1.12  2008-09-25 09:42:27  heinemann
	 * <br>fixed copyrights
	 * <br>
	 * <br>Revision 1.11  2008-05-27 09:22:30  hermen
	 * <br>fixed nullpointer if searching with no callendar selected
	 * <br>
	 * <br>Revision 1.10  2008-03-11 17:17:11  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.9  2008-01-18 16:09:05  heinemann
	 * <br>code cleanup and java doc
	 * <br>
	 * <br>Revision 1.8  2007-12-17 14:59:59  heinemann
	 * <br>plugins and file store and open
	 * <br>
	 * <br>Revision 1.7  2007-11-20 08:58:54  hermen
	 * <br>moved Managerfactory to core.utils and refactured code to use ManagerFactory instead of context.lookup
	 * <br>
	 * <br>Revision 1.6  2007-10-22 09:58:14  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.5  2007/08/09 14:10:34  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 *   
	 */
	public class AppointmentRenderer extends LineColorCellRenderer {

		private static final long serialVersionUID = 1L;

		private AppointmentTableModel model;
		
		public AppointmentRenderer(AppointmentTableModel listModel) {
			this.model = listModel;
			this.setFont(new Font("Arial", Font.PLAIN, 12));
		}

		public Component getTableCellRendererComponent(JTable p_Table, Object value, boolean p_IsSelected, boolean hasFocus, int p_Row, int p_Column) {
			Appointment app = model.getAppointment(p_Row); 
			AgendaCalendar cal = AgendaModule.getCalendarForId(app.getCalendarId());
			Color c = Color.WHITE;
			try {
				c = new Color(cal.getColor());		
				if (new Date().before(app.getEndDate()))
					c = new Color(c.getRed(),c.getGreen(),c.getBlue(),120);
				else
					c = new Color(c.getRed(),c.getGreen(),c.getBlue(),20);

			} catch (Exception ee) {
			}

			
			switch (p_Column) {
			case 0:
				this.setVerticalAlignment(JLabel.TOP);
				this.setHorizontalAlignment(JLabel.LEFT);
				this.setText((String) value);
				this.setIcon(null);
				break;
			case 1:
				this.setVerticalAlignment(JLabel.CENTER);
				this.setHorizontalAlignment(JLabel.CENTER);
				this.setText("");
				try {
					AppointmentType at = AgendaModule.getTypeForId((Integer)value);
					this.setIcon(AgendaModule.getMiniIcon(at.getIcon()));					
				} catch (Exception ee) {
				}
				break;
			case 2:
				this.setVerticalAlignment(JLabel.CENTER);
				this.setHorizontalAlignment(JLabel.CENTER);
				try {
					this.setText(cal.getTitle());					
				} catch (Exception ee) {}
				this.setIcon(null);
				break;
			default:
				this.setVerticalAlignment(JLabel.TOP);
				this.setHorizontalAlignment(JLabel.LEFT);
				this.setText((String) value + "");
				this.setIcon(null);
			    if (p_Table.getRowHeight(p_Row) < this.getPreferredSize().height) {
			    	p_Table.setRowHeight(p_Row, this.getPreferredSize().height + 4);
			    }
			    break;
			}

			if (p_IsSelected)
				this.setBackground(p_Table.getSelectionBackground());
			else
				this.setBackground(c);
			return this;
		}

	}
}
