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

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
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.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.Logger;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.labo.ejb.entity.beans.Laboratory;
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.beans.ResultBean;
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.ejb.session.interfaces.ResultInterface;
import lu.tudor.santec.gecamed.labo.gui.LaboModule;
import lu.tudor.santec.gecamed.labo.gui.download.DownloadDialog;
import lu.tudor.santec.gecamed.labo.utils.DecryptException;
import lu.tudor.santec.gecamed.labo.utils.PasswordEncrypter;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.PatientAdminBean;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.PatientAdminInterface;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;

public class FileImportHandler
	{
	private PasswordEncrypter			m_PasswordEncrypter;
	
	private static Logger				m_Logger = new Logger (FileImportHandler.class);

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

	private static final int	c_BufferSize  = 4096;
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public FileImportHandler ()
	{
	m_PasswordEncrypter = new PasswordEncrypter ();	
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Primitives	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
/**
 * 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) 
		{
		m_Logger.log (Level.FATAL, "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)	
//		{
//		m_Logger.log (Level.WARN, "Failed to release Import Interface!", p_Exception);
//		}
//	}

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

private ByteArrayOutputStream readResultFile (File p_ResultFile)
	{
	FileInputStream			l_ResultStream  = null;
	ByteArrayOutputStream	l_EncryptedData = null;
	byte[]					l_Buffer;
	int						l_BytesRead;
					
	l_Buffer = new byte [c_BufferSize];

	if ((p_ResultFile != null) && (p_ResultFile.exists()))
		{
		try	{
			l_ResultStream = new FileInputStream (p_ResultFile.getPath());
			l_EncryptedData = new ByteArrayOutputStream ();
			
			do	{
				l_BytesRead = l_ResultStream.read(l_Buffer, 0, c_BufferSize);
				if (l_BytesRead > 0) l_EncryptedData.write(l_Buffer, 0, l_BytesRead);
				}
			while (l_BytesRead > 0);
			
			}
		catch (Exception p_Exception)
			{
			m_Logger.log(Level.FATAL, "Failed to read Result File " + p_ResultFile.getPath(),p_Exception);
			}		
		finally
			{
			try	{
				if (l_ResultStream != null)  l_ResultStream.close();
				if (l_EncryptedData != null) l_EncryptedData.close();			
				}
			catch (IOException p_Exception)
				{
				m_Logger.log(Level.FATAL, "Failed to close Streams!",p_Exception);
				}	
			}	
		}
	
	return l_EncryptedData;
	}

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

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

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

public Boolean importResult	(File p_ResultFile)
	{
	ImportInterface			l_ResultImporter;
	ByteArrayOutputStream 	l_EncryptedData;
	Result					l_Result 	= null;
	Exception 				l_Exception = null;
	boolean					l_Success 	= false;
	
	l_ResultImporter = this.getImportInterface();
	if (l_ResultImporter != null)
		{
		l_ResultImporter.setPasswordEncrypter (m_PasswordEncrypter);
			
		l_EncryptedData = this.readResultFile(p_ResultFile);	
		if ((l_EncryptedData != null) && (l_EncryptedData.size() > 0))
			{
			try	{
				l_Result = l_ResultImporter.importResult(l_EncryptedData.toByteArray(), p_ResultFile.getName());
				}
			catch (Exception p_Exception)
				{
//				this.releaseImportInterface (l_ResultImporter);	
//				l_ResultImporter = null;
				m_Logger.log(Level.FATAL, "Failed to import result " + p_ResultFile.getName() + "!",p_Exception);
				
				if (p_Exception instanceof DecryptException)
				{
					((DecryptException) p_Exception).setFailedResultFileName(p_ResultFile.getName());
					((DecryptException) p_Exception).logFailedResult();
				}
				
				l_Exception = p_Exception;
				}
			finally 
				{
				l_Success = (handleImportResult(l_ResultImporter, l_Result, l_Exception, p_ResultFile.getName(), null) == ImportInterface.IMPORT_SUCCESSFUL);
				}
			}
		}	
	
	return l_Success;
	}

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

public static int handleImportResult (ImportInterface p_ResultImporter, Result p_Result, 
		Exception p_Exception, String p_FileName, ButtonOption p_ReplaceAllExistingResults)
	{
	Patient 				l_Patient;
	PatientAdminInterface 	l_PatientManager;
	Physician 				l_Physician;
	LaboratoryInterface		l_LabManager;
	Laboratory				l_Lab;
	
	String 					l_Title;
	String					l_Message;
	
//	int						l_ImportState;
	int 					buttonOption;
	boolean					savePatient = false;

	if (DownloadDialog.isDownloadAborted())
		return ImportInterface.CANCEL_IMPORTING;
	
	if (p_Exception != null)
		{
		l_Title = Translatrix.getTranslationString("FileImportHandler.ErrorWhileImport_Title")
				.replace("$FILENAME", p_FileName == null ? "" : p_FileName);
		l_Message = p_Exception.getMessage();
		
		buttonOption = GECAMedBaseDialogImpl.showMessageDialog(MainFrame.getInstance(), l_Title, l_Message, 
				GECAMedBaseDialog.OK_CANCEL_BUTTON_MODE, IconFetcher.getBigIcon(LaboModule.class, "error.png"));
		
		if (buttonOption == GECAMedBaseDialog.CANCEL_OPTION)
			return ImportInterface.CANCEL_IMPORTING;
		
		if (p_Exception instanceof DecryptException
				&&(((DecryptException)p_Exception).getState().equals(ImportInterface.INVALID_SIGNATURE)
				|| ((DecryptException)p_Exception).getState().equals(ImportInterface.INVALID_XML)
				|| ((DecryptException)p_Exception).getState().equals(ImportInterface.RESULT_NOT_ENCRYPTED)))
			return ImportInterface.SKIP_THIS_RESULT;
		else
			return ImportInterface.UNKNOWN_REASON;
		}
	
	if (p_Result == null)
		return ImportInterface.SKIP_THIS_RESULT;

	if (p_Result.getId() != null)
		{
		if (p_ReplaceAllExistingResults == null
				|| !p_ReplaceAllExistingResults.applyToAll)
			{
			ButtonOption bo = GECAMedBaseDialogImpl.showMessageDialog(MainFrame.getInstance(), 
					Translatrix.getTranslationString("FileImportHandler.ResultAlreadyExists_Title"), 
					Translatrix.getTranslationString("FileImportHandler.ResultAlreadyExists_Message"),
					GECAMedBaseDialog.YES_NO_CANCEL_BUTTON_MODE, 
					GECAMedModule.getBigIcon(GECAMedIconNames.WARNING),
					true);
			
			if (p_ReplaceAllExistingResults == null)
				p_ReplaceAllExistingResults = bo;
			else
				{
				p_ReplaceAllExistingResults.applyToAll = bo.applyToAll;
				p_ReplaceAllExistingResults.buttonOption = bo.buttonOption;
				}
			}
		if (p_ReplaceAllExistingResults.buttonOption == GECAMedBaseDialog.CANCEL_OPTION)
			return ImportInterface.CANCEL_IMPORTING;
		else if (p_ReplaceAllExistingResults.buttonOption != GECAMedBaseDialog.YES_OPTION)
			return ImportInterface.SKIP_THIS_RESULT;
		}
	
	if (p_Result.isPersistent()
			&&(!p_Result.getPatient().isPersistent()
			|| !p_Result.getPrescriber().isPersistent()
			|| !p_Result.getLaboratory().isPersistent()))
		{
		try {
			boolean 		fetchPatient 		= !p_Result.getPatient().isPersistent();
			boolean 		fetchPrescriber 	= !p_Result.getPrescriber().isPersistent();
			boolean 		fetchLabo 			= !p_Result.getLaboratory().isPersistent();
			
			ResultInterface resultManager 		= (ResultInterface)ManagerFactory.getRemote(ResultBean.class);
			Result 			l_PersistentResult 	= resultManager.getResultByIdFetchAll(p_Result.getId(), 
													fetchPatient, fetchPrescriber, fetchLabo);
			
			
			if (fetchPatient) 		p_Result.setPatient(l_PersistentResult.getPatient());
			if (fetchPrescriber) 	p_Result.setPrescriber(l_PersistentResult.getPrescriber());
			if (fetchLabo) 			p_Result.setLaboratory(l_PersistentResult.getLaboratory());
			} 
		catch (Exception l_Exception) 
			{
			m_Logger.log(Level.ERROR, l_Exception.getMessage(), l_Exception);
			}
		}
	
	// the result is a new result
	l_Patient 	= p_Result.getPatient();
	l_Physician = p_Result.getPrescriber();
	l_Lab		= p_Result.getLaboratory();
	
	
	if (!l_Patient.isPersistent())
		{
//		String l_FirstName 	= l_Patient.getFirstName();
//		String l_SurName 	= l_Patient.getSurName();
//		String l_SSN 		= l_Patient.getSocialSecurityNumber();
//		
//		
//		buttonOption = GECAMedBaseDialogImpl.showMessageDialog(MainFrame.getInstance(), 
//				Translatrix.getTranslationString("FileImportHandler.PatientDoesNotExist_Title"), 
//				Translatrix.getTranslationString("FileImportHandler.PatientDoesNotExist_Message")
//						.replace("$FIRSTNAME", 	l_FirstName == null ? "" : l_FirstName)
//						.replace("$SURNAME", 	l_SurName 	== null ? "" : l_SurName)
//						.replace("$SSN", 		l_SSN 		== null ? "" : l_SSN), 
//				GECAMedBaseDialog.YES_NO_CANCEL_BUTTON_MODE);
		
		ChoosePatientDialog dialog = ChoosePatientDialog.getInstance();
		buttonOption	= dialog.showDialog(l_Patient);
		
		if (buttonOption == ChoosePatientDialog.OK_OPTION
				|| buttonOption == ChoosePatientDialog.CLOSED_OPTION)
			return ImportInterface.SKIP_THIS_RESULT;
		else if (buttonOption == ChoosePatientDialog.CANCEL_OPTION)
			return ImportInterface.CANCEL_IMPORTING;
		else if (buttonOption == ChoosePatientDialog.CREATE_NEW_PATIENT)
			// note to save the patient
			savePatient = true;
		else if (buttonOption == ChoosePatientDialog.REASSIGN_PATIENT)
			{
			p_Result.setPatient(dialog.getPatient());
			}
		}
	
	if (!l_Physician.isPersistent())
		{
		ChoosePhysicianDialog dialog = new ChoosePhysicianDialog(l_Physician);
		
		dialog.pack();
		MainFrame.showDialogCentered(dialog);
		
		buttonOption = dialog.getButtonOption();
		
		if (buttonOption == GECAMedBaseDialog.NO_OPTION)
			return ImportInterface.SKIP_THIS_RESULT;
		else if (buttonOption == GECAMedBaseDialog.CANCEL_OPTION
				|| buttonOption == GECAMedBaseDialog.CLOSED_OPTION)
			return ImportInterface.CANCEL_IMPORTING;
		else if (buttonOption == GECAMedBaseDialog.YES_OPTION)
			{
			l_Physician = dialog.getPhysician();
			p_Result.setPrescriber(l_Physician);
			}
		else 
			m_Logger.log(Level.WARN, "Unhandled option of ChoosePhysicianDialog");
		}
	
	if (savePatient)
		{
		try
			{
			l_PatientManager= (PatientAdminInterface)ManagerFactory.getRemote(PatientAdminBean.class);
			l_Patient 		= l_PatientManager.savePatient(l_Patient);
			p_Result.setPatient(l_Patient);
			} 
		catch (Exception e)
			{
			m_Logger.log(Level.FATAL, "Fail to save patient!", e);
			}
		}
	
	if (!l_Lab.isPersistent())
		{
		try {
			l_LabManager= (LaboratoryInterface)ManagerFactory.getRemote(LaboratoryBean.class);;
			l_Lab 		= l_LabManager.saveLaboratory(l_Lab);
			p_Result.setLaboratory(l_Lab);
			} 
		catch (Exception e)
			{
			m_Logger.log(Level.FATAL, "Fail to save laboratory!", e);
			}
		}
	
	try {
		p_Result = p_ResultImporter.saveResult(p_Result);
		return ImportInterface.IMPORT_SUCCESSFUL;
		}
	catch (Exception e)
		{
		if (DownloadDialog.isDownloadAborted())
			return ImportInterface.CANCEL_IMPORTING;
		else 
			{
			m_Logger.log(Level.FATAL, "Fail to save result!", e);
			buttonOption = GECAMedBaseDialogImpl.showMessageDialog(MainFrame.getInstance(), 
					Translatrix.getTranslationString("FileImportHandler.ErrorWhileImport_Title")
							.replace("$FILENAME", p_FileName == null ? "" : p_FileName),
					e.getMessage(), GECAMedBaseDialog.OK_CANCEL_BUTTON_MODE);
			
			if (buttonOption == GECAMedBaseDialog.CANCEL_OPTION)
				return ImportInterface.CANCEL_IMPORTING;
			}
		}
	
	return ImportInterface.COULD_NOT_SAVE_RESULT;
	}

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

}

