package com.tandbergtv.metadatamanager.search;

import org.w3c.util.InvalidDateException;

import com.tandbergtv.watchpoint.search.Entity;
import com.tandbergtv.workflow.driver.search.RangeParameter;
import com.tandbergtv.workflow.driver.search.SearchOperator;
import com.tandbergtv.workflow.driver.search.SearchType;
import com.tandbergtv.workflow.driver.search.ValueParameter;

/**
 * @author vgoyal
 * 
 */
public class RangeFieldInfo extends FieldInfo {

	SearchOperator operator;	
	String rangeStart;
	String rangeEnd;
	
	
	/**
	 * For searching within a range, the Operator is fixed to IN
	 */
	public RangeFieldInfo() {
		super();
		this.operator = SearchOperator.IN;
		this.isConjunction = true;
	}

	/**
	 * 
	 * @param ttvxpath
	 * @param rangeStart
	 * @param rangeEnd
	 */
	public RangeFieldInfo(String ttvxpath, String rangeStart,
			String rangeEnd) {
		super();
		this.ttvxpath = ttvxpath;
		this.operator = SearchOperator.IN;
		this.rangeStart = rangeStart;
		this.rangeEnd = rangeEnd;
		this.isConjunction = true;
	}

	/**
	 * @param rangeStart
	 * @param rangeEnd
	 */
	public RangeFieldInfo(String ttvxpath, String rangeStart,
			String rangeEnd, boolean isConjunction) {
		super();
		this.ttvxpath = ttvxpath;
		this.operator = SearchOperator.IN;
		this.rangeStart = rangeStart;
		this.rangeEnd = rangeEnd;
		this.isConjunction = isConjunction;
	}

	/**
	 * @return the operator
	 */
	public SearchOperator getOperator() {
		return operator;
	}

	/**
	 * @return the rangeStart
	 */
	public String getRangeStart() {
		return rangeStart;
	}
	
	/**
	 * @param rangeStart the rangeStart to set
	 */
	public void setRangeStart(String rangeStart) {
		this.rangeStart = rangeStart;
	}
	
	/**
	 * @return the rangeEnd
	 */
	public String getRangeEnd() {
		return rangeEnd;
	}
	
	/**
	 * @param rangeEnd the rangeEnd to set
	 */
	public void setRangeEnd(String rangeEnd) {
		this.rangeEnd = rangeEnd;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void createEntity(String property, Entity assetEntity) {
		String valueColumnName = "";
		SearchType searchType = SearchType.STRING;

		Entity field = new Entity("field", property, "f");

		if(ttvxpath.contains("CustomField[@name")) {
			handleCustomFieldValueParameter(field);
			
			field.addParameter(new ValueParameter("ttvXPath",
					SearchType.STRING, ttvxpath, SearchOperator.EQUAL));			
		} else {
			field.addParameter(new ValueParameter("ttvXPath", SearchType.STRING, ttvxpath, SearchOperator.EQUAL));

			//find out the datatype for the xpath
			valueColumnName = getValueColumnName();
			searchType = getSearchTypeBasedOnColumn(valueColumnName);
			
			RangeParameter rangeParam = new RangeParameter(valueColumnName, searchType);
			rangeParam.setFrom(getRangeStart());
			rangeParam.setTo(getRangeEnd());
			
			field.addParameter(rangeParam);	
		}

		ValueParameter assetTypeParam = addAssetTypeCriteria();
		if(assetTypeParam != null) {
			field.addParameter(assetTypeParam);
		}

		assetEntity.addParameter(field, isConjunction());
	}
	
	/**
	 * This method is a piece of beauty. it jumps through so many hoops
	 * (if/else, try/catch) to try to find the datatype for the custom field
	 *
	 * REMOVE this method once we have the functionality to find the datatype
	 * for a customfield
	 * 
	 * @param field
	 */
	private void handleCustomFieldValueParameter(Entity field) {
		boolean isInt = true;
		boolean isFloat = true;
		boolean isDate = false;
		boolean isString = false;

		try {
			Integer.parseInt(getRangeStart());
			RangeParameter rangeParam = new RangeParameter("intValue", SearchType.NUMERIC);
			rangeParam.setFrom(getRangeStart());
			rangeParam.setTo(getRangeEnd());
			field.addParameter(rangeParam);
		} catch (NumberFormatException e) {
			isInt = false;
		}

		if (!isInt) {
			try {
				Float.parseFloat(getRangeStart());
				RangeParameter rangeParam = new RangeParameter("floatValue", SearchType.NUMERIC);
				rangeParam.setFrom(getRangeStart());
				rangeParam.setTo(getRangeEnd());
				field.addParameter(rangeParam);
			} catch (NumberFormatException e) {
				isFloat = false;
			}

			if (!isFloat) {
				try {
					org.w3c.util.DateParser.parse(getRangeStart());
					
					RangeParameter rangeParam = new RangeParameter("dateValue", SearchType.DATE);
					rangeParam.setFrom(getRangeStart());
					rangeParam.setTo(getRangeEnd());
					field.addParameter(rangeParam);
				} catch (NumberFormatException e) {
					isDate = false;
				} catch (InvalidDateException e) {
					isDate = false;
				}

				if (!isDate) {
					// its a string!!
					RangeParameter rangeParam = new RangeParameter("value", SearchType.STRING);
					rangeParam.setFrom(getRangeStart());
					rangeParam.setTo(getRangeEnd());
					field.addParameter(rangeParam);
					isString = true;
				}
			}
		}
		// this check is to make sure we also check the value column. this is
		// needed coz a user might define a custom field as a string in spec
		// view but then enter a date value in the data. that will be stored in
		// the value column and not in date column
		if (!isString) {
			RangeParameter rangeParam = new RangeParameter("value", SearchType.STRING);
			rangeParam.setFrom(getRangeStart());
			rangeParam.setTo(getRangeEnd());
			field.addParameter(rangeParam, false);
		}
	}

}
