package lu.tudor.santec.gecamed.core.gui.widgets.print;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import lu.tudor.santec.gecamed.address.ejb.session.beans.AddressManagerBean;
import lu.tudor.santec.gecamed.address.ejb.session.interfaces.AddressManagerInterface;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Account;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Bailiff;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.InvoiceStub;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.BillingPrinterBean;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.SettlementBean;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.BillingPrinterInterface;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.SettlementInterface;
import lu.tudor.santec.gecamed.billing.gui.BillingModule;
import lu.tudor.santec.gecamed.billing.utils.BillingAdminSettings;
import lu.tudor.santec.gecamed.billing.utils.InvoiceWorkflow;
import lu.tudor.santec.gecamed.core.gui.GECAMedLists;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.core.utils.PrintParameter;
import lu.tudor.santec.gecamed.core.utils.printing.ireport.UtilFormatter;
import lu.tudor.santec.gecamed.core.utils.printing.ireport.UtilSettings;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.office.ejb.session.beans.OfficeManagerBean;
import lu.tudor.santec.gecamed.office.ejb.session.interfaces.OfficeManagerInterface;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Incident;
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.gecamed.patient.utils.CertificateData;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.Prescription;

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

public class PrintParameterFetcher
{
	/* ======================================== */
	// 		CONSTANTS
	/* ======================================== */
	
	private static final String NEWLINE	= System.getProperty("line.separator");
	
	
	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(PrintParameterFetcher.class.getName());
	
	private static OfficeManagerInterface 	officeManager;
	private static PatientAdminInterface 	patientManager;
	private static BillingPrinterInterface 	billingPrinter;
	private static SettlementInterface		settlementManager;
	
	
	
	/* ======================================== */
	// 		DEFAULT METHOD
	/* ======================================== */
	
	public static HashMap<String, Object> createDefaultPrintParameter ()
	{
		Patient 		patient 	= GECAMedModule.getCurrentPatient();
		Physician 		physician 	= GECAMedModule.getCurrentPhysician();
		UtilFormatter 	formatter 	= new UtilFormatter((AddressManagerInterface) ManagerFactory.getRemote(AddressManagerBean.class));
		UtilSettings 	settings 	= formatter.getSettings();
		
		HashMap<String, Object> printParameter = new HashMap<String, Object>();
		
		formatter.initTranslations();
		formatter.setReferenceOffice(MainFrame.getCurrentOffice());
		formatter.setReferenceAddress(MainFrame.getCurrentOffice().getLatestOfficeAddress());
		
		printParameter.put(PrintParameter.PRINT_PARAMETER_NEWLINE, 				NEWLINE);
		printParameter.put(PrintParameter.PRINT_PARAMETER_TODAY, 				new Date());
		printParameter.put(PrintParameter.PRINT_PARAMETER_FORMATTER, 			formatter);
		printParameter.put(PrintParameter.PRINT_PARAMETER_SETTINGS, 			settings);
		printParameter.put(PrintParameter.PRINT_PARAMETER_CURRENT_PATIENT, 		patient);
		printParameter.put(PrintParameter.PRINT_PARAMETER_PATIENT, 				patient);
		printParameter.put(PrintParameter.PRINT_PARAMETER_CURRENT_PHYSICIAN, 	physician);
		printParameter.put(PrintParameter.PRINT_PARAMETER_PHYSICIAN, 			physician);
		printParameter.put(PrintParameter.PRINT_PARAMETER_CURRENT_USER, 		GECAMedModule.getCurrentUser());
		printParameter.put(PrintParameter.PRINT_PARAMETER_CURRENT_OFFICE, 		MainFrame.getCurrentOffice());
		
		return printParameter;
	}
	
	
	
	/* ======================================== */
	// 		FORM-EDITOR METHODS
	/* ======================================== */
	
//	public static HashMap<String, Object> createDefaultPrintParameter (Date dateCreated)
//	{
//		HashMap<String, Object> printParameter = createDefaultPrintParameter();
//		UtilSettings settings = (UtilSettings) printParameter.get(PRINT_PARAMETER_SETTINGS);
//		settings.putSetting(UtilSettings.SETTING_DATE_CREATED, dateCreated);
//		
//		return printParameter;
//	}
	

	public static HashMap<String, Object> createDefaultPrintParameter (Incident incident)
	{
		HashMap<String, Object> printParameter = createDefaultPrintParameter();
		UtilSettings settings = (UtilSettings) printParameter.get(PrintParameter.PRINT_PARAMETER_SETTINGS);
		settings.putSetting(UtilSettings.SETTING_DATE_CREATED, incident.getIncidentDate());
		printParameter.put(PrintParameter.PRINT_PARAMETER_PHYSICIAN, MainFrame.getPhysicianById(incident.getPhysicianId()));
		
		return printParameter;
	}

	
	
	/* ======================================== */
	//		BILLING METHODS
	/* ======================================== */
	
	public static HashMap<String, Object> createDefaultPrintParameter (Invoice invoice)
	{
		return createDefaultPrintParameter(invoice, null);
	}
	
	
	public static HashMap<String, Object> createDefaultPrintParameter (Invoice invoice, Date settlementVerificationDate)
	{
		BillingPrinterInterface billingPrinter;
		SettlementInterface		settlementManager;
		Bailiff 				bailiff;
		UtilSettings 			settings;
		HashMap<String, Object> printParameter	= createDefaultPrintParameter();
		Integer					defaultAccountId;
		Account					defaultAccount	= null;
		List<Account>			accountList;
		
		
		printParameter.put(PrintParameter.PRINT_PARAMETER_PHYSICIAN, 	invoice.getPhysician());
		printParameter.put(PrintParameter.PRINT_PARAMETER_PATIENT, 	invoice.getPatient());
		printParameter.put(PrintParameter.PRINT_PARAMETER_INVOICE,		invoice);
		
		billingPrinter 	= getBillingPrinter();
		try
		{
			bailiff 		= billingPrinter.fetchBailiffForInvoice(invoice);
			printParameter.put(PrintParameter.PRINT_PARAMETER_BAILIFF, bailiff);
		}
		catch (Throwable e)
		{
			logger.log(Level.WARN, "Couldn't add the bailiff to the parameter list.", e);
			logger.log(Level.ERROR, e.getMessage(), e);
		}
		
		settings = (UtilSettings) printParameter.get(PrintParameter.PRINT_PARAMETER_SETTINGS);
		
		switch (invoice.getState().intValue())
		{
			case InvoiceWorkflow.c_PrintedState:
			case InvoiceWorkflow.c_RemindedState:
			case InvoiceWorkflow.c_PaidState:
				// mark invoice as copy
				settings.putSetting(UtilSettings.SETTING_IS_COPY, Boolean.TRUE);
				break;
				
			default: 
				settings.putSetting(UtilSettings.SETTING_IS_COPY, Boolean.FALSE);
				break;
		}
		
		accountList			= billingPrinter.getAccounts(invoice.getPhysician());
		if (settlementVerificationDate != null)
			settings.putSetting(UtilSettings.SETTING_SETTLEMENT_VERIFICATION_DATE, settlementVerificationDate);
		
		defaultAccountId	= (Integer)BillingModule.getSetting(BillingAdminSettings.c_DefaultAccountIdSetting);
		settlementManager	= getSettlementManager();
		
 		if (defaultAccountId != null)
			try
			{
				defaultAccount	= settlementManager.getAccountByID(defaultAccountId);
			}
			catch (Exception e)
			{
				logger.log(Level.ERROR, e.getMessage(), e);
			}
		
		// if there is no default account set, one from the list
		if (defaultAccount == null && !accountList.isEmpty())
		{
			for (Account account : accountList)
			{
				if (		account.getHolder() != null &&	account.getHolder().equals(invoice.getPhysician()))
				{
					defaultAccount	= accountList.get(0);
					break;
				}
				
				if (defaultAccount == null)
					defaultAccount	= account;
			}
		}
		
		printParameter.put(PrintParameter.PRINT_PARAMETER_ACCOUNT_LIST,	accountList);
		printParameter.put(PrintParameter.PRINT_PARAMETER_DEFAULT_ACCOUNT,	defaultAccount);
		// this is an old parameter, that should stay
		printParameter.put(PrintParameter.PRINT_PARAMETER_ACCOUNT,			defaultAccount);
		
		return printParameter;
	}
	
	
	public static HashMap<String, Object> createDefaultPrintParameter (InvoiceStub invoiceStub) 
	{
		HashMap<String, Object> printParameter = createDefaultPrintParameter();
		
		if (invoiceStub != null)
		{
			try
			{
				printParameter.put(PrintParameter.PRINT_PARAMETER_PATIENT, 	getPatientManager().getPatient(invoiceStub.getPatientId()));
				printParameter.put(PrintParameter.PRINT_PARAMETER_PHYSICIAN, 	getOfficeManager().getPhysician(invoiceStub.getPhysicianId()));
			} 
			catch (Exception e)
			{
				logger.log(Level.WARN, "Couldn't set patient and physician of this invoice.", e);
			}
		}
		
		return printParameter;
	}

	public static HashMap<String, Object> createDefaultPrintParameter (Collection<InvoiceStub> invoiceStub)
	{
		InvoiceStub 			anInvoiceStub 	= null;
		Iterator<InvoiceStub> 	iterator;
		
		if (invoiceStub != null && !invoiceStub.isEmpty())
		{
			iterator = invoiceStub.iterator();
			while (iterator.hasNext() && (anInvoiceStub = iterator.next()) == null) {
				;
			}
		}
		
		if (anInvoiceStub == null) {
			return createDefaultPrintParameter();			
		} else {
			return createDefaultPrintParameter(anInvoiceStub);
		}
	}
	
	
	
	/* ======================================== */
	//		PRESCRIPTION METHODS
	/* ======================================== */
	
	public static HashMap<String, Object> createDefaultPrintParameter (Prescription prescription)
	{
		HashMap<String, Object> printParameter = createDefaultPrintParameter();
		Patient patient;
		
		try
		{
			Physician physician = getOfficeManager().getPhysician(prescription.getPhysicianId());
			printParameter.put(PrintParameter.PRINT_PARAMETER_PHYSICIAN, physician);
			
			if (prescription.getIncidentId() != null)
				patient 	= getPatientManager().getPatientOfIncident(prescription.getIncidentId());
			else 
			{
				try 
				{
					patient	= GECAMedModule.getCurrentPatient();
				}
				catch (Exception e) 
				{
					patient	= null;
				}
			}
			printParameter.put(PrintParameter.PRINT_PARAMETER_PATIENT, patient);
		} 
		catch (Exception e)
		{
			logger.log(Level.WARN, "Couldn't set patient and physician of this prescription.", e);
		}
		printParameter.put(PrintParameter.PRINT_PARAMETER_PRESCRIPTION, prescription);
		
		return printParameter;
	}
	
	
	
	/* ======================================== */
	// 		CERTIFICATE METHODS
	/* ======================================== */
	
	public static HashMap<String, Object> createDefaultPrintParameter (Date date, Incident incident)
	{
		HashMap<String, Object> printParameter = createDefaultPrintParameter();
		CertificateData certificate = new CertificateData(date, incident);
		printParameter.put(PrintParameter.PRINT_PARAMETER_CERTIFICATE, certificate);
		
		return printParameter;
	}
	
	
	
	/* ======================================== */
	// 		HELP METHODS
	/* ======================================== */
	
	/* ---------------------------------------- */
	// 		GET MANGER
	/* ---------------------------------------- */

	private static OfficeManagerInterface getOfficeManager ()
	{
		if (officeManager == null)
			officeManager = (OfficeManagerInterface) ManagerFactory.getRemote(OfficeManagerBean.class);
		
		return officeManager;
	}


	private static PatientAdminInterface getPatientManager ()
	{
		if (patientManager == null)
			patientManager 	= (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
		
		return patientManager;
	}
	
	private static BillingPrinterInterface getBillingPrinter ()
	{
		if (billingPrinter == null)
			billingPrinter = (BillingPrinterInterface) ManagerFactory.getRemote(BillingPrinterBean.class);
		
		return billingPrinter;
	}
	
	private static SettlementInterface getSettlementManager ()
	{
		if (settlementManager == null)
			settlementManager = (SettlementInterface) ManagerFactory.getRemote(SettlementBean.class);
		
		return settlementManager;
	}
}
