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

import java.util.Collection;

import javax.ejb.EJBNoSuchObjectException;

import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl.ButtonOption;
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.Result;
import lu.tudor.santec.gecamed.labo.ejb.session.beans.ImportBean;
import lu.tudor.santec.gecamed.labo.ejb.session.beans.LaboratoryBean;
import lu.tudor.santec.gecamed.labo.ejb.session.interfaces.ImportInterface;
import lu.tudor.santec.gecamed.labo.ejb.session.interfaces.LaboratoryInterface;
import lu.tudor.santec.gecamed.labo.gui.LaboModule;
import lu.tudor.santec.gecamed.labo.gui.fileimport.FileImportHandler;
import lu.tudor.santec.gecamed.labo.utils.CertificateSynchronizer;
import lu.tudor.santec.gecamed.labo.utils.DecryptException;
import lu.tudor.santec.gecamed.labo.utils.LaboAdminSettings;
import lu.tudor.santec.gecamed.labo.utils.LaboException;
import lu.tudor.santec.gecamed.labo.utils.PasswordEncrypter;
import lu.tudor.santec.gecamed.labo.utils.ResultDownloader;
import lu.tudor.santec.i18n.Translatrix;

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

public class DownloadHandler
	{
	private ResultDownloader			m_ClientDownload;
	private ImportInterface				m_ServerDownload;
	private ImportInterface				m_ResultImporter;
	private PasswordEncrypter			m_PasswordEncrypter;
	
	private ButtonOption 				m_ReplaceAllExistingResults = new ButtonOption(-1, false);
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(DownloadHandler.class.getName());
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Constants	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public DownloadHandler ()
	{
	m_PasswordEncrypter = new PasswordEncrypter ();	
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Primitives	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

private int	getDownloadRoute ()
	{
	Integer	l_DownloadRoute;
	
	l_DownloadRoute = (Integer) LaboModule.getSetting (LaboAdminSettings.c_DownloadRouteSetting);
	return l_DownloadRoute.intValue();	
	}
	
//---------------------------------------------------------------------------
/**
 * The private getLaboratoryInterface returns an instance of the LaboratoryBean
 * session bean. On the first call, the LaboratoryBean 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 LaboratoryBean session bean.
 */
//---------------------------------------------------------------------------

private ImportInterface getImportInterface ()
	{
	ImportInterface l_ImportInterface = null;

	try {
		l_ImportInterface = (ImportInterface) ManagerFactory.getStatefulRemote(ImportBean.class);
		} 
	catch (Exception p_Exception) 
		{
		logger.log(Level.ERROR, "Failed to lookup Import Interface!", p_Exception);
		}

	return l_ImportInterface;
	}

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

private void releaseImportInterface (ImportInterface p_Interface)
	{
	if (p_Interface == null) return;
	
	try {
		p_Interface.remove();
		}
	catch (EJBNoSuchObjectException p_Exception)	
		{
		logger.log(Level.WARN, "Failed to release Import Interface!", p_Exception);
		}
	}

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

public void setMasterPassword (String p_Password)
	{
	m_PasswordEncrypter.setEncryptionPassword (p_Password);	
	}

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

public boolean synchronizeCertifificates (Connection p_Connection) throws Exception
	{
	CertificateSynchronizer		l_Synchronizer;
	Connection					l_Connection;
	LaboratoryInterface			l_LaboManager;
	boolean						l_Success = false;
	
	switch (this.getDownloadRoute())
		{
		case LaboAdminSettings.c_DownloadViaClient:
			
			l_Connection = (Connection) p_Connection.clone();
			l_Connection.setPassword (m_PasswordEncrypter.decryptPassword(p_Connection.getPassword()));
	
			try	{
				l_LaboManager	= (LaboratoryInterface) ManagerFactory.getRemote(LaboratoryBean.class);
				l_Synchronizer	= new CertificateSynchronizer ();
				l_Success = l_Synchronizer.synchronizeCertificates(l_Connection, l_LaboManager);
				}
			catch (Exception p_Exception)
				{
				throw p_Exception;
//				m_Logger.log(Level.ERROR, "Failed to synchronize certificates with server " + p_Connection.getServer() + "!",p_Exception);	
				}
			
			break;
		
		case LaboAdminSettings.c_DownloadViaServer:
			
			if (m_ServerDownload == null) m_ServerDownload = this.getImportInterface();
			if (m_ServerDownload != null)
				{
				m_ServerDownload.setPasswordEncrypter (m_PasswordEncrypter);
				
				try	{
					m_ServerDownload.synchronizeCertificates(p_Connection);
					}
				catch (Exception p_Exception)
					{
					this.releaseImportInterface (m_ServerDownload);	
					m_ServerDownload = null;
//					m_Logger.log(Level.ERROR, "Failed to synchronize certificates with server " + p_Connection.getServer() + "!",p_Exception);
					throw p_Exception;
					}
				}
			break;
		}	
	
	return l_Success;
	}


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

public boolean openConnection (Connection p_Connection)
	{
	Connection	l_Connection;
	boolean		l_Success = false;
	
	switch (this.getDownloadRoute())
		{
		case LaboAdminSettings.c_DownloadViaClient:
				
			l_Connection = (Connection) p_Connection.clone();
			try
			{
				l_Connection.setPassword (m_PasswordEncrypter.decryptPassword(p_Connection.getPassword()));
			}
			catch (LaboException e)
			{
				logger.log(Level.ERROR, e.getMessage(), e);
				return false;
			}
			
			m_ResultImporter = this.getImportInterface();
			if (m_ResultImporter != null)
				{
				m_ResultImporter.setPasswordEncrypter (m_PasswordEncrypter);
				m_ClientDownload = new ResultDownloader ();
				m_ClientDownload.openConnection(l_Connection, (LaboratoryInterface) ManagerFactory.getRemote(LaboratoryBean.class));
				l_Success = m_ClientDownload.isConnected();
				}
			break;
		
		case LaboAdminSettings.c_DownloadViaServer:	
		
			try {
				m_ServerDownload.setPasswordEncrypter (m_PasswordEncrypter);
				}
			catch (Exception e) 
				{
				m_ServerDownload = this.getImportInterface();
				}
//			if (m_ServerDownload == null) m_ServerDownload = this.getImportInterface();
			if (m_ServerDownload != null)
				{
				m_ServerDownload.setPasswordEncrypter (m_PasswordEncrypter);
				
				try	{
					l_Success = m_ServerDownload.openConnection (p_Connection);
					}
				catch (Exception p_Exception)
					{
					this.releaseImportInterface (m_ServerDownload);	
					m_ServerDownload = null;
					logger.log(Level.ERROR, "Failed to open connection to server " + p_Connection.getServer() + "!",p_Exception);
					}
				}
		break;
	}
return l_Success;
}

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

public Collection <String>	getAvailableResults	()
	{
	Collection <String>	l_AvailableResults = null;
		
	switch (this.getDownloadRoute())
		{
		case LaboAdminSettings.c_DownloadViaClient:
			
			if ((m_ClientDownload != null) && m_ClientDownload.isConnected())
				l_AvailableResults = m_ClientDownload.getListOfAvailableResults();	
		break;
		
		case LaboAdminSettings.c_DownloadViaServer:	

			if (m_ServerDownload != null)
				{
				try	{
					l_AvailableResults = m_ServerDownload.getAvailableResults();
					}
				catch (Exception p_Exception)
					{
					this.releaseImportInterface (m_ServerDownload);	
					m_ServerDownload = null;
					logger.log(Level.ERROR, "Failed to retrieve list of available results!",p_Exception);						
					}
				}
		break;
		}
	
	return l_AvailableResults;
	}

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

public int importResult	(String p_ResultFileName)
	{
	byte[]  		l_EncryptedData;
	int				l_ImportState 	= ImportInterface.SKIP_THIS_RESULT;
	Result 			l_Result 		= null;
	Exception 		l_Exception		= null;
	ImportInterface	l_ImportBean	= null;
	
	if (this.getDownloadRoute() == LaboAdminSettings.c_DownloadViaClient)
		l_ImportBean = m_ResultImporter;
	else 
		l_ImportBean = m_ServerDownload;
	
	try {
		if (this.getDownloadRoute() == LaboAdminSettings.c_DownloadViaClient)
			{
			if ((l_ImportBean != null) && (m_ClientDownload != null) && m_ClientDownload.isConnected())
				{
				l_EncryptedData = m_ClientDownload.downloadResult (p_ResultFileName);	
				if ((l_EncryptedData != null) && (l_EncryptedData.length > 0))
					l_Result = l_ImportBean.importResult(l_EncryptedData, p_ResultFileName);
				}
			}
		else // if (this.getDownloadRoute() == LaboAdminSettings.c_DownloadViaServer)
			if (l_ImportBean != null)
				l_Result = l_ImportBean.importResult(p_ResultFileName);
		}
	catch (Exception p_Exception)
		{
		// log the error
		logger.log(Level.ERROR, "Failed to import result " + p_ResultFileName + "!",p_Exception);
		
		if (p_Exception instanceof DecryptException)
		{
			((DecryptException) p_Exception).setFailedResultFileName(p_ResultFileName);
			((DecryptException) p_Exception).logFailedResult();
		}
		
		l_Exception = p_Exception;
		}
	finally 
		{
		l_ImportState = FileImportHandler.handleImportResult(l_ImportBean, l_Result, 
				l_Exception, p_ResultFileName, m_ReplaceAllExistingResults);
		
		if (l_ImportState == ImportInterface.IMPORT_SUCCESSFUL)
			try {
				// the import was successful => move the file into the "old" folder
				if (this.getDownloadRoute() == LaboAdminSettings.c_DownloadViaClient)
					// move via client
					m_ClientDownload.renameFile(p_ResultFileName, "old/" + p_ResultFileName);
				else
					// move via server
					l_ImportBean.moveResultFile(p_ResultFileName);
				} 
			catch (DecryptException e)
				{
				logger.log(Level.ERROR, "Couldn't move successfully imported result to \"old\" folder!", e);
				
				e.setFailedResultFileName(p_ResultFileName);
				e.logFailedResult();
				
				int buttonOption = GECAMedBaseDialogImpl.showMessageDialog(MainFrame.getInstance(), 
						Translatrix.getTranslationString("FileImportHandler.ErrorWhileImport_Title"),
						e.getMessage(), GECAMedBaseDialog.OK_CANCEL_BUTTON_MODE);
				
				if (buttonOption == GECAMedBaseDialog.OK_OPTION)
					return l_ImportState;
				else
					return ImportInterface.CANCEL_IMPORTING;
				}
		}
	
	return l_ImportState;		
	}

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

public void closeConnection ()
	{
	switch (this.getDownloadRoute())
		{
		case LaboAdminSettings.c_DownloadViaClient:
				
			if (m_ClientDownload != null)
				{
				m_ClientDownload.closeConnection();
				m_ClientDownload = null;
				}
			break;
		
		case LaboAdminSettings.c_DownloadViaServer:	
		
			if (m_ServerDownload != null)
				{
				m_ServerDownload.closeConnection();
				this.releaseImportInterface (m_ServerDownload);	
				m_ServerDownload = null;
				}
			break;
		}
	}

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

public void resetApplyAllForExistingResults ()
	{
	m_ReplaceAllExistingResults.applyToAll = false;
	}

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

}
