package com.tandbergtv.watchpoint.pmm.web.validators;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.validator.Field;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

import com.tandbergtv.watchpoint.pmm.web.title.TitleListForm;
import com.tandbergtv.watchpoint.pmm.web.title.TitleSearchType;
import com.tandbergtv.watchpoint.pmm.web.title.search.TitleSearchPageBuilder;
import com.tandbergtv.workflow.driver.search.SearchType;
import com.tandbergtv.workflow.web.page.Page;

/**
 * Validates the TitleForm object used in Create & Edit Title pages
 * 
 * @author Raj Prakash
 */
public class TitleValidator {

	/* Logger */
	private static Logger logger = Logger.getLogger(TitleValidator.class);

	/* The Message Key for invalid integer value */
	private static final String KEY_INVALID_INTEGER_VALUE = "error.title.search.invalidIntegerValue";

	/* The Message Key for invalid date value */
	private static final String KEY_INVALID_DATE_VALUE = "error.title.search.invalidDateValue";

	/* The Message Key for invalid date range values */
	private static final String KEY_INVALID_DATE_RANGE_VALUES = "error.title.search.invalidDateRangeValues";
	
	/**
	 * Validate all the fields submitted by the Title Search Page.
	 * 
	 * @param form
	 * @param action
	 * @param field
	 * @param messages
	 * @param validator
	 * @param request
	 * @return
	 */
	public boolean validateSearch(Object form, ValidatorAction action, Field field,
			ActionMessages messages, Validator validator, HttpServletRequest request) {
		boolean result = true;

		/* Only validate the 'search' method */
		String method = request.getParameter("method");
		if (!("search".equals(method))) {
			return result;
		}

		/* The form is dynamic, validate all the dynamic fields based on the search page */
		TitleListForm titleForm = (TitleListForm) form;
		String specification = titleForm.getSpecification();
		TitleSearchType searchType = titleForm.getSearchType();
		Page searchPage = null;
		try {
			TitleSearchPageBuilder builder = TitleSearchPageBuilder.newInstance();
			searchPage = builder.buildSearchPage(searchType, specification);
		} catch (Exception e) {
			logger.error("Failed to build the Title Search Page for specification: "
					+ specification + " for search type: " + searchType, e);

			ActionMessage msg = new ActionMessage("The Title Search Page is invalid.", false);
			messages.add("TitleSearch", msg);
			return false;
		}

		/* Validate each of the search fields */
		Collection<com.tandbergtv.workflow.web.page.Field> fields = searchPage.getFields();
		String fieldKey = field.getKey();
		for (com.tandbergtv.workflow.web.page.Field searchField : fields) {
			result &= validateSearchField(searchField, fieldKey, titleForm, messages, request);
		}
		return result;
	}

	/* Validate the Search Page based on the data types specified for each of the fields */
	private static boolean validateSearchField(com.tandbergtv.workflow.web.page.Field searchField,
			String key, TitleListForm titleForm, ActionMessages messages, HttpServletRequest request) {
		boolean result = true;

		/* Check if there are values to validate */
		String[] values = request.getParameterValues(searchField.getName());
		if (values == null || values.length == 0)
			return true;

		/* Validate based on the search type */
		String label = searchField.getLabel();
		SearchType searchType = searchField.getSearchType();
		for (String value : values) {
			if (searchType == SearchType.DATE || searchField.getIsDateRange()) {
				result &= validateDateField(key, label, value, messages);
			} else if (searchType == SearchType.NUMERIC) {
				result &= validateNumberField(key, label, value, messages);
			}

			/* If any value is not valid, don't repeat validation for other values */
			if (!result)
				break;
		}

		/* Validate the date range, if values are valid */
		if (result)
			result &= validateDateRangeField(key, label, values, messages);

		return result;
	}

	/* Validate that all the values are date values, if specified */
	private static boolean validateDateField(String key, String label, String value,
			ActionMessages messages) {
		boolean result = true;

		if (value != null && value.trim().length() > 0) {
			try {
				result = ValidatorUtil.isValidDate(value.trim());
			} catch (Exception e) {
				result = false;
			}
		}

		if (!result) {
			ActionMessage message = new ActionMessage(KEY_INVALID_DATE_VALUE, label);
			messages.add(key, message);
		}

		return result;
	}

	/* Validate if the start date is before the end date in the date range */
	private static boolean validateDateRangeField(String key, String label, String[] values,
			ActionMessages messages) {
		boolean result = true;

		if (values == null || values.length < 2) {
			return result;
		}

		String start = values[0];
		String end = values[1];
		try {
			DateFormat format = new SimpleDateFormat(ValidatorUtil.getDatePattern());
			if (!isBlank(start) && !isBlank(end)) {
				Date startDate = format.parse(start);
				Date endDate = format.parse(end);
				result = (startDate.getTime() <= endDate.getTime());
			}
		} catch (Exception e) {
		}

		if (!result) {
			ActionMessage message = new ActionMessage(KEY_INVALID_DATE_RANGE_VALUES, label);
			messages.add(key, message);
		}

		return result;
	}

	/* Validate that all the values are integer values, if specified */
	private static boolean validateNumberField(String key, String label, String value,
			ActionMessages messages) {
		boolean result = true;

		if (value != null && value.trim().length() > 0) {
			try {
				Long.parseLong(value.trim());
			} catch (Exception e) {
				String msgKey = KEY_INVALID_INTEGER_VALUE;
				ActionMessage message = new ActionMessage(msgKey, label);
				messages.add(key, message);
				result = false;
			}
		}

		return result;
	}

	/* Checks if the value is blank */
	private static boolean isBlank(String value) {
		return (value == null || value.trim().length() == 0);
	}
}
