package lu.tudor.santec.gecamed.esante.gui.dialogs;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

import lu.tudor.santec.gecamed.esante.ejb.entity.beans.ESanteProperty;
import lu.tudor.santec.i18n.Translatrix;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: EHealthIdTableModel.java,v $
 * <br>Revision 1.3  2014-02-06 14:24:53  ferring
 * <br>user info will be added, if it doesn't exist and a bug fixed, which prevented the saving of changes in the reference ID and user info
 * <br>
 * <br>Revision 1.2  2014-02-04 10:08:39  ferring
 * <br>eSante ID management completed
 * <br>Only those documents will be shown, that are retrieved by the RSQ
 * <br>
 * <br>Revision 1.1  2014-01-29 16:57:50  donak
 * <br>Renamed references to HPD to eHealth in respect to the request of the eHealth Agency
 * <br>Removed template DSP-11-12 as it is not needed and was created only for internal testing purposes
 * <br>
 * <br>Revision 1.2  2014-01-28 17:55:31  donak
 * <br>adapted constants as term HDP ID should be replaced by eHealth ID
 * <br>
 * <br>Revision 1.1  2014-01-28 16:02:44  ferring
 * <br>eHealth ID management implemented
 * <br>
 */

public class EHealthIdTableModel implements TableModel
{
	/* ======================================== */
	// MEMBERS
	/* ======================================== */
	
	private Collection<TableModelListener>	listeners			= new HashSet<TableModelListener>();
	
	private List<EHealthIdModelEntry>		data				= new ArrayList<EHealthIdTableModel.EHealthIdModelEntry>();
	
	private Set<ESanteProperty>				changedProperties	= new HashSet<ESanteProperty>();
	
	private List<ESanteProperty>			newProperties		= new LinkedList<ESanteProperty>();
	
	private List<ESanteProperty>			deletedProperties	= new LinkedList<ESanteProperty>();
	
	private Set<String>						esanteUserIds		= new HashSet<String>();
	
	
	
	/* ======================================== */
	// CLASS BODY
	/* ======================================== */
	
	/**
	 * Clears the old data model and fills it with the data given.
	 * 
	 * @param userInfos The user information stored in the database
	 * @param eHealthIds The eHealth IDs stored in the database
	 */
	public void setData (Collection<ESanteProperty> userInfos, Collection<ESanteProperty> eHealthIds, ESanteProperty practiveEHealthId)
	{
		// clear
		changedProperties.clear();
		newProperties.clear();
		deletedProperties.clear();
		esanteUserIds.clear();
		data.clear();
		
		// prepare filling
		HashMap<String, ESanteProperty>	eHealthIdMap	= new HashMap<String, ESanteProperty>();
		eHealthIdMap.put(ESanteProperty.PROP_PRACTICE_EHEALTH_ID, practiveEHealthId);
		for (ESanteProperty p : eHealthIds)
			eHealthIdMap.put(p.getEsanteUserId(), p);
		
		// fill model
		ESanteProperty practiceIdName = new ESanteProperty();
		practiceIdName.setEsanteUserId(ESanteProperty.PROP_PRACTICE_EHEALTH_ID);
		practiceIdName.setValue(Translatrix.getTranslationString("esante.managementPanel.objectId.manageEHealthIds.practiceId"));
		data.add(new EHealthIdModelEntry(practiceIdName, practiveEHealthId));
		
		for (ESanteProperty p : userInfos)
		{
			data.add(new EHealthIdModelEntry(p, eHealthIdMap.get(p.getEsanteUserId())));
			esanteUserIds.add(p.getEsanteUserId());
		}
		
		// notify listeners
		fireModelChanged(0, data.size()-1, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT);
	}
	
	
	/**
	 * @return All properties that have been modified
	 */
	public Collection<ESanteProperty> getChangedProperties ()
	{
		if (newProperties.isEmpty())
		{
			return changedProperties;
		}
		else
		{
			List<ESanteProperty> changes = new ArrayList<ESanteProperty>(
					newProperties.size() + changedProperties.size());
			
			changes.addAll(newProperties);
			changes.addAll(changedProperties);
			
			return changedProperties;
		}
	}
	
	
	/**
	 * @return All properties that are marked to be removed.
	 */
	public Collection<ESanteProperty> getRemovedProperties ()
	{
		return deletedProperties;
	}
	
	
	public void addProperty ()
	{
		ESanteProperty newProperty	= new ESanteProperty();
		newProperty.setName(ESanteProperty.PROP_ESANTE_USER_INFO);
		newProperty.setValue("");
		newProperty.setEsanteUserId("");
		
		data.add(new EHealthIdModelEntry(newProperty, null));
		newProperties.add(newProperty);
		
		fireModelChanged(data.size()-2, data.size()-1, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT);
	}
	
	
	public void removeProperty (int row)
	{
		data.get(row).remove();
		
		fireModelChanged(row, row, TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE);
	}
	
	
	/* ---------------------------------------- */
	// TABLE MODEL METHODS
	/* ---------------------------------------- */
	
	public int getRowCount ()
	{
		return data.size();
	}
	
	
	public int getColumnCount ()
	{
		return EHealthIdEditDialog.COLUMN_IDENTIFIERS.length;
	}
	
	
	public String getColumnName (int columnIndex)
	{
		if (columnIndex < 0 || columnIndex >= EHealthIdEditDialog.COLUMN_IDENTIFIERS.length)
			return null;
		
		return EHealthIdEditDialog.COLUMN_IDENTIFIERS[columnIndex];
	}
	
	
	public Class<?> getColumnClass (int columnIndex)
	{
		return String.class;
	}
	
	
	public boolean isCellEditable (int rowIndex, int columnIndex)
	{
		return false;
	}
	
	
	public Object getValueAt (int rowIndex, int columnIndex)
	{
		switch (columnIndex)
		{
			case EHealthIdEditDialog.COLUMN_INDEX_OWNER:
				
				return data.get(rowIndex).getUserInfo();
				
			case EHealthIdEditDialog.COLUMN_INDEX_REF_ID:
				
				return data.get(rowIndex).getESanteUserId();
				
			case EHealthIdEditDialog.COLUMN_INDEX_EHEALTH_ID:
				
				return data.get(rowIndex).getEHealthId();
			
			default:
				return null;
		}
	}
	
	
	public void setValueAt (Object aValue, int rowIndex, int columnIndex)
	{
		String value	= aValue == null ? "" : aValue.toString();
		
		switch (columnIndex)
		{
			case EHealthIdEditDialog.COLUMN_INDEX_OWNER:
				
				if (rowIndex > 0)
					data.get(rowIndex).setUserInfo(value);
				break;
				
			case EHealthIdEditDialog.COLUMN_INDEX_REF_ID:
				
				if (rowIndex > 0)
					data.get(rowIndex).setESanteUserId(value);
				break;
				
			case EHealthIdEditDialog.COLUMN_INDEX_EHEALTH_ID:
				
				data.get(rowIndex).setEHealthId(value);
				break;
		}
		
		fireModelChanged(rowIndex, rowIndex, columnIndex, TableModelEvent.UPDATE);
	}
	
	
	public void addTableModelListener (TableModelListener l)
	{
		listeners.add(l);
	}
	
	
	public void removeTableModelListener (TableModelListener l)
	{
		listeners.remove(l);
	}
	
	
	
	/* ======================================== */
	// HELP METHODS
	/* ======================================== */
	
	private void fireModelChanged (int firstRow, int lastRow, int column, int type)
	{
		TableModelEvent e = new TableModelEvent(this, firstRow, lastRow, column, type);
		
		for (TableModelListener l : listeners)
			l.tableChanged(e);
	}
	
	
	
	/* ======================================== */
	// CLASS: EHealthIdModelEntry
	/* ======================================== */
	
	private class EHealthIdModelEntry
	{
		/* ======================================== */
		// MEMBERS
		/* ======================================== */
		
		private ESanteProperty	userInfo;
		private ESanteProperty	eHealthId;
		
		
		
		/* ======================================== */
		// CONSTRUCTORS
		/* ======================================== */
		
		public EHealthIdModelEntry (ESanteProperty userInfo, ESanteProperty eHealthId)
		{
			this.userInfo	= userInfo;
			this.eHealthId	= eHealthId;
			
			if (this.userInfo == null)
			{
				userInfo	= new ESanteProperty();
				if (this.eHealthId != null)
					userInfo.setEsanteUserId(this.eHealthId.getEsanteUserId());
			}
		}
		
		
		
		/* ======================================== */
		// GETTER & SETTER
		/* ======================================== */
		
		public String getEHealthId ()
		{
			if (eHealthId == null)
				return "";
			
			return eHealthId.getValue();
		}
		
		
		public void setEHealthId (String eHealthId)
		{
			if (eHealthId == null)
				eHealthId = "";
			
			if (this.eHealthId == null)
			{
				this.eHealthId	= new ESanteProperty();
				this.eHealthId.setName(ESanteProperty.PROP_USER_EHEALTH_ID);
				this.eHealthId.setEsanteUserId(userInfo.getEsanteUserId());
			}
			else if (eHealthId.equals(this.eHealthId.getValue()))
			{
				return;
			}
			
			this.eHealthId.setValue(eHealthId);
			changedProperties.add(this.eHealthId);
		}
		
		
		public String getESanteUserId ()
		{
			return ESanteProperty.PROP_PRACTICE_EHEALTH_ID.equals(userInfo.getEsanteUserId()) ? "" : userInfo.getEsanteUserId();
		}
		
		
		public void setESanteUserId (String eSanteUserId)
		{
			if (eSanteUserId == null)
				eSanteUserId = "";
			
			if (eSanteUserId.equals(userInfo.getValue()))
				return;

			
			if (esanteUserIds.contains(eSanteUserId))
			{
				return;
			}
			else
			{
				esanteUserIds.remove(userInfo.getEsanteUserId());
				esanteUserIds.add(eSanteUserId);
			}
			
			if (eHealthId != null)
			{
				eHealthId.setEsanteUserId(eSanteUserId);
				changedProperties.add(eHealthId);
			}
			this.userInfo.setEsanteUserId(eSanteUserId);
			changedProperties.add(userInfo);
		}
		
		
		public String getUserInfo ()
		{
			return userInfo.getValue();
		}
		
		
		public void setUserInfo (String userInfo)
		{
			if (userInfo == null)
				userInfo = "";
			
			if (userInfo.equals(this.userInfo.getValue()))
				return;
			
			this.userInfo.setValue(userInfo);
			changedProperties.add(this.userInfo);
		}
		
		
		/**
		 * Removes this object from the model and removes 
		 */
		public void remove ()
		{
			if (userInfo.isPersistent())
			{
				deletedProperties.add(userInfo);
			}
			else
			{
				int index = 0;
				for (ESanteProperty p : newProperties)
				{
					if (p.getEsanteUserId().equals(userInfo.getEsanteUserId()))
						break;
					index++;
				}
				
				newProperties.remove(index);
			}
			
			if (eHealthId != null)
			{
				if (eHealthId.isPersistent())
				{
					deletedProperties.add(eHealthId);
				}
				else
				{
					int index = 0;
					for (ESanteProperty p : newProperties)
					{
						if (p.getEsanteUserId().equals(eHealthId.getEsanteUserId()))
							break;
						index++;
					}
					
					newProperties.remove(index);
				}
			}
			
			esanteUserIds.remove(userInfo.getEsanteUserId());
			data.remove(this);
		}
	}
}
