package industries.doublehelix.conditionalfilter.filtertypes;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * A Filter
 * @author klaue
 *
 */
public abstract class Filter implements Serializable, Cloneable {
	private static final long serialVersionUID = 1L;
	protected String filterName = "";
	protected String filterRawName = "";
	
	protected Filter(String filterName, String filterRawName) {
		this.filterName = filterName;
		this.filterRawName = filterRawName;
	}
	
	protected Filter(String filterName) {
		this.filterName = filterName;
		this.filterRawName = null;
	}
	
	/**
	 * Get the common (user friendly) name attached to this filter
	 * @return field name
	 */
	public String getFieldName() {
		return filterName;
	}
	
	/**
	 * Set the common (user friendly) name attached to this filter
	 * @param fieldName
	 */
	public void setFieldName(String fieldName) {
		this.filterName = fieldName;
	}
	
	/**
	 * Get the raw (sql friendly) name attached to this filter
	 * @return the raw filter name
	 */
	public String getFieldRawName() {
		return filterRawName;
	}
	
	/**
	 * Set the raw (sql friendly) name attached to this filter
	 * @param fieldRawName
	 */
	public void setFieldRawName(String fieldRawName) {
		this.filterRawName = fieldRawName;
	}
	

	/**
	 * get the where part for a prepared statement to select items that conform to the filter.
	 * use like
	 * "Select * where " + getPreparedStatementWhereString()
	 * @return the where
	 */
	public abstract String getPreparedStatementWhereString();
	

	/**
	 * get the filter as represented by the 'where'-part of an SQL query
	 * "Select * where " + getSqlWhere()
	 * Compare with getPreparedStatementWhereString() and addPreparedStatementValues()
	 * @return the where
	 */
	public abstract String getSqlWhere();
	
	/**
	 * Add the values to the prepared statement made with getPreparedStatementWhereString()
	 * @param ps the prepared statement built with the other function
	 * @param currentIndex the current index for adding values (1 if this is the first one) 
	 * @return the new index
	 * @throws SQLException 
	 */
	public abstract int addPreparedStatementValues(PreparedStatement ps, int currentIndex) throws SQLException;
	
	/**
	 * Chcks if this filter has anything save for the name, raw name and possibly type set
	 * @return false if any filter value was set
	 */
	public abstract boolean isEmpty();
	
	/**
	 * Add the values to the prepared statement made with getPreparedStatementWhereString()
	 * @param ps the prepared statement built with the other function
	 * @return the new index
	 * @throws SQLException 
	 */
	public int addPreparedStatementValues(PreparedStatement ps) throws SQLException {
		return addPreparedStatementValues(ps, 1);
	}
	
	/**
	 * Returns the real filter name depending of raw filter and normal filter names were set
	 * @param forSql true to prioritize raw filter name for use in sql, false to prioritize common name for use in GUI etc
	 * @return the filter name or "unnamed" (for sql) or "Unnamed Filter" (not for sql)
	 */
	public String getRealFilterField(boolean forSql) {
		if (forSql) {
			return this.filterRawName == null ? (this.filterName == null ? "unnamed" : this.filterName) : this.filterRawName;
		} else {
			return this.filterName == null ? (this.filterRawName == null ? "Unnamed Filter" : this.filterRawName) : this.filterName;
		}
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj == null) return false;
		if (obj == this) return true;
		
		// instanceof tests for subtypes as well, but we want the same bottom-most type
		if (!(obj.getClass() != this.getClass())) return false;
		
		// all filters implement toString(), so we can just compare those
		return obj.toString().equals(this.toString());
	}
	
	public Object clone(){  
	    try{  
	        return super.clone();  
	    }catch(Exception e){ 
	    	e.printStackTrace();
	        return null; 
	    }
	}
}
