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

import java.awt.Color;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenu;

import lu.tudor.santec.gecamed.core.gui.GECAMedAction;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.RegexFileFilter;
import lu.tudor.santec.gecamed.core.gui.widgets.PasswordChangeDialog;
import lu.tudor.santec.gecamed.core.utils.Logger;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.labo.ejb.entity.beans.Connection;
import lu.tudor.santec.gecamed.labo.ejb.entity.beans.MasterPassword;
import lu.tudor.santec.gecamed.labo.ejb.session.beans.KeyChainBean;
import lu.tudor.santec.gecamed.labo.ejb.session.interfaces.KeyChainInterface;
import lu.tudor.santec.gecamed.labo.gui.actions.DownloadAction;
import lu.tudor.santec.gecamed.labo.gui.actions.ImportAction;
import lu.tudor.santec.gecamed.labo.gui.admin.LaboAdminPanel;
import lu.tudor.santec.gecamed.labo.gui.download.DownloadDialog;
import lu.tudor.santec.gecamed.labo.gui.fileimport.FileImportHandler;
import lu.tudor.santec.gecamed.labo.gui.history.HistoryPanel;
import lu.tudor.santec.gecamed.labo.gui.settings.LaboAdminSettingsPlugin;
import lu.tudor.santec.gecamed.labo.utils.LaboPermissions;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Office;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.UserSettingsPlugin;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;

public class LaboModule extends GECAMedModule
	{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	private LaboAdminPanel				m_AdminPanel;
	private HistoryPanel				m_HistoryPanel;
	
	private Collection <GECAMedAction>  m_LaboActions;

	
	private static LaboModule			  	m_Instance		= null;
	
	private static Logger					m_Logger	     = new Logger (LaboModule.class);
	
	private static LaboAdminSettingsPlugin 	m_AdminSettings	 = new LaboAdminSettingsPlugin();

	private static String				    m_MasterPassword = null;
	private static KeyChainInterface		m_KeyChainInterface;

//---------------------------------------------------------------------------
//***************************************************************************
//* Constants	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

    public static final String 	MODULE_NAME 			= "Labo";

 	public static final String	c_i32_Labo				= "labo.png";
	public static final String	c_i32_LaboLocked		= "labo_locked.png";
	public static final String	c_i32_Server			= "server.png";
	
	public static final String	c_i32_AddConnection		= "connection_add_action.png";
	public static final String	c_i32_RemoveConnection	= "connection_remove_action.png";
	public static final String	c_i32_TestConnection	= "connection_test_action.png";
	public static final String	c_i32_AbortConnection	= "connection_abort_action.png";	
	public static final String  c_i32_ConnectionError	= "connection_error_status.png";
	public static final String  c_i32_ConnectionSuccess	= "connection_success_status.png";
	
	public static final String	c_i16_Certificate		= "certificate_tiny.png";

	public static final String  c_i32_Key				= "key.png";
	public static final String	c_i32_AddKey			= "key_add_action.png";
	public static final String	c_i32_RemoveKey			= "key_remove_action.png";
	public static final String	c_i32_WithoutPassword	= "key_without_password.png";
	public static final String	c_i16_WithPassword		= "key_with_password.png";

	public static final String  c_i32_TestKey			= "key_test_action.png";
	public static final String  c_i32_KeySuccess		= "key_success_status.png";
	public static final String  c_i32_KeyFailure		= "key_failure_status.png";

	public static final String  c_i32_UnlockLabo		= "labo_unlock_action.png";
	
	public static final String  c_i32_DownloadResult	= "result_download_action.png";
	public static final String	c_i16_DownloadBusy		= "busy_wheel_tiny.gif";
	public static final String	c_i16_DownloadFailed	= "download_failure_status.png";
	public static final String	c_i16_DownloadSuccess	= "download_success_status.png";
	
	public static final String  c_i32_ImportResult		= "result_import_xml_action.png";

	public static final String	c_i16_HistoryNode		= "history_node.png";

	//=======================================================================
	//= I18N Strings
	//=======================================================================

	public static final String c_UnlockTitle			= "LaboModule.UnlockTitle";
	public static final String c_UnlockMessage			= "LaboModule.UnlockMessage";
	public static final String c_WrongPasswordMessage	= "LaboModule.WrongPasswordMessage";
	
	public static final String c_DownloadAction			= "LaboModule.DownloadAction";
	public static final String c_ImportAction			= "LaboModule.ImportAction";
	
	public static final Color c_ModuleColor = new Color (177,137,190);

//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public LaboModule ()
	{
 	super(MODULE_NAME, IconFetcher.getIcon (LaboModule.class, c_i32_LaboLocked), c_ModuleColor);
	
 	JMenu		l_LaboMenu;
 	
	m_Instance = this;
 	
 	Translatrix.addBundle ("lu.tudor.santec.gecamed.labo.gui.resources.WidgetResources");	
	
   	this.setOpaque(false);
 	this.setCanDisplayPatient(false);
   	
	m_AdminPanel = new LaboAdminPanel ();
	MainFrame.addAdminTab(m_AdminPanel);
	
	m_AdminSettings.relocalize();
	
	PatientManagerModule.getInstance().addAdminSettingsPlugin (m_AdminSettings);
	
	l_LaboMenu = new JMenu (Translatrix.getTranslationString("Labo"));
    this.setModuleMenu(l_LaboMenu);

    this.createLaboActions();
	
	
	m_HistoryPanel = new HistoryPanel ();
//	this.add (m_HistoryPanel);
	this.setContentPanel(m_HistoryPanel);
	}
	
//---------------------------------------------------------------------------

private void createLaboActions ()
	{
	GECAMedAction		l_Action;
		
    m_LaboActions = new ArrayList <GECAMedAction> ();
		
	if (userHasPermission (LaboPermissions.c_Module,LaboPermissions.c_DownloadResults))
		{ 	
	   	l_Action = new DownloadAction (this,
		    						   c_DownloadAction,
		    						   IconFetcher.getIcon (LaboModule.class, c_i32_DownloadResult),
		    						   KeyEvent.VK_D,
		    						   true, true, false);
	   	l_Action.add();
	   	m_LaboActions.add(l_Action);
		
		l_Action = new ImportAction (this,
									 c_ImportAction,
		    						 IconFetcher.getIcon (LaboModule.class, c_i32_ImportResult),
		    						 KeyEvent.VK_I,
		    						 true, true, false);
									 
	   	l_Action.add();
	   	l_Action.setEnabled(false);
	   	m_LaboActions.add(l_Action);
		}
	}

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

private void enableLaboActions (boolean p_EnableThem)
	{
	Iterator <GECAMedAction> l_ActionIterator;
	
	l_ActionIterator = m_LaboActions.iterator();
	while (l_ActionIterator.hasNext())
		{
		l_ActionIterator.next().setEnabled(p_EnableThem);	
		}
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Primitives	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * The static getInstance method returns a reference to the current
 * instance of the LaboModule
 * @return current instance (this) of LaboModule 
 */
//---------------------------------------------------------------------------

public static LaboModule getInstance()
	{
	return m_Instance;
	}

//---------------------------------------------------------------------------
/**
 * Returns the value of the admin labo setting specified by p_Setting.
 * Admin settings are those settings that are common to all users.
 * @param p_Setting specifies the name of the admin setting to get the
 * value of.
 * @return the value (Object) of the admin setting specified by p_Setting.
 */
//---------------------------------------------------------------------------

public static Object getSetting (String p_Setting)
	{
	return m_AdminSettings.getValue(p_Setting);
	}

//---------------------------------------------------------------------------
/**
 * The private getKeyChainInterface returns an instance of the KeyChainBean
 * session bean. On the first call, the KeyChainBean will actualy be looked up
 * via JNDI. Once it has been found, the reference to the bean will be stored
 * in a private data member. Doing so avoids JNDI lookups on later calls.
 * @return an instance of the KeyChainBean session bean.
 */
//---------------------------------------------------------------------------

private static KeyChainInterface getKeyChainInterface ()
	{
	if (m_KeyChainInterface != null) return m_KeyChainInterface;

	try {
		m_KeyChainInterface = (KeyChainInterface) ManagerFactory.getRemote(KeyChainBean.class);
		} 
	catch (Exception p_Exception) 
		{
		m_Logger.log(Level.FATAL, "Failed to lookup KeyChainInterface!",p_Exception);
		}

	return m_KeyChainInterface;
	}

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

private static MasterPassword getMasterPasswordForOffice (Office p_Office)
	{
	KeyChainInterface	l_Interface;
	MasterPassword		l_Password	= null;
	
	if ((p_Office == null) || !p_Office.isPersistent()) return null;
	
	l_Interface = getKeyChainInterface();
	if (l_Interface == null) return null;
	
	try	{
		l_Password = l_Interface.getMasterPasswordByOfficeId(p_Office.getId());
		}
	catch (Exception p_Exception) 
		{
		m_Logger.log(Level.ERROR, "Failed to retrieve master password for office " + p_Office.getName() +"!",p_Exception);
		}
	
	return l_Password;
	}

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

private static MasterPassword saveMasterPassword (MasterPassword p_Password)
	{
	KeyChainInterface	l_Interface;
	
	if (p_Password == null) return null;
	
	l_Interface = getKeyChainInterface();
	if (l_Interface == null) return null;
	
	try	{
		p_Password = l_Interface.saveMasterPassword(p_Password);
		}
	catch (Exception p_Exception) 
		{
		m_Logger.log(Level.ERROR, "Failed to save master password!",p_Exception);
		}
	
	return p_Password;
	}

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

private Collection <Connection> getConnectionsForPhysician ()
	{
	KeyChainInterface		l_Interface;
	Physician				l_CurrentPhysician;
	Collection <Connection>	l_Connections	= null;
	
	l_Interface = getKeyChainInterface();
	if (l_Interface == null) return null;
	
	l_CurrentPhysician = MainFrame.getCurrentPhysician();
	if (l_CurrentPhysician == null) return null;
	
	try	{
		l_Connections = l_Interface.getConnectionsByPhysicianId (l_CurrentPhysician.getId());
		}
	catch (Exception p_Exception) 
		{
		m_Logger.log(Level.ERROR, "Failed to retrieve connections for " + l_CurrentPhysician.toString() + "!",p_Exception);
		}
	
	return l_Connections;
	}

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

private static void initializeMasterPassword ()
	{
	Office					l_Office;
	MasterPassword			l_Password;
	PasswordChangeDialog	l_NewPasswordDialog;
	PasswordDialog			l_PasswordDialog;
	String[]				l_Filler;
	boolean					l_DialogAlreadyShown = false;
	
	m_MasterPassword = null;
	
	l_Office = MainFrame.getCurrentOffice();
	if (l_Office != null)
		{
		l_Password = getMasterPasswordForOffice(l_Office);
		if (l_Password == null)
			{
			l_Password = new MasterPassword ();
			l_Password.setOfficeId(l_Office.getId());
				
			l_NewPasswordDialog = new PasswordChangeDialog (MainFrame.getInstance());
			l_Password.setPasswordHash(l_NewPasswordDialog.getPassword());
			if (l_Password.getPasswordHash() != null)
				{
				l_Password = saveMasterPassword(l_Password);	
				m_MasterPassword = l_NewPasswordDialog.getUnencodedPassword();
				}
			}
		else
			{	
			l_Filler = new String [1];
			l_Filler[0] = l_Office.getName();
			l_PasswordDialog = new 	PasswordDialog ();
			l_PasswordDialog.setIcon(IconFetcher.getIcon (LaboModule.class,c_i32_UnlockLabo));
			l_PasswordDialog.setTitle   (c_UnlockTitle);
			l_PasswordDialog.setMessage (c_UnlockMessage,l_Filler);
			l_PasswordDialog.setPasswordHash(l_Password.getPasswordHash());
			l_PasswordDialog.pack ();
			
			do	{
				if (l_DialogAlreadyShown)
					l_PasswordDialog.setVisible(true);
				else
					{
					MainFrame.showDialogCentered(l_PasswordDialog);
					l_DialogAlreadyShown = true;
					}
				
				if (!l_PasswordDialog.wasCanceled())
					{
					if (l_PasswordDialog.passwordMatched()) m_MasterPassword = l_PasswordDialog.getPassword();
					else 
						{
						MainFrame.getInstance().showMessage(Translatrix.getTranslationString(c_WrongPasswordMessage));
//						MainFrame.getInstance().showMessage(l_PasswordDialog, Translatrix.getTranslationString(c_WrongPasswordMessage));

						l_PasswordDialog.markPasswordWrong();
//						try {
//							LaboModule.getInstance().wait ((Integer)MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.OSD_TIME));
//							}
////						catch (InterruptedException p_Exeption)
//						catch (Exception p_Exception)
//							{
//							}
						}	
					}
				}
			while ((m_MasterPassword == null) && !l_PasswordDialog.wasCanceled());
			}
		}
	}

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

public static String getMasterPassword ()
	{
	if (m_MasterPassword == null) initializeMasterPassword ();
	return m_MasterPassword;	
	}

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

public static ImageIcon getButtonIcon (String p_IconName)
	{
	ImageIcon l_Icon; 
	
	l_Icon = IconFetcher.getIcon(LaboModule.class,p_IconName);
	if (l_Icon == null) return l_Icon;
	
	if ((Boolean)MainFrame.getInstance().userSettings.getValue(UserSettingsPlugin.SMALL_ICONS))
		{
		l_Icon = new ImageIcon (l_Icon.getImage().getScaledInstance(16,16,Image.SCALE_SMOOTH));
		}

	return l_Icon;
	}

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

public void preparetoShowup ()
	{
	if (getMasterPassword () != null)
		{
		this.setIcon(IconFetcher.getIcon (LaboModule.class, c_i32_Labo));	
		this.enableLaboActions(true);
		}	
	else this.enableLaboActions(false);
	}

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

public void importResults ()
	{
	JFileChooser  		l_FileSelector;
    RegexFileFilter		l_ResultFileFilter;
	int					l_Choice;
    File				l_File;
	FileImportHandler	l_FileImporter;
	String				l_MasterPassword = LaboModule.getMasterPassword();
	
	if (l_MasterPassword == null)
		return;
    
    
    l_FileSelector = MainFrame.getFileChooser();
	l_FileSelector.setLocale (Translatrix.getLocale());
    l_FileSelector.setOpaque(false);	
		
	l_ResultFileFilter = new RegexFileFilter ();
	l_ResultFileFilter.setFilePattern ("^(\\d{6}-\\d{2}[A-Z]?)(\\d{6}-\\d{2}[A-Z]?)(\\d{10})\\.xml$", false);
	l_ResultFileFilter.setDescription (Translatrix.getTranslationString("LaboModule.ResultFileFilterDescription"));
	
	l_FileSelector.setFileFilter (l_ResultFileFilter);
	
	l_FileSelector.setDialogTitle (Translatrix.getTranslationString ("LaboModule.ImportResultFileTitle"));
	l_Choice = l_FileSelector.showOpenDialog (MainFrame.getInstance());
	
	if (l_Choice == JFileChooser.APPROVE_OPTION)
        {
        l_File = l_FileSelector.getSelectedFile ();
        l_FileImporter = new FileImportHandler ();
        l_FileImporter.setMasterPassword (l_MasterPassword);
        l_FileImporter.importResult(l_File);
        
        m_HistoryPanel.update();
        }
	}

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

public void downloadResults ()
	{	
	DownloadDialog	l_Dialog;
	
	l_Dialog = new DownloadDialog ();
	l_Dialog.setConnections (this.getConnectionsForPhysician());
	l_Dialog.pack();
	
	MainFrame.showDialogCentered(l_Dialog);
	
	m_HistoryPanel.update();
	}

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