/**
 * JobManager.java
 * Created on May 15, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.job;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import com.tandbergtv.watchpoint.pmm.dao.hibernate.HibernateContext;
import com.tandbergtv.watchpoint.pmm.entities.Job;
import com.tandbergtv.watchpoint.pmm.entities.RuleType;
import com.tandbergtv.watchpoint.pmm.job.dao.IJobHDAO;
import com.tandbergtv.watchpoint.pmm.job.dao.IJobRuleTypeDAO;
import com.tandbergtv.watchpoint.pmm.job.dao.JobHDAO;
import com.tandbergtv.watchpoint.pmm.job.dao.JobRuleTypeHDAO;
import com.tandbergtv.watchpoint.pmm.job.scheduling.IJobScheduleManager;
import com.tandbergtv.workflow.core.service.ServiceRegistry;

/**
 * This class manages all job related tasks.
 * @author spuranik
 */
public class JobManager implements IJobManager {

	private static IJobManager instance;
	private static final Logger logger = Logger.getLogger(JobManager.class);

	/**
	 * Default ctor
	 */
	private JobManager() {
	}

	/**
	 * @return singleton object of job manager
	 */
	public static synchronized IJobManager getInstance() {
		if (instance == null) {
			instance = new JobManager();
		}
		return instance;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#createJob(com.tandbergtv.watchpoint.pmm.entities.Job)
	 */
	public boolean createJob(Job job) {
		Session session = null;
		try {
			// add the job to the database
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobHDAO jobDAO = new JobHDAO(session);
			jobDAO.create(job);

			// schedule the job in the scheduling engine
			IJobScheduleManager scheduleManager = ServiceRegistry.getDefault().lookup(IJobScheduleManager.class);
			scheduleManager.addSchedule(job);

			session.getTransaction().commit();
		} catch (Exception e) {
			// if the job could not be added to the scheduling engine
			// rollback the db transaction as this is treated as an atomic unit.			
			try {
				session.getTransaction().rollback();
			} catch (HibernateException e1) {
				logger.error("Error while rolling back in createJob: " + e1.toString(), e1);
			}
			logger.error("Error while creating job: " + e.getMessage(), e);
			return false;
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#deleteJob(long)
	 */
	public synchronized boolean deleteJob(long jobId) {
		Session session = null;
		try {
			// get the job in the first session. this will be used for removing
			// the schedule
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobHDAO jobDAO = new JobHDAO(session);
			Job j = jobDAO.findByKey(jobId);
			jobDAO.delete(jobId);

			// remove schedule for the job from the scheduling engine
			IJobScheduleManager scheduleManager = ServiceRegistry.getDefault().lookup(IJobScheduleManager.class);
			scheduleManager.deleteSchedules(j);
			
			session.getTransaction().commit();
		} catch (Exception e) {
			// if the job could not be deleted from the scheduling engine
			// rollback the db transaction as this is treated as an atomic unit.
			try {
				session.getTransaction().rollback();
			} catch (HibernateException e1) {
				logger.error("Error while rolling back in deleteJob: " + e1.toString(), e1);				
			}
			logger.error("Error while deleting job(id: " + jobId + "): " + e.getMessage(), e);
			return false;
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#getAllJobs(long)
	 */
	public synchronized List<Job> getAllJobs(long contextId) {
		Session session = null;
		List<Job> jobs = new ArrayList<Job>();
		try {
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobHDAO jobDAO = new JobHDAO(session);
			Criteria criteria = session.createCriteria(Job.class).add(
					Restrictions.eq("context.id", contextId));
			jobs = jobDAO.findByCriteria(criteria);
			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error("Error while getting all jobs: " + e.getMessage(), e);
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return jobs;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#getRuleType(java.lang.String)
	 */
	public RuleType getRuleType(String name) {
		Session session = null;
		RuleType ruleType = new RuleType();
		try {
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobRuleTypeDAO ruleTypeDAO = new JobRuleTypeHDAO(session);
			Criteria criteria = session.createCriteria(RuleType.class).add(
					Restrictions.eq("name", name));
			ruleType = ruleTypeDAO.findUniqueByCriteria(criteria);
			session.getTransaction().commit();
			return ruleType;
		} catch (Exception e) {
			logger.error("Error while getting rule type(" + name + "): " + e.getMessage(), e);
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return ruleType;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#getAllRuleTypes()
	 */
	public List<RuleType> getAllRuleTypes() {
		Session session = null;
		List<RuleType> ruleTypes = new ArrayList<RuleType>();
		try {
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobRuleTypeDAO ruleTypeDAO = new JobRuleTypeHDAO(session);
			ruleTypes = ruleTypeDAO.findAll();
			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error("Error while getting all rule types: " + e.getMessage(), e);
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return ruleTypes;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#getRuleType(org.hibernate.Criteria)
	 */
	public List<RuleType> getRuleTypes(boolean isAssociatedWithTitles) {
		Session session = null;
		List<RuleType> ruleTypes = new ArrayList<RuleType>();
		try {
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobRuleTypeDAO ruleTypeDAO = new JobRuleTypeHDAO(session);
			Criteria criteria = session.createCriteria(RuleType.class).add(
					Restrictions.eq("titlesAssociated", isAssociatedWithTitles));
			ruleTypes = ruleTypeDAO.findByCriteria(criteria);
			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error("Error while getting rule type(" + isAssociatedWithTitles + "): "
					+ e.getMessage(), e);
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return ruleTypes;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#getJob(long)
	 */
	public synchronized Job getJob(long jobId) {
		Job j = new Job();
		Session session = null;
		try {
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobHDAO jobDAO = new JobHDAO(session);
			j = jobDAO.findByKey(jobId);
			j.getName();
			session.getTransaction().commit();
		} catch (Exception e) {
			logger.error("Error while getting job(id: " + jobId + "): " + e.getMessage(), e);
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return j;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.IJobManager#updateJob(com.tandbergtv.watchpoint.pmm.entities.Job)
	 */
	public synchronized boolean updateJob(Job job) {
		Session session = null;
		try {
			session = HibernateContext.getContext().getCurrentSession();
			session.beginTransaction();
			IJobHDAO jobDAO = new JobHDAO(session);
			jobDAO.update(job);

			// update the schedule for this job in the scheduling engine
			IJobScheduleManager scheduleManager = ServiceRegistry.getDefault().lookup(IJobScheduleManager.class);
			scheduleManager.updateSchedule(job);

			session.getTransaction().commit();
		} catch (Exception e) {
			// if the job could not be deleted from the scheduling engine
			// rollback the db transaction as this is treated as an atomic unit.
			try {
				session.getTransaction().rollback();
			} catch (HibernateException exp) {
				logger.error("Error while rolling back in updateJob: " + exp.toString(), exp);				
			}
			logger.error("Error while updating job(id: " + job.getId() + "): " + e.getMessage(), e);
			return false;
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
		return true;
	}
}
