/**
 * JobValidator.java
 * Created on May 30, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.web.validators;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.commons.validator.Field;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

import com.tandbergtv.watchpoint.pmm.entities.JobRuleTypeConstants;
import com.tandbergtv.watchpoint.pmm.entities.RuleParameterDataType;
import com.tandbergtv.watchpoint.pmm.entities.RuleType;
import com.tandbergtv.watchpoint.pmm.entities.RuleTypeParameter;
import com.tandbergtv.watchpoint.pmm.job.IJobManager;
import com.tandbergtv.watchpoint.pmm.job.JobManager;
import com.tandbergtv.watchpoint.pmm.job.ui.JobUIConstants;
import com.tandbergtv.watchpoint.pmm.job.util.Day;
import com.tandbergtv.watchpoint.pmm.job.util.ParameterReferenceHelper;
import com.tandbergtv.watchpoint.pmm.web.formbeans.job.JobForm;
import com.tandbergtv.watchpoint.pmm.web.formbeans.job.JobParameterForm;
import com.tandbergtv.watchpoint.pmm.web.formbeans.job.RuleParameterForm;
import com.tandbergtv.watchpoint.pmm.web.util.JobFormPopulator;
import com.tandbergtv.workflow.core.Datatype;
import com.tandbergtv.workflow.core.TaskVariable;
import com.tandbergtv.workflow.core.WorkflowTemplate;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.driver.service.ITemplateLoaderService;

/**
 * This class has methods to validate the input from the job UI
 * 
 * @author spuranik
 * 
 */
public class JobValidator {

	private static String PARAMETER_NAME_DELIMETER = ",";
	private static int INVALID_INDEX = -1;
	private static int MAX_JOB_NAME_LENGTH = 25;
	private static final String JOB_NAME = "name";
	private static final String JOB_START_DATE = "jobStartDate";
	private static final String JOB_END_DATE = "jobEndDate";
	private static final String JOB_SELECTED_RULETYPE = "selectedRuleType";
	private static final String JOB_SELECTED_TEMPLATE = "selectedTemplate";
	private final static String durationFormat = getDurationFormat();

	private static final Logger logger = Logger.getLogger(JobValidator.class);

	/**
	 * This method validates the parameter values entered for the templates task variables in the
	 * job.
	 * 
	 * @param obj
	 * @param action
	 * @param field
	 * @param msgs
	 * @param validator
	 * @param request
	 * @return
	 */
	public static boolean validateJobTemplateParams(java.lang.Object obj,
			org.apache.commons.validator.ValidatorAction action,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs,
			org.apache.commons.validator.Validator validator,
			javax.servlet.http.HttpServletRequest request) {
		if (!(request.getQueryString().equals("method=createJob") || request.getQueryString()
				.equals("method=updateJob"))) {
			return true;
		}

		JobForm jobForm = (JobForm) obj;
		List<String> paramNames = new ArrayList<String>();
		List<String> paramValues = new ArrayList<String>();

		// get all start variables for the selected template
		String selectedTemplateName = jobForm.getSelectedTemplate();
		Collection<TaskVariable> params = new ArrayList<TaskVariable>();

		ServiceRegistry registry = ServiceRegistry.getDefault();
		ITemplateLoaderService templateLoader = registry.lookup(ITemplateLoaderService.class);
		List<WorkflowTemplate> templates = templateLoader.getLatestTemplates();
		for (WorkflowTemplate t : templates) {
			if (t.getName().equals(selectedTemplateName)) {
				params = t.getStartTaskVariables();
				break;
			}
		}

		// get the names of the variables which were displayed
		// at job creation time
		String jobParamNames = jobForm.getJobParamNames();
		String jobParamNameList[] = jobParamNames.split(PARAMETER_NAME_DELIMETER);
		String values[] = jobForm.getValue();

		// loop thru each of the params to see if the variable is
		// found in the list which was displayed to the user
		for (TaskVariable currVariable : params) {
			if (currVariable.isRequired()) {
				paramNames.add(currVariable.getMappedName());
				int varIndex = getVariableIndex(currVariable.getMappedName(), jobParamNameList);
				if (varIndex != INVALID_INDEX) {
					// the variable was displayed at the time of job creation
					if (values[varIndex].length() == 0)
						paramValues.add(null);
					else
						paramValues.add(values[varIndex].trim());
				} else {
					// the variable was not shown at the time of job creation.
					// this could be because the template was updated in the meanwhile
					paramValues.add(null);
				}
			}
		}

		boolean isValid = validateRequiredSet(paramValues, paramNames, field, msgs, obj);

		List<JobParameterForm> paramForms = prepareJobParameterForm(params, values,
				jobParamNameList);
		isValid = validateDataTypeSet(paramForms, field, msgs) && isValid;

		JobFormPopulator.setRequiredInfoInForm(jobForm);

		return isValid;
	}

	public static boolean validateJobDates(java.lang.Object obj,
			org.apache.commons.validator.ValidatorAction action,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs,
			org.apache.commons.validator.Validator validator,
			javax.servlet.http.HttpServletRequest request) {
		if (!(request.getQueryString().equals("method=createJob") || request.getQueryString()
				.equals("method=updateJob"))) {
			return true;
		}

		JobForm jobForm = (JobForm) obj;

		boolean isValid = true;
		if (field.getKey().equalsIgnoreCase(JOB_START_DATE)) {
			if (jobForm.getJobStartDate().trim().length() > 0) {
				boolean startDateAllowed = startDateAllowed(jobForm.getSelectedRuleType());
				// check if start date is allowed for this rule
				if (!startDateAllowed) {
					String errorMsg = "Job start date cannot be used for rule type: "
							+ jobForm.getSelectedRuleType();
					msgs.add(field.getKey(), new ActionMessage(errorMsg, false));
					logger.debug("Adding error message: " + errorMsg);
					isValid = false;
				}

				// do the following format checks only if the start date is allowed.
				if (startDateAllowed) {
					// check the date format
					if (!isValidDate(jobForm.getJobStartDate(),
							JobUIConstants.JOB_START_DATE_FORMAT)) {
						msgs.add(field.getKey(), new ActionMessage(
								"Job start date should be a valid date in the correct format("
										+ JobUIConstants.JOB_START_DATE_FORMAT
										+ ").", false));
						logger
								.debug("Adding error message:"
										+ "Job start date should be a valid date in the correct format("
										+ JobUIConstants.JOB_START_DATE_FORMAT
										+ ").");
						isValid = false;
					}

					// check if the job start date is either current or in the
					// future for all rule types
					// other than on a specific date type.
					if (!jobForm.getSelectedRuleType().equalsIgnoreCase(
							JobRuleTypeConstants.ONDATE_RULE)) {
						if (isDateInPast(jobForm.getJobStartDate(),
								JobUIConstants.JOB_START_DATE_FORMAT)) {
							msgs.add(field.getKey(),new ActionMessage(
								"Job start date should be current or in the future.",
								false));
							logger
									.debug("Adding error message: Job start date should be current or in the future.");
							isValid = false;
						}
					}
				}
			}
			// check if the start date + time is always in the future for rule types other than on
			// a specific date type.
			if (!jobForm.getSelectedRuleType().equalsIgnoreCase(JobRuleTypeConstants.ONDATE_RULE)) {
				String time = getJobTime(jobForm);
				if (time == null
						|| isDateTimeInPast(jobForm.getJobStartDate(),
								JobUIConstants.JOB_START_DATE_FORMAT, time,
								JobUIConstants.JOB_RULE_TIME_FORMAT)) {
					msgs.add(field.getKey(), new ActionMessage(
							"Job start date time should be in the future.", false));
					logger.debug("Adding error message: "
							+ "Job start date time should be in the future.");
					isValid = false;
				}
			}
		} else if (field.getKey().equalsIgnoreCase(JOB_END_DATE)
				&& jobForm.getJobEndDate().trim().length() > 0) {
			boolean endDateAllowed = endDateAllowed(jobForm.getSelectedRuleType());
			// check if start date is allowed for this rule
			if (!endDateAllowed) {
				String errorMsg = "Job end date cannot be used for rule type: "
						+ jobForm.getSelectedRuleType();
				msgs.add(field.getKey(), new ActionMessage(errorMsg, false));
				logger.debug("Adding error message: " + errorMsg);
				isValid = false;
			}
			
			// do the following format checks only if the end date is allowed.
			if (endDateAllowed) {
				// check if the format is right
				String jobEndDate = jobForm.getJobEndDate();

				if (!isValidDate(jobEndDate, JobUIConstants.JOB_END_DATE_FORMAT)) {
					msgs.add(field.getKey(),
						new ActionMessage("Job end date should be a valid date in the correct format("
							+ JobUIConstants.JOB_END_DATE_FORMAT
							+ ").", false));
					logger.debug("Adding error message:"
						+ "Job end date should be a valid date in the correct format("
						+ JobUIConstants.JOB_END_DATE_FORMAT + ").");
					isValid = false;
				}

				// if the format is right, check if the date is current or in the future
				if (isDateInPast(jobEndDate, JobUIConstants.JOB_END_DATE_FORMAT)) {
					msgs.add(field.getKey(), new ActionMessage(
							"Job end date should be current or in the future.",
							false));
					logger.debug("Adding error message: Job end date should be current or in the future.");
					isValid = false;
				}
			}
		}
		JobFormPopulator.setRequiredInfoInForm(jobForm);

		return isValid;
	}

	/**
	 * Returns true/false based on the selected rule type. Certain rule types
	 * may not make sense with a start date. e.g. on a specific date and time.
	 * 
	 * @param selectedRuleType
	 * @return
	 */
	public static boolean startDateAllowed(String selectedRuleType) {
		return (!selectedRuleType.equals(JobRuleTypeConstants.ONDATE_RULE));
	}

	/**
	 * Returns true/false based on the selected rule type. Certain rule types
	 * may not make sense with a end date. e.g. on a specific date and time.
	 * 
	 * @param selectedRuleType
	 * @return
	 */	
	public static boolean endDateAllowed(String selectedRuleType) {
		return (!selectedRuleType.equals(JobRuleTypeConstants.ONDATE_RULE));
	}
	
	/**
	 * @param jobForm
	 * @return
	 */
	private static String getJobTime(JobForm jobForm) {

		String selectedRuleType = jobForm.getSelectedRuleType();
		List<RuleParameterForm> ruleParams = jobForm.getRuleParameters().get(selectedRuleType);

		IJobManager mgr = JobManager.getInstance();
		RuleType type = mgr.getRuleType(selectedRuleType);
		if (type != null) {
			List<RuleTypeParameter> ruleTypeParams = type.getParams();
			for (RuleTypeParameter p : ruleTypeParams) {
				if (p.getType() == RuleParameterDataType.TIME) {
					RuleParameterForm ruleParam = getRuleParam(ruleParams, p.getOrder());
					return ruleParam.getRuleParamValue();
				}
			}
		}
		return null;
	}

	/**
	 * @param params
	 * @param order
	 * @return
	 */
	private static RuleParameterForm getRuleParam(List<RuleParameterForm> params, int order) {
		for (RuleParameterForm p : params) {
			if (p.getOrder() == order) {
				return p;
			}
		}
		return null;
	}

	/**
	 * Checks if the given date (and format) is either current or in the future.
	 * 
	 * @param date
	 *            The date that needs to be verified
	 * @return true if the given date is either current or in the future.
	 */
	public static boolean isDateInPast(String date, String format) {
		try {
			SimpleDateFormat timefomat = new SimpleDateFormat(format);
			timefomat.setLenient(false);
			Date d = timefomat.parse(date);

			Calendar jobCalendar = Calendar.getInstance();
			jobCalendar.setTime(d);
			jobCalendar = resetTime(jobCalendar);

			Calendar currCalendar = Calendar.getInstance();
			currCalendar.setTime(new Date());
			currCalendar = resetTime(currCalendar);

			return jobCalendar.before(currCalendar);
		} catch (ParseException e) {
			// this should not happen as the format should be already verified
			// before this method is called.
			logger.error("Error while parsing date while determining if its in the future: "
					+ e.toString());
			return true;
		}
	}

	/**
	 * This method sets the time for this calendar to midnight. Basically removing the time
	 * information from the calendar.
	 * 
	 * @param jobCalendar
	 * @return
	 */
	private static Calendar resetTime(Calendar c) {
		c.set(Calendar.HOUR, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		c.set(Calendar.AM_PM, Calendar.AM);
		return c;
	}

	/**
	 * This method is called when the user has entered values in the job creation UI and clickd
	 * 'create'. This method ensures that the required rule parameters are filled with the expected
	 * data type
	 * 
	 * @param obj
	 * @param action
	 * @param field
	 * @param msgs
	 * @param validator
	 * @param request
	 * @return
	 */
	public static boolean validateJobRuleParams(java.lang.Object obj,
			org.apache.commons.validator.ValidatorAction action,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs,
			org.apache.commons.validator.Validator validator,
			javax.servlet.http.HttpServletRequest request) {
		if (!(request.getQueryString().equals("method=createJob") || request.getQueryString()
				.equals("method=updateJob"))) {
			return true;
		}
		boolean isValid = true;

		JobForm jobForm = (JobForm) obj;

		// get selected rule typename
		// for that ruletype, get the parameters
		// for each of these parameters, make sure that values are provided if its not optional
		// also validate the values provided against the data type
		// String[] ruleParams = jobForm.getRuleParamValue();
		String selectedRuleType = jobForm.getSelectedRuleType();
		String[] ruleParams = JobFormPopulator.getRuleParamsForSelectedRule(jobForm);

		IJobManager jobMgr = JobManager.getInstance();
		RuleType ruleType = jobMgr.getRuleType(selectedRuleType);
		List<RuleTypeParameter> ruleTypeParams = ruleType.getParams();

		isValid = validateRequiredRuleTypeParameters(ruleTypeParams, ruleParams, field, msgs);
		isValid = validateRuleParamsDataTye(ruleTypeParams, ruleParams, field, msgs) && isValid;
		isValid = validateRuleParams(ruleType, ruleParams, field, msgs);

		JobFormPopulator.setRequiredInfoInForm(jobForm);

		return isValid;
	}

	/**
	 * Runs thru any validation required for a specific rule. This is run after verifying that all
	 * required items have been provided and are of the correct data type.
	 * 
	 * @param ruleType
	 *            the rule type whose rules will be used to run the validation
	 * @param ruleParams
	 *            rule params given by the user
	 * @param field
	 *            field which needs to be validated
	 * @param msgs
	 *            error msgs that will be returned back
	 * @return true if validation was successful else false
	 */
	private static boolean validateRuleParams(RuleType ruleType, String[] ruleParams, Field field,
			ActionMessages msgs) {
		String ruleTypeName = ruleType.getName();
		List<RuleTypeParameter> ruleTypeParams = ruleType.getParams();

		if (ruleTypeName.equalsIgnoreCase(JobRuleTypeConstants.ONDATE_RULE)) {
			// the date specified should be current or in the future.
			if (isDateInPast(ruleParams[JobRuleTypeConstants.DATE_INDEX],
					JobUIConstants.JOB_RULE_PARAM_DATE_FORMAT)) {
				String parameterName = ruleTypeParams.get(JobRuleTypeConstants.DATE_INDEX)
						.getName();

				msgs.add(field.getKey(), new ActionMessage(parameterName
						+ " should be current or in the future.", false));
				logger.debug("Adding error message: " + parameterName
						+ "  should be current or in the future.");
				return false;
			}

			// the date + time should always be in the future.
			if (isDateTimeInPast(ruleParams[JobRuleTypeConstants.DATE_INDEX],
					JobUIConstants.JOB_RULE_PARAM_DATE_FORMAT,
					ruleParams[JobRuleTypeConstants.ONDATE_TIME_INDEX],
					JobUIConstants.JOB_RULE_TIME_FORMAT)) {
				msgs.add(field.getKey(), new ActionMessage(
						"Job rule date time should be in the future.", false));
				logger.debug("Adding error message: "
						+ "Job rule date time should be in the future.");
				return false;
			}
		} else if (ruleTypeName.equalsIgnoreCase(JobRuleTypeConstants.EVERY_N_DAYS_RULE)) {
			int numberOfDays = Integer.parseInt(ruleParams[JobRuleTypeConstants.DAYS_INDEX]);
			// number of days cannot be set to 0
			if (numberOfDays == 0) {
				String parameterName = ruleTypeParams.get(JobRuleTypeConstants.DAYS_INDEX)
						.getName();
				msgs.add(field.getKey(), new ActionMessage(
						parameterName + " for rule cannot be 0.", false));
				logger.debug("Adding error message:" + parameterName + " for rule cannot be 0.");
				return false;
			}

		} else if (ruleTypeName.equalsIgnoreCase(JobRuleTypeConstants.ON_DAY_EVERY_N_WEEKS_RULE)) {
			int numberOfWeeks = Integer.parseInt(ruleParams[JobRuleTypeConstants.WEEK_INDEX]);
			// number of weeks cannot be set to 0
			if (numberOfWeeks == 0) {
				String parameterName = ruleTypeParams.get(JobRuleTypeConstants.WEEK_INDEX)
						.getName();
				msgs.add(field.getKey(), new ActionMessage(
						parameterName + " for rule cannot be 0.", false));
				logger.debug("Adding error message:" + parameterName + " for rule cannot be 0.");
				return false;
			}
		}
		return true;
	}

	public static boolean validateRequiredItem(java.lang.Object obj,
			org.apache.commons.validator.ValidatorAction action,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs,
			org.apache.commons.validator.Validator validator,
			javax.servlet.http.HttpServletRequest request) {
		if (!(request.getQueryString().equals("method=createJob") || request.getQueryString()
				.equals("method=updateJob"))) {
			return true;
		}

		boolean isValid = true;

		JobForm jobForm = (JobForm) obj;

		if (field.getKey().equalsIgnoreCase(JOB_NAME)) {
			if (jobForm.getName() == null || jobForm.getName().trim().length() == 0) {
				msgs.add(field.getKey(), new ActionMessage("Job name is required.", false));
				logger.debug("Adding error message:" + " Job name is required.");
				isValid = false;
			}
			if (jobForm.getName().trim().length() > MAX_JOB_NAME_LENGTH) {
				msgs.add(field.getKey(), new ActionMessage("Job name length should be <= "
						+ MAX_JOB_NAME_LENGTH + ".", false));
				logger.debug("Adding error message:" + "Job name length should be <= "
						+ MAX_JOB_NAME_LENGTH + ".");
				isValid = false;
			}
		}
		if (field.getKey().equalsIgnoreCase(JOB_SELECTED_RULETYPE)) {
			if (jobForm.getSelectedRuleType() == null
					|| jobForm.getSelectedRuleType().trim().length() == 0) {
				msgs.add(field.getKey(), new ActionMessage(
						"Schedule rule must be selected for job.", false));
				logger.debug("Adding error message:" + "Schedule rule must be selected for job.");
				isValid = false;
			}
		}
		if (field.getKey().equalsIgnoreCase(JOB_SELECTED_TEMPLATE)) {
			if (jobForm.getSelectedTemplate() == null
					|| jobForm.getSelectedTemplate().trim().length() == 0) {
				msgs.add(field.getKey(), new ActionMessage(
						"A template must be selected for the job.", false));
				logger.debug("Adding error message:" + "A template must be selected for the job.");
				isValid = false;
			}
		}

		JobFormPopulator.setRequiredInfoInForm(jobForm);

		return isValid;
	}

	private static boolean validateRequiredRuleTypeParameters(
			List<RuleTypeParameter> ruleTypeParams, String[] ruleParams,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs) {
		boolean isValid = true;

		for (int i = 0; i < ruleTypeParams.size(); i++) {
			if (ruleTypeParams.get(i).getIsRequired()) {
				if (ruleParams[i] == null || ruleParams[i].trim().length() == 0) {
					msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
							+ " for rule is required.", false));
					logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
							+ " for rule  is required.");
					isValid = false;
				}
			}
		}
		return isValid;
	}

	private static boolean validateRuleParamsDataTye(List<RuleTypeParameter> ruleTypeParams,
			String[] ruleParams, org.apache.commons.validator.Field field,
			org.apache.struts.action.ActionMessages msgs) {

		boolean isValid = true;

		for (int i = 0; i < ruleTypeParams.size(); i++) {
			if (ruleParams[i] != null && ruleParams[i].trim().length() != 0) {
				RuleParameterDataType type = ruleTypeParams.get(i).getType();
				if (type == RuleParameterDataType.DATE) {
					if (!isValidDate(ruleParams[i], JobUIConstants.JOB_RULE_PARAM_DATE_FORMAT)) {
						msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
								+ " should be a valid date in the correct format("
								+ JobUIConstants.JOB_RULE_PARAM_DATE_FORMAT + ").", false));
						logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
								+ " should be a valid date in the correct format("
								+ JobUIConstants.JOB_RULE_PARAM_DATE_FORMAT + ").");
						isValid = false;
					}
				} else if (type == RuleParameterDataType.DAY) {
					if (!isValidDay(ruleParams[i])) {
						msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
								+ " should be a valid week day.", false));
						logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
								+ " should be a valid week day.");
						isValid = false;
					}
				} else if (type == RuleParameterDataType.INTEGER) {
					try {
						int number = Integer.parseInt(ruleParams[i]);
						if (number < 0) {
							msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i)
									.getName()
									+ " must be a valid positive integer.", false));
							logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
									+ " must be a valid positive integer.");
							isValid = false;
						}
					} catch (NumberFormatException ex) {
						msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
								+ " must be a valid integer.", false));
						logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
								+ " must be a valid integer.");
						isValid = false;
					}
				} else if (type == RuleParameterDataType.OPTIONS) {
					if (ruleParams[i] == null || ruleParams[i].trim().length() == 0) {
						msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
								+ " must be a valid available option.", false));
						logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
								+ " must be a valid available option.");
						isValid = false;
					}
				} else if (type == RuleParameterDataType.PARAMETERREF) {
					if (ruleParams[i] == null
							|| ruleParams[i].trim().length() == 0
							|| !ruleParams[i]
									.startsWith(ParameterReferenceHelper.PROPERTY_REFERENCE_PREFIX)) {
						msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
								+ " must be a valid parameter reference. Use available drop down.",
								false));
						logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
								+ " must be a valid parameter reference.Use available drop down.");
						isValid = false;
					}
				} else if (type == RuleParameterDataType.TIME) {
					try {
						SimpleDateFormat timefomat = new SimpleDateFormat(
								JobUIConstants.JOB_RULE_TIME_FORMAT);
						timefomat.setLenient(false); // this is important!
						timefomat.parse(ruleParams[i]);
					} catch (ParseException e) {
						msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
								+ " should be a valid time in the correct format("
								+ JobUIConstants.JOB_RULE_TIME_FORMAT + ").", false));
						logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
								+ " should be a valid time in the correct format("
								+ JobUIConstants.JOB_RULE_TIME_FORMAT + ").");
						isValid = false;
					} catch (IllegalArgumentException e) {
						msgs.add(field.getKey(), new ActionMessage(ruleTypeParams.get(i).getName()
								+ " should be a valid time in the correct format("
								+ JobUIConstants.JOB_RULE_TIME_FORMAT + ").", false));
						logger.debug("Adding error message:" + ruleTypeParams.get(i).getName()
								+ " should be a valid time in the correct format("
								+ JobUIConstants.JOB_RULE_TIME_FORMAT + ").");
						isValid = false;
					}
				}
			}
		}
		return isValid;
	}

	/**
	 * @param string
	 * @return
	 */
	private static boolean isValidDay(String ruleDay) {
		Day day = Day.valueOf(ruleDay);
		if (day != null)
			return true;

		return false;
	}

	/**
	 * @param params
	 * @param paramValues
	 * @param paramNames
	 * @return
	 */
	private static List<JobParameterForm> prepareJobParameterForm(Collection<TaskVariable> params,
			String[] paramValues, String[] paramNames) {

		List<JobParameterForm> jobParameters = new ArrayList<JobParameterForm>();

		for (TaskVariable currVariable : params) {
			JobParameterForm jobParameter = new JobParameterForm();
			jobParameter.setName(currVariable.getMappedName());
			jobParameter.setRequired(currVariable.isRequired());
			jobParameter.setType(currVariable.getDatatype().toString());

			int index = getVariableIndex(currVariable.getMappedName(), paramNames);
			if (index != INVALID_INDEX) {
				jobParameter.setValue(paramValues[index]);
			} else {
				// the variable was not shown at job creation time
				jobParameter.setValue(null);
			}

			jobParameters.add(jobParameter);
		}
		return jobParameters;
	}

	/**
	 * @param variableName
	 *            variable name to be searched in the list provided
	 * @param list
	 *            the list in which the the name will be searched
	 * @return index in the list where the name is found in the list
	 */
	private static int getVariableIndex(String variableName, String[] list) {
		for (int i = 0; i < list.length; i++) {
			if (list[i].equalsIgnoreCase(variableName))
				return i;
		}
		return INVALID_INDEX;
	}

	/**
	 * this method goes thru the list of parameter names and checks the value for that. if its null
	 * then it builds an error message
	 * 
	 * @param params
	 * @param paramNames
	 * @param field
	 * @param msgs
	 * @param obj
	 * @return
	 */
	private static boolean validateRequiredSet(List<String> params, List<String> paramNames,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs,
			Object obj) {

		logger.debug("list of paramNmes: " + paramNames);
		logger.debug("list of params: " + params);

		boolean noErrors = true;
		for (int i = 0; i < paramNames.size(); i++) {

			if (params.get(i) != null && !params.get(i).trim().equals("")) {
			} else {
				msgs.add(field.getKey(), new ActionMessage(paramNames.get(i) + " is required.",
						false));
				logger.debug("Adding error message:" + paramNames.get(i) + " is required.");
				noErrors = false;
			}
		}
		return noErrors;
	}

	private static boolean validateDataTypeSet(List<JobParameterForm> paramList,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs) {
		boolean noErrors = true;
		for (JobParameterForm parameter : paramList) {
			noErrors = validateField(parameter, field, msgs) && noErrors;
		}

		return noErrors;
	}

	private static boolean validateField(JobParameterForm param,
			org.apache.commons.validator.Field field, org.apache.struts.action.ActionMessages msgs) {
		boolean isValid = true;
		if (param.getType() == null || param.getType().equals("")) {
			msgs.add(field.getKey(), new ActionMessage(param.getName()
					+ " does not have a datatype associated with it.", false));
			logger.debug("Adding error message:" + param.getName()
					+ " does not have a datatype associated with it.");
			isValid = false;
		} else if (param.getValue() == null || param.getValue().toString().equals("")
				|| param.getValue().startsWith(ParameterReferenceHelper.PROPERTY_REFERENCE_PREFIX)) {
			// return true if the value is a parameter reference or an empty string
			// an in-appropriate parameter reference will fail the work order eventually
			return isValid;
		} else if (param.getType().equalsIgnoreCase(Datatype.INT.toString())) {
			try {
				Integer.parseInt(param.getValue().toString());
			} catch (NumberFormatException ex) {
				msgs.add(field.getKey(), new ActionMessage(param.getName()
						+ " must be a valid integer.", false));
				logger.debug("Adding error message:" + param.getName()
						+ " must be a valid integer.");
				isValid = false;
			}
		} else if (param.getType().equalsIgnoreCase(Datatype.BOOLEAN.toString())) {
			if (!param.getValue().toString().equals("true")
					&& !param.getValue().toString().equals("false")) {
				msgs.add(field.getKey(), new ActionMessage(param.getName()
						+ " must be true or false.", false));
				logger.debug("Adding error message:" + param.getName() + " must be true or false.");
				isValid = false;
			}
		} else if (param.getType().equalsIgnoreCase(Datatype.DESTINATION.toString())) {
			if (!folderExists(param.getValue().toString())) {
				msgs.add(field.getKey(), new ActionMessage(param.getName() + " is incorrect. "
						+ param.getValue() + " is an invalid file or path.", false));
				logger.debug("Adding error message:" + param.getName() + " is incorrect. "
						+ param.getValue() + " is an invalid file or path.");
				isValid = false;
			}
		} else if (param.getType().equalsIgnoreCase(Datatype.DATE.toString())) {
			if (!isValidDate(param.getValue().toString(), JobUIConstants.JOB_PARAM_DATE_FORMAT)) {
				msgs.add(field.getKey(), new ActionMessage(param.getName()
						+ " should be a valid date in the correct format("
						+ JobUIConstants.JOB_PARAM_DATE_FORMAT + ").", false));
				logger.debug("Adding error message:" + param.getName()
						+ " should be a valid date in the correct format("
						+ JobUIConstants.JOB_PARAM_DATE_FORMAT + ").");
				isValid = false;
			}
		} else if (param.getType().equalsIgnoreCase(Datatype.DURATION.toString())) {
			if (!isValidDuration(param.getValue().toString())) {
				msgs.add(field.getKey(), new ActionMessage(param.getName()
						+ " is not in the correct format(" + durationFormat + ").", false));
				logger.debug("Adding error message:" + param.getName()
						+ " is not in the correct format(" + durationFormat + ").");
				isValid = false;
			}
		}

		return isValid;
	}

	private static String getDurationFormat() {
		return "HH:mm:ss";
	}

	private static boolean isValidDuration(String duration) {
		SimpleDateFormat format = new SimpleDateFormat(durationFormat);
		format.setLenient(false);
		try {
			format.parse(duration);
		} catch (ParseException e) {
			return false;
		}
		return true;
	}

	private static boolean isValidDate(String value, String format) {
		try {
			SimpleDateFormat df = new SimpleDateFormat(format);
			df.setLenient(false); // this is important!
			df.parse(value);
			// The API considers any extra chars after the expected format as valid input.
			// Hence performing this check to make sure the input contains no extra chars than the
			// format.
			if (value.trim().length() != format.length()) {
				return false;
			}
		} catch (ParseException e) {
			return false;
		} catch (IllegalArgumentException e) {
			return false;
		}

		return true;
	}

	private static boolean folderExists(String filePath) {
		File file = new File(filePath);
		File dir;
		if (filePath.length() > 2
				&& (filePath.substring(2).lastIndexOf("//") != -1 || filePath.substring(2)
						.lastIndexOf("\\\\") != -1))
			return false;
		if (file.getParent() == null)
			return false;
		dir = new File(file.getParent());
		return !file.isDirectory() && dir.isDirectory() && dir.exists() && dir.canRead();

	}

	/**
	 * checks if the timestamp represented by the date time provided is in the past.
	 * 
	 * @param date
	 * @param dateFormat
	 * @param time
	 * @param timeFormat
	 * @return true if the timestamp is the past. If there is any exception while parsing the date
	 *         or time, the return value is true indicating that the timestamp is in the past.
	 */
	private static boolean isDateTimeInPast(String date, String dateFormat, String time,
			String timeFormat) {
		try {
			Calendar cDate = Calendar.getInstance();
			SimpleDateFormat dateformat = new SimpleDateFormat(dateFormat);
			dateformat.setLenient(false);
			if (date.length() > 0) {
				Date jobDate = dateformat.parse(date);
				cDate.setTime(jobDate);
			} else {
				cDate.setTime(new Date());
			}

			SimpleDateFormat timefomat = new SimpleDateFormat(timeFormat);
			timefomat.setLenient(false);
			Date jobTime = timefomat.parse(time);
			Calendar cTime = Calendar.getInstance();
			cTime.setTime(jobTime);

			cDate.set(Calendar.AM_PM, cTime.get(Calendar.AM_PM));
			cDate.set(Calendar.HOUR_OF_DAY, cTime.get(Calendar.HOUR_OF_DAY));
			cDate.set(Calendar.MINUTE, cTime.get(Calendar.MINUTE));
			cDate.set(Calendar.SECOND, 0);

			Calendar cNow = Calendar.getInstance();
			cNow.setTime(new Date());
			return cDate.before(cNow);
		} catch (ParseException e) {
			String errorMsg = "Error while checking if dateTime is in future: " + e.getMessage()
					+ e.getStackTrace();
			logger.error(errorMsg);
			return true;
		}
	}
}
