/*******************************************************************************
 * 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.agenda.ejb.mdb.beans;

import java.util.Calendar;
import java.util.Collection;
import java.util.GregorianCalendar;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.AgendaCalendar;
import lu.tudor.santec.gecamed.agenda.ejb.session.beans.DoctenaSyncBean;
import lu.tudor.santec.gecamed.agenda.ejb.session.interfaces.AppointmentManager;
import lu.tudor.santec.gecamed.agenda.ejb.session.interfaces.DoctenaSyncInterface;
import lu.tudor.santec.gecamed.agenda.utils.AgendaAdminSettingsConstants;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.log.Log;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.log.LogType;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.LogManager;
import lu.tudor.santec.gecamed.core.schedulable.GECAMedHeartbeatPoster;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;

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


/**
 * Message driven bean that registers to the GECAMED Heartbeat JMS Topic
 *   
 */
@MessageDriven(activationConfig =
{
  @ActivationConfigProperty(propertyName = "destinationType", 	propertyValue="javax.jms.Topic"),
  @ActivationConfigProperty(propertyName = "destination",		    propertyValue=GECAMedHeartbeatPoster.HeartbeatTopic),
  @ActivationConfigProperty(propertyName = "acknowledgeMode", 	propertyValue = "AUTO_ACKNOWLEDGE"),
  @ActivationConfigProperty(propertyName = "maxSession", 		propertyValue = "1")
 })
public class DoctenaSyncSchedulerBean implements MessageListener{

    @EJB
    LoginInterface loginBean;
    
    @EJB
    AppointmentManager appoitmentManager;
    
    @EJB
    DoctenaSyncInterface doctenaSyncBean;
    
    @EJB
    LogManager logManager;
    
    private static int instanceNr;
   
    private static boolean isrunning;
    
    private static long  lastSYNC;
	
	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger.getLogger(DoctenaSyncSchedulerBean.class.getName());
	
	
	/* (non-Javadoc)
	 * @see javax.jms.MessageListener#onMessage(javax.jms.Message)
	 */
	public void onMessage(Message msg) {
		/* ================================================== */

	    if (isrunning)
		return;
	    
	    isrunning = true;
	    
		try	{
			if (msg instanceof TextMessage) 	{		
				TextMessage textMessage = (TextMessage) msg;
				if (textMessage.getText() == null)
					return;
				if (textMessage.getText().equals(GECAMedHeartbeatPoster.DoMinutely)){
					boolean active = false;
					try {
						active = (Boolean) loginBean.getAdminSettingValue(AgendaAdminSettingsConstants.NAME, AgendaAdminSettingsConstants.DOCTENA_SYNC_ACTIVE, AgendaAdminSettingsConstants.DEFAULT_DOCTENA_SYNC_ACTIVE);
					} catch (Exception e) {
						logger.log(Level.DEBUG, "Unable to read Admin Setting: " +AgendaAdminSettingsConstants.DEFAULT_DOCTENA_SYNC_ACTIVE);
					}
					if (active) {
						Integer syncinterval = (Integer) loginBean.getAdminSettingValue(AgendaAdminSettingsConstants.NAME, AgendaAdminSettingsConstants.DOCTENA_SYNC_INTERVAL, AgendaAdminSettingsConstants.DEFAULT_DOCTENA_SYNC_INTERVAL);
						// every X min....
						if (new GregorianCalendar().get(Calendar.MINUTE) % syncinterval == 0) {
//							long passedHours = (System.currentTimeMillis() - lastSYNC)/1000/60/60;
//							if (passedHours > 24) {
//								logger.log(Level.INFO, "DOCTENA: Last Fullsync is " + passedHours + " hours ago, STARTING FULL SYNC");
//								doSync(true);
//							} else {								
								doSync(false);
//							}
							lastSYNC = System.currentTimeMillis();
						} else {
							logger.log(Level.DEBUG, "Doctena Sync interval not reached");
						}
					} else {
						logger.log(Level.DEBUG, "Doctena Sync Disabled in Settings");
					}
				} 
			}
		}
		catch (Exception p_Exception){
			logger.log(Level.FATAL, "Failed to process received message",p_Exception);
		}
		
	     isrunning = false;
	     
	     /* ================================================== */
	}

	/**
	 * Start the import from appointment in the waitingrooms
	 */
	private void doSync(boolean fullSync) {
		// fetch calendars
		logger.log(Level.INFO, "DOCTENA: Starting Doctena Sync");
		long globalStart = System.currentTimeMillis();
		int pushedAppointments = 0;
		int fetchedAppointments = 0;
		int importedAppointments = 0;
		try {
			Collection<AgendaCalendar> cals = appoitmentManager.getCalendars();
			if (cals != null && cals.size() > 0) {
				for (AgendaCalendar agenda : cals) {
					String login = agenda.getDoctenaLogin();
					String password = agenda.getDoctenaPassword();
					// only if we have login data....
					if (login != null && login.trim().length() > 0 && password != null && password.trim().length() > 0) {
						int fetched = 0;
						int imported = 0;
						int pushed = 0;
						logger.log(Level.DEBUG, "Starting Doctena Sync configured for Agenda: " + agenda);
						long start = System.currentTimeMillis();
						String log = null;
						boolean ok = false;
						try {
							DoctenaSyncInterface docManager = (DoctenaSyncInterface) ManagerFactory.getStatefulRemote(DoctenaSyncBean.class);
							
							docManager.intSyncBean(agenda);
							
							if (docManager.connectFTP()) {
								
								ok = docManager.syncDoctena(fullSync, false);
								
								log = docManager.getLog();
								fetched = docManager.getFetchedAppointments();
								fetchedAppointments += fetched;
								imported = docManager.getImportedAppointments();
								importedAppointments += imported;
								pushed = docManager.getPushedAppointments();
								pushedAppointments += pushed;

								agenda = docManager.getAgenda();
							} else {
								ok = false;
							}
						} catch (Throwable ex) {
							ok = false;
//							logger.log(Level.FATAL, "Error Syncing "+agenda+" with Doctena.lu",ex);
							if (log == null) {
								log = ex.getMessage();
								if (ex.getCause() != null) {
									ex = ex.getCause();
									log += " " + ex.getMessage();
									if (ex.getCause() != null) {
										ex = ex.getCause();
										log += " " + ex.getMessage();
									}
								}
							}
						} finally {
							long took = System.currentTimeMillis()-start;
							if (!ok) {
								logger.log(Level.WARN, "=============== DOCTENA SYNC FAILED FOR AGENDA: "+agenda+" ============\n" + log); 
								Log logEntry = new Log(LogType.SYSTEM, "DOCTENA SYNC FAILED", "DOCTENA", "Doctena Sync for Agenda: " + agenda + " Failed!" + log, took);
								logManager.saveLog(logEntry);
							} else {								
								logger.log(Level.INFO, "DOCTENA: Doctena Sync for Agenda: " + agenda + " took: " + took + " " + numbersInfo(fetched, imported, pushed));
							}
						}
					} else {
						logger.log(Level.DEBUG, "No Doctena Sync configured for Agenda: " + agenda);
					}
				}
			}
			
		} catch (Throwable e) {
			logger.log(Level.FATAL, "Error Syncing Calendars with Doctena.lu",e);
		}
		
		
		long took = System.currentTimeMillis()-globalStart;
		logger.log(Level.INFO, "DOCTENA: Doctena Sync FINISHED took " + took + " " + numbersInfo(fetchedAppointments, importedAppointments, pushedAppointments));
		Log logEntry = new Log(LogType.SYSTEM, "DOCTENA SYNC", "DOCTENA", "Doctena Sync DONE! " + numbersInfo(fetchedAppointments, importedAppointments, pushedAppointments), took);
		logManager.saveLog(logEntry);
		
		/* ================================================== */
	}
	
	
	private String numbersInfo(int fetchedAppointments, int importedAppointments, int pushedAppointments) {
		StringBuffer sb = new StringBuffer();
		sb.append("Fetched: ").append(fetchedAppointments);
		sb.append(" Imported: ").append(importedAppointments);
		sb.append(" Pushed: ").append(pushedAppointments);
		return sb.toString();
	}

	@PostConstruct
	public void postConstruct () {
	    instanceNr++;
	    logger.info("DoctenaSyncSchedulerBean postConstruct instances: " + instanceNr);
	}
	
	@PreDestroy
	public void preDestroy () {
	    instanceNr--;
	    logger.info("DoctenaSyncSchedulerBean preDestroy instances: " + instanceNr);
	}

}