package lu.tudor.santec.gecamed.agenda.gui;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.swing.JDialog;

import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.AgendaCalendar;
import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.Appointment;
import lu.tudor.santec.gecamed.agenda.ejb.session.beans.AppointmentManagerBean;
import lu.tudor.santec.gecamed.agenda.ejb.session.interfaces.AppointmentManager;
import lu.tudor.santec.gecamed.core.ejb.session.beans.TemplateManagerBean;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.TemplateManagerInterface;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.widgets.ErrorDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.PrintPreviewDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.print.PrintParameterFetcher;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
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.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 net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

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

import bizcal.common.Event;

/**
 * Printer class of the agenda modul. All agenda prints are generated by this
 * class. The template is filled with data from the current physian, patient and
 * office. To gain a standard font and layout the templates are generated on
 * server-side because the past has shown that clients can vary in their
 * installed set of fonts.
 * 
 * @author Thorsten Roth thorsten.roth(at)tudor.lu
 * 
 * @version <br>
 *          $Log: AgendaPrinter.java,v $
 *          Revision 1.11  2013-12-27 18:09:25  donak
 *          Cleanup of imports
 *
 *          Revision 1.10  2013-07-15 06:18:36  ferring
 *          logging changed
 *
 *          Revision 1.9  2013-04-24 12:55:25  troth
 *          Fix path one of Ticket #1179.
 *
 *          Revision 1.8  2013-04-24 09:30:05  troth
 *          Bug fix: Print holidays events causes a Error.
 *
 *          Revision 1.7  2013-01-22 14:21:29  ferring
 *          iReport templates will now be compiled only once until the server is stopped
 *
 *          Revision 1.6  2012-01-24 10:42:29  ferring
 *          Maiden name printing fixed
 *
 *          Revision 1.5.2.1  2012-01-20 09:13:54  ferring
 *          BRANCHED VERSION
 *
 *          Revision 1.5  2011-11-16 11:47:16  troth
 *          fix Ticket #907 Error when trying to print list view of agenda entries
 *
 *          Revision 1.4  2011-10-05 08:29:48  ferring
 *          iReport printing changed. Beans added, only one formatter used for everything and reports changed, so that they only use the bean (util) Parameter
 *
 *          Revision 1.3  2011-09-28 13:14:03  troth
 *          Rename class AgendaPrinterObject in AgendaReportField
 *
 *          Revision 1.2  2011-09-14 12:20:34  troth
 *          Add the new function for printing a appointment overview for the physician.
 * <br>
 *          Revision 1.1 2011-09-02 14:11:55 troth <br>
 *          Add the new agenda appointment printing for patient function. <br>
 */
public class AgendaPrinter
{
	/*
	 * Different types of Agenda printouts
	 */
	public static final String PATIENT_TEMPLATE_TYPE = "agenda_template_pat";

	public static final String PHYSICIAN_TEMPLATE_TYPE = "agenda_template_phy";

	public static final String PATIENT_DEFAULT_TEMPLATE_FILE = "templates/AgendaPatientAppointmentPrintTemplate.jrxml";

	public static final String PHYSICIAN_DEFAULT_TEMPLATE_FILE = "templates/AgendaPhysicianAppointmentPrintTemplate.jrxml";

	// the print dialog
	private static PrintPreviewDialog printPreviewDialog = new PrintPreviewDialog();

	// the logger Object for this class
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(AgendaPrinter.class.getName());	

	/*
	 * Needed beans
	 */
	private static AppointmentManager appointmentManager;

	private static PatientAdminInterface patientManager;

	private static OfficeManagerInterface officeManager;

	/*
	 * Initialize all needed beans
	 */
	static
	{
		try{
			appointmentManager = (AppointmentManager) ManagerFactory.getRemote(AppointmentManagerBean.class);
			patientManager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
			officeManager = (OfficeManagerInterface) ManagerFactory.getRemote(OfficeManagerBean.class);
		} catch (Exception e) {
			logger.log(Level.WARN, "Couldn't set appointment-, patient- and physician- Bean of this agenda print.", e);
		}
	}

	/**
	 * Show the generated JasperReport in a print dialog.
	 * 
	 * @param appointmentList a list of events to print
	 * @param maxNumberAppointments the max number of events to print
	 * @param defaultTemplateFile the default template filename
	 * @param parent the parent dialog
	 * @return true if print dialog was displayed successfully else false
	 */
	public static boolean print(List<Event> appointmentList,
			int maxNumberAppointments, String templateBeanName, JDialog parent)
	{

		try{
			JasperPrint agendaPrint = generateAgendaReport(appointmentList,
					maxNumberAppointments, templateBeanName);
			
			if (parent == null){
				return printPreviewDialog.doPrint(agendaPrint);
			} else {
				
				PrintPreviewDialog pp = new PrintPreviewDialog(parent);
				return pp.doPrint(agendaPrint);
			}	
		} catch (Exception e) {
			e.printStackTrace();
			logger.log(Level.WARN, "Couldn't generate JasperPrint.", e);
			return false;
		}
	}

	/**
	 * Generate different types of Agenda JasperPrintReport.
	 * 
	 * @param appointmentList a list of events to print
	 * @param maxNumberAppointments the max number of events to print
	 * @param templateBeanName the template type to print
	 * @return the generated JasperPrint
	 * @throws JRException if not able to compile JasperReport
	 */
	private static JasperPrint generateAgendaReport(
			List<Event> appointmentList, int maxNumberAppointments,
			String templateBeanName) throws JRException
	{
		// =================================================
		// load Jasper Template
		// =================================================
		// jasper parameter hashmap
		HashMap<String, Object> param = PrintParameterFetcher
				.createDefaultPrintParameter();
		// jasper dataSource
		JRBeanCollectionDataSource dataSource = null;
//		JasperReport compiledDefaultTemplate = null;
		JasperReport jasperReport = null;

		// -------------------------------------------------
		// get the patient over first event in list
		// -------------------------------------------------
//		Event event = null;
//		Patient patient = null;
//		Appointment appointment = null;
		// get the event
//		event = appointmentList.get(0);
//		// get the appointment
//		appointment = (Appointment) event.getId();
//
//		try {
//			// get the patient
//			patient = patientManager.getPatient(appointment.getPatientId());
//		} catch (Exception e) {
//			logger.log(Level.WARN, "Couldn't set patient for this agenda print.");
//		}

		// -------------------------------------------------
		// get the current physician
		// -------------------------------------------------
		Physician currentPhysician = GECAMedModule.getCurrentPhysician();
		
		/*
		 * This is already done when using the PrintParameterFetcher to 
		 * generate the parameters.
		 */
//		// -------------------------------------------------
//		// get the current office
//		// -------------------------------------------------
//		Office currentOffice = MainFrame.getCurrentOffice();
//		// -------------------------------------------------
//		// set jasper parameter hashmap
//		// -------------------------------------------------
//		// set constant
//		param.put("TODAY", 			new Date());
//		param.put("NEWLINE", 		System.getProperty("line.separator"));
//		// set Beans
//		param.put("beanPatient", 	patient);
//		param.put("beanPhysician", 	currentPhysician);
//		param.put("beanOffice", 	currentOffice);
//		// set Formatter
//		param.put("utilFormatter", 	new UtilFormatter());

		// -------------------------------------------------
		// create the report
		// -------------------------------------------------
		try {

			TemplateManagerInterface tm = (TemplateManagerInterface) ManagerFactory
					.getRemote(TemplateManagerBean.class);
			jasperReport = tm.findTemplate(templateBeanName, currentPhysician.getId(), new Date());
			
//			Template t = null;
//			
//			try {
//				// get current physician and set date to new date
//				t = tm.getTemplate(templateType, currentPhysician.getId(),
//						new Date());
//			} catch (Exception e) {
//				logger.error("error fetching template from DB");
//			}
//			if (t != null) {
//				logger.info("using template from DB");
//				jasperReport = (JasperReport) JRLoader
//						.loadObject(new ByteArrayInputStream(t.getJasper()));
//			} else {
//				logger.info("using default template");
//				if (compiledDefaultTemplate == null) {
//					JasperDesign design = (JasperDesign) JRXmlLoader
//							.load(AgendaModule.class
//									.getResourceAsStream(defaultTemplateFile));
//					compiledDefaultTemplate = tm.compileReport(design);
//				}
//				jasperReport = compiledDefaultTemplate;
//			}

		} catch (Exception e) {
			ErrorDialog.showErrorDialog(MainFrame.getInstance(), e);
			logger.log(Level.WARN, " ", e);
		}

		// -------------------------------------------------
		// set jasper dataSource object
		// -------------------------------------------------
		ArrayList<AgendaReportField> apps = new ArrayList<AgendaReportField>();
		Patient patient = null;
		AgendaCalendar calendar = null;
		Physician phy = null;
		Appointment appointment = null;
		Event event = null;
		
		for (int i = 0; i < maxNumberAppointments; i++) {
			// get the event
			event = appointmentList.get(i);
			// get the appointment
			appointment = (Appointment) event.getId();
						
			if(appointment != null)
			{
				// get the calender
				calendar = appointmentManager.getCalendar(appointment.getCalendarId());
				
				try {
					// get the physician
					phy = officeManager.getPhysician(calendar.getPhysicianId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set physician for this agenda print.");
					phy = null;
					if(event.isBackground()) {
						phy = new Physician(Translatrix.getTranslationString("pm.office"));
					} else {
						phy = new Physician(calendar.getTitle());
					}
				}
	
				try {
					// get the patient
					patient = patientManager.getPatient(appointment.getPatientId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set patient for this agenda print.");
					// create dummy patient for office and unavailable events
					patient = null;
					patient = new Patient();
					patient.setSurName(event.getSummary());
				}
			}
			else{
				// create dummy patient and physician for holiday events
				phy = new Physician(Translatrix.getTranslationString("Agenda.holiday"));
				patient = new Patient();
				patient.setSurName(event.getSummary());
			}
			// create and add AgendaPrinterObject
			apps.add(new AgendaReportField(event, patient, phy));
			
		}

		dataSource = new JRBeanCollectionDataSource(apps);

		// -------------------------------------------------
		// set data to jasper report
		// -------------------------------------------------
		try {
			return JasperFillManager.fillReport(jasperReport, param,
					(JRDataSource) dataSource);
		} catch (Exception e) {
			logger.log(Level.WARN,
					"unable to generate agenda patient list print", e);
			return null;
		}
	}
}