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

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import javax.swing.table.DefaultTableModel;

import lu.tudor.santec.gecamed.core.gui.GECAMedLog;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.waitingroom.ejb.entity.beans.Queue;
import lu.tudor.santec.gecamed.waitingroom.ejb.session.beans.WaitingroomManagerBean;
import lu.tudor.santec.gecamed.waitingroom.ejb.session.interfaces.WaitingroomManager;
import lu.tudor.santec.gecamed.waitingroom.ejb.session.util.QueueUpdateEvent;
import lu.tudor.santec.gecamed.waitingroom.gui.widgets.QueueEditDialog;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Logger;

public class WaitingroomTableModel extends DefaultTableModel{

	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger.getLogger(WaitingroomTableModel.class.getName());
	
	private static final long serialVersionUID = 1L;
	
	private List<Queue> data = Collections.synchronizedList(new ArrayList<Queue>());

	public int mode;

	private boolean showIsVisit;

	private Vector<Object> cachedData = new Vector<Object>();

	private HashMap<Integer, Queue> row2QueueLink = new HashMap<Integer, Queue>();

	private WaitingroomManager manager;

	private WaitingroomModule module;

	
	
	public WaitingroomTableModel(int mode, boolean showIsVisit) {
		/* ================================================== */
		this.mode = mode;
		this.showIsVisit = showIsVisit;
		
		this.manager = (WaitingroomManager) ManagerFactory.getRemote(WaitingroomManagerBean.class);
		/* ================================================== */
	}



	/* (non-Javadoc)
	 * @see javax.swing.table.DefaultTableModel#getColumnCount()
	 */
	@Override
	public int getColumnCount() {
		/* ====================================================== */
		if (showIsVisit)
		    return 4;
		else
		    return 3;
		/* ====================================================== */
	}




	/* (non-Javadoc)
	 * @see javax.swing.table.DefaultTableModel#getRowCount()
	 */
	@Override
	public int getRowCount() {
		/* ====================================================== */
		if (data == null)
			return 0;
		
//		return data.size();
		return cachedData.size();
		/* ====================================================== */
	}


	/* (non-Javadoc)
	 * @see javax.swing.table.DefaultTableModel#getValueAt(int, int)
	 */
	@Override
	public Object getValueAt(int row, int column) {
		/* ====================================================== */
		if (row > cachedData.size()) 
			return null;
		
		
		Object obj = null;
		try {
			obj = cachedData.get(row);			
		} catch (ArrayIndexOutOfBoundsException e) {
			return null;
		}
		
		/* ------------------------------------------------------- */
		if (obj == null)
			return null;
		/* ------------------------------------------------------- */
		if (obj instanceof Queue) {
			Queue q = (Queue) obj;
			/* ------------------------------------------------------- */
			if (column == 0)
				return q.getStartDate();
			else if (column == 1)
				return q;
			else if (column == 2) {
				/* ------------------------------------------------------- */
				if (mode == Waitingroom.MODE_PHYSICIAN)
					return q.getTreated();
				/* ------------------------------------------------------- */
				return q.getIsPresent();
				/* ------------------------------------------------------- */
			} else if (column == 3) {
				/* ------------------------------------------------------- */
			    	if (q.getIsVisit() == null)
			    	    return false;
			    	else
			    	    return q.getIsVisit();
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		} else {
			/* ------------------------------------------------------- */
			// probabply String =)
			/* ------------------------------------------------------- */
			String comment = (String) obj;
			if (column == 0)
				return null;
			if (column == 1)
				return comment;
			if (column == 2) {
				/* ------------------------------------------------------- */
				return null;
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		
		return null;
		/* ====================================================== */
	}
	

	/* (non-Javadoc)
	 * @see javax.swing.table.DefaultTableModel#isCellEditable(int, int)
	 */
	@Override
	public boolean isCellEditable(int row, int column) {
		/* ====================================================== */
		Object obj = cachedData.get(row);
		/* ------------------------------------------------------- */
		if (obj instanceof Queue && column == 3)
			return true;
		if (obj instanceof Queue && column == 2)
			return true;
		if (obj instanceof String && column == 1)
			return true;
		/* ------------------------------------------------------- */
		
		return false;
		/* ====================================================== */
	}



	/* (non-Javadoc)
	 * @see javax.swing.table.DefaultTableModel#moveRow(int, int, int)
	 */
	@Override
	public void moveRow(int start, int end, int to) {
		/* ====================================================== */
		// TODO Auto-generated method stub
		super.moveRow(start, end, to);
		/* ====================================================== */
	}

	

	/* (non-Javadoc)
	 * @see javax.swing.table.DefaultTableModel#setValueAt(java.lang.Object, int, int)
	 */
	@Override
	public void setValueAt(Object arg0, int row, int column) {
		/* ====================================================== */
	    	if (column == 3) {
        		/* ------------------------------------------------------- */
        //		Queue q = data.get(row);
        		Object obj = cachedData.get(row);
        		Queue q = (Queue) obj;
        		/* ------------------------------------------------------- */
        		q.setIsVisit((Boolean) arg0);
        		/* ------------------------------------------------------- */
        		saveQueue(q, null);
        		
        		fireTableCellUpdated(row, column);
        		/* ------------------------------------------------------- */
	    	} else if (column == 2) {
			/* ------------------------------------------------------- */
//			Queue q = data.get(row);
			Object obj = cachedData.get(row);
			Queue q = (Queue) obj;
			/* ------------------------------------------------------- */
			if (mode == Waitingroom.MODE_PHYSICIAN)
				q.setTreated((Boolean) arg0);
			else
				q.setIsPresent((Boolean) arg0);
			/* ------------------------------------------------------- */
			saveQueue(q, null);
			
			fireTableCellUpdated(row, column);
			/* ------------------------------------------------------- */
		} else if (column == 1) {
			/* ------------------------------------------------------- */
			if (cachedData.get(row) instanceof String) {
				/* ------------------------------------------------------- */
				Queue q = getQueue(row);
				q.setDescription((String) arg0);
				
				saveQueue(q, null);
				
				fireTableCellUpdated(row, column);
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		/* ====================================================== */
	}

	
	public void setQueue(Queue q, Integer oldRoom) {
		int i = this.data.indexOf(q);
		saveQueue(q, oldRoom);

		if (i > 0) {
			this.data.set(i, q);			
		} else {
			this.data.add(q);
		}
		
		createCacheData();
		fireTableDataChanged();
	}
	
	/**
	 * @param q
	 */
	protected void saveQueue(Queue q, Integer oldRoom) {
		/* ================================================== */
		try {
			/* --------------------------------------------- */
			manager.saveQueue(q, MainFrame.getClientId(), oldRoom);			
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			logger.error("Error saving Queue event", e);
			/* --------------------------------------------- */
		}
		/* ================================================== */
	}
	

	/**
	 * @param queues
	 */
	public void setData(List<Queue> queues) {
		/* ====================================================== */
		this.data.clear();
		/* ------------------------------------------------------- */
		if (data != null && queues != null)
		    for (Queue queue : queues) {	
			if (queue != null)
			    data.add(queue);
		    }
		createCacheData();
		/* ------------------------------------------------------- */
		fireTableDataChanged();
		/* ====================================================== */
	}

	
	/**
	 * 
	 */
	public void createCacheData() {
		/* ================================================== */
		this.cachedData.clear();
		this.row2QueueLink.clear();
		/* ------------------------------------------------------- */
		for (Queue q : this.data) {
			/* ------------------------------------------------------- */
			this.cachedData.add(q);
			row2QueueLink.put(cachedData.indexOf(q), q);
			if (q != null && q.getDescription() != null && !"".equals(q.getDescription())) {
				String desc = q.getDescription().replace("\n", " ");
				/* ------------------------------------------------------- */
				cachedData.add(desc);
				row2QueueLink.put(cachedData.indexOf(desc), q);
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}
	

	/* (non-Javadoc)
	 * @see javax.swing.table.AbstractTableModel#getColumnClass(int)
	 */
	@Override
	public Class<?> getColumnClass(int arg0) {
		/* ====================================================== */
		if (arg0 == 3)
			return Boolean.class;
		if (arg0 == 2)
			return Boolean.class;
		return super.getColumnClass(arg0);
		/* ====================================================== */
	}



	public void setTreated(int row) {
		/* ====================================================== */
		this.setValueAt(true, row, 2);
		/* ====================================================== */
	}


	public Queue getQueue(int row) {
		/* ====================================================== */
//		return data.get(row);
		return row2QueueLink.get(row);
		/* ====================================================== */
	}

	public Queue getQueueByID(int id) {
		/* ====================================================== */
		if (data != null) {
			for (Queue q : data) {
				if (q.getId() == id) 
					return q;
			}			
		}
		return null;
		/* ====================================================== */
	}

	/**
	 * @param selectedRow
	 */
	public void toggleTreated(int selectedRow) {
		/* ====================================================== */
		Queue q = getQueue(selectedRow);
		q.setTreated(!q.getTreated());
		
		saveQueue(q, null);
		
		fireTableDataChanged();
		/* ====================================================== */
	}
	
	/**
	 * @param selectedRow
	 */
	public void toggleEmergency(int selectedRow) {
		/* ================================================== */
		Queue q = getQueue(selectedRow);
		q.setEmergency(!q.getEmergency());
		/* ------------------------------------------------------- */
		saveQueue(q, null);
		/* ================================================== */
	}
	
	
	/**
	 * @param selectedRow
	 */
	public void togglePresence(int selectedRow) {
		/* ================================================== */
		Queue q = getQueue(selectedRow);
		q.setIsPresent(!q.getIsPresent());
		// TODO set end date if the patient is leaving
		if(!q.getIsPresent()) q.setEndDate(new Date());
		/* ------------------------------------------------------- */
		saveQueue(q, null);
		/* ================================================== */
	}
	
	
	/**
	 * @param selectedRow
	 */
	public void setKilometers(int selectedRow, Integer kilometers) {
		/* ================================================== */
		Queue q = getQueue(selectedRow);
		q.setKilometers(kilometers);
		/* ------------------------------------------------------- */
		saveQueue(q, null);
		/* ================================================== */
	}
	
	@Override
	public void removeRow(int row) {
		long start = System.currentTimeMillis();
		/* ================================================== */
		Queue q = getQueue(row);
		this.data.remove(q);
		try {
			/* --------------------------------------------- */
			manager.removeQueue(q, MainFrame.getClientId());
			
			long took = (System.currentTimeMillis()-start);
			GECAMedLog.user(WaitingroomModule.MODULE_NAME,	WaitingroomModule.WAITINGROOM_REMOVE,
			    		"Patient " + q.getPatientName() + " removed from Waitingroom " + q.getRoomId(), took);
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			logger.error("Error removing queue event", e);
			/* --------------------------------------------- */
		}
		/* ================================================== */
	}
	
	public String getToolTip( int row, int column) {
		switch (column) {
		case 2:
		    if (mode == Waitingroom.MODE_PHYSICIAN)
			return Translatrix.getTranslationString("waitingroom.treated") ;
		    else
			return Translatrix.getTranslationString("waitingroom.present") ;
		case 3:
		    return Translatrix.getTranslationString("waitingroom.isVisit") ;
		default:
			try {
				return getQueue(row).toToolTip();
			} catch (Exception e) {}
		    return null;
		}
	}
	
	
	/**
	 * updates the model regarding on the given QueueUpdateEvent
	 * an item may be updates/deleted or added.
	 * 
	 * @param update
	 */
	public void updateModel(QueueUpdateEvent update)
	{
	    if (update == null) 
		return;
	    
	    try {
	    	if (QueueUpdateEvent.ENTRY_DELETE.equals(update.getStatus()))
	    	{
	    		this.data.remove(update.getEntry());
	    	} else {
	    		int index = this.data.indexOf(update.getEntry());
	    		if (index >= 0)
	    		{
	    			// remove old
	    			this.data.remove(index);
	    		} //else {
	    			index = 0;
	    			// find place to add new entry
	    			for (int i = 0; i < this.data.size(); i++)
	    			{
	    				Queue q = this.data.get(i);
	    				if (q == null) continue;
	    				
	    				index = i;
	    				if (q.getStartDate().after(update.getEntry().getStartDate())) {
	    					break;
	    				}
	    				index++;
	    			//}
	    		}
	    		// add entry
	    		this.data.add(index, update.getEntry());
	    	}
	    } catch (Exception e) {
	    	e.printStackTrace();
	    }
	    
	    createCacheData();
	    fireTableDataChanged();
	}	
	
	public void editQueue(Queue q) {
		Integer oldRoom = q.getRoomId();
		QueueEditDialog sd = new QueueEditDialog();	
		q = sd.showDialog(q);
		
		setQueue(q, oldRoom);
		
		if (module != null) {
			module.reload(false);							
		}
	}

	public void setModule(WaitingroomModule module) {
		this.module = module;
	}
}
