<?
/**
*
* MYSQL FILTER
*
*
* in controller
* $filter = $this->Filter->setFilter(array('name', 'parent_name', 'between' => 'url', 'class', 'is_enabled'));
* column types are: string (default LIKE '%string%'), string_before (LIKE 'string%'), string_after (LIKE '%string'), int (= int), date (= 'date'), between (BETWEEN 'param1' AND 'param2')
*
* in view
* $filter = $this->Filter;
* $filter->is_enabled(array('type="radio"', 'value="1"', 'text=JA')); - add element1 to same filter
* $filter->is_enabled(array('type="radio"', 'value="0"', 'text=EI')); - add element2 to same filter
* $filter->parent_name(array('multiple=multiple'), 'select'); - create select element
* $filter->option('parent_name', '1', 'Yes'); - set option to element
* $filter->option('parent_name', '0', 'No', true); - set option to element
* $filter->option('parent_name', '2', 'AHHaa'); - set option to element
* $filter->option('parent_name', '3', 'MEee', true); - set option to element
* $filter->create(); - create whole filter
*/
class Filter{

	/**
	* set filtered columns
	* @param Array $array
	*/
	function setFilter($array){

		$this->elemList = $array;

		foreach($array as $k => $v){

			$this->elementType[str_replace('.', '-', $v)] = $k;
			$function = str_replace('.', '_', $v);
			$this->$function = create_function('','');
			$this->createImages($v);
		}

		if($_GET['filter'])
			return $this->filterData($_GET, $array);
	}

	/**
	* create filter images to table th elements
	*/
	function create(){

		$elemList = '';

		foreach($this->elemList as $elem){

			$elemList .= '<div class="filter-div-'.$this->getName($elem).'" style="display:none;">';
			if( is_array($this->element[$elem]) ){

				foreach($this->element[$elem] as $k => $e){

					$elemList .= $this->createElem($elem, $e['element'], $e['attr'], $k);
				}
			}
			else{

				$elemList .= $this->createElem($elem, $this->element[$elem]['element'], $this->element[$elem]['attr'], 0);
			}
			$elemList .= '</div>';
		}
		$model = $_GET['model'] ? $_GET['model'] : 'unnamed';
		$page = $_GET['page'] ? $_GET['page'] : 'unnamed';
		echo "\n".'<script type="text/javascript">imageList["list"] = "'. (is_Array($this->images) ? implode(',', $this->images) : '') .'";imageList["selected"] = "'. (is_array($this->imagesSelected) ? implode(',', $this->imagesSelected) : '') .'";</script>'."\n";
		echo $elemList;

		unset($this->elemList);
		unset($this->element);
		unset($this->images);
		unset($this->imagesSelected);
		unset($this->elementType);
		unset($this->optionSelected);
		unset($this->optionList);
	}

	/**
	* if filter element is select then set options tag
	* @param String $name AS select name
	* @param String $key AS option value
	* @param String $value AS option html value
	* @param Boolean $selected = false AS if option is selected
	*/
	function option($name, $key, $value, $selected = false){

		$name = $this->getName($name);

		if($selected)
			$this->optionSelected[$name][$key] = $selected;
		$this->optionList[$name] .= '<option value="'.$key.'" {selected='.$key.'}>'.$value.'</option>';
	}

	private function createImages($name){

		$name = $this->getName($name);

		if($_GET[$name])
			$this->imagesSelected[] = $name;
		else
			$this->images[] = $name;
	}

	private function setParams($elemName, $args, $elemType){

		if( !in_array($elemName, $this->elemList) ){

			$exp = explode('_', $elemName);
			$first = $exp[0];
			unset($exp[0]);
			$testElemName = $first.'-'.implode($exp, '_');
			if( in_array($testElemName, $this->elemList) )
				$elemName = $testElemName;
		}

		$this->element[$elemName][] = array('attr' => $args, 'element' => $elemType);
	}

	private function createElem($name, $element, $attr, $i){

		$return = '';
		$name = $this->getName($name);
		$type = 'text';
		$value = $_GET[$name];
		$text = '';
		$checked = '';
		$attrList = '';
		$float = 'none';
		$marginBottom = 0;

		if(is_array($attr)){

			foreach($attr as $k => $v){

				list($attrType, $attrValue) = explode('=', $v);
				$attrValue = preg_replace('/\"(.*?)\"/s', '\1', $attrValue);
				if($attrType == 'type')
					$type = $attrValue;
				else if($attrType == 'value')
					$value = $attrValue;
				else if($attrType == 'text')
					$text = ' '.$attrValue;
				else
					$attrList .= $attrType.'="'.$attrValue.'"'; 
			}
		}
		if($this->optionList[$name]){

			$value = $this->optionList[$name];
			$defaultSelection = $this->optionSelected[$name];
			if($_GET[$name]){

				if( is_array(json_decode($_GET[$name])) ){

					foreach(json_decode($_GET[$name]) as $v){

						$optionSelected[$name][$v] = true;
					}
				}
				else{

					$optionSelected[$name][$_GET[$name]] = true;
				}
			}
			if(is_array($optionSelected[$name])){

				foreach($optionSelected[$name] as $k => $v){

					$value = str_replace('{selected='.$k.'}', 'selected="selected"', $value);
				}
			}
			else{

				foreach($defaultSelection as $k => $v){

					$value = str_replace('{selected='.$k.'}', 'selected="selected"', $value);
				}
			}
			$value = preg_replace('/([[:space:]_]+)\{selected=([a-zA-Z0-9[:space:]_]+)\}/s', '', $value);
		}

		switch($element){

			case 'input':
				if( $this->elementType[$name] === 'between' ){

					$return = '<input type="{type}" name="'.$name.'[min]" value="'.$_GET[$name]['min'].'" {attr}/><div style="width:155px;height:10px;"></div><input type="{type}" name="'.$name.'[max]" value="'.$_GET[$name]['max'].'" {attr}/>';
					$marginBottom = 5;
				}
				else{

					$return = '<input type="{type}" name="'.$name.'" value="{value}" {attr}/> {text}';
				}

				if($type == 'text' && $this->elementType[$name] != 'between')
					$float = 'left';
				else
					$marginBottom = 5;

				$attrList .= $this->setAttribute($name, $value, $type);
			break;

			case 'textarea':
				$return = '<textarea name="'.$name.'" {attr}>'.$_GET[$name].'</textarea>';
			break;

			case 'select':
				$return = '<select name="'.$name.'" {attr}>{value}</select>';
				$float = 'left';
			break;

			default:
				if( $this->elementType[$name] === 'between' ){
				
					$return = '<input type="{type}" name="'.$name.'[min]" value="'.$_GET[$name]['min'].'" {attr}/><div style="width:155px;height:10px;"></div><input type="{type}" name="'.$name.'[max]" value="'.$_GET[$name]['max'].'" {attr}/>';
					$marginBottom = 5;
				}
				else{

					$return = '<input type="{type}" name="'.$name.'" value="{value}" {attr}/> {text}';
					$float = 'left';
				}

				$attrList .= $this->setAttribute($name, $value, $type);
			break;
		}
		if(!is_array($_GET[$name]) && $_GET[$name] && ($type == 'text' || $element == 'textarea'))
			if(!is_array(json_decode($_GET[$name])))
				$value = $_GET[$name];

		$return = str_replace('{type}', $type, $return);
		$return = str_replace('{value}', $value, $return);
		$return = str_replace(' {attr}', $attrList, $return);
		$return = str_replace(' {text}', $text, $return);

		return '<div style="display:block;float:'.$float.';margin-bottom:'.$marginBottom.'px;" class="filter-input">'.$return.'</div>';
	}

	private function getName($name){

		return str_replace('.', '-', $name);
	}

	private function setAttribute($name, $value, $type){

		$attr = '';
		$name = $this->getName($name);

		if( is_array($_GET[$name]) ){

			if(in_array($value, $_GET[$name]) && ($type == 'checkbox' || $type == 'radio'))
				$attr = ' checked="checked"';
		}
		else if( is_array(json_decode($_GET[$name])) ){

			if(in_array($value, json_decode($_GET[$name])) && ($type == 'checkbox' || $type == 'radio'))
				$attr = ' checked="checked"';
		}
		else{

			if($value == $_GET[$name] && ($type == 'checkbox' || $type == 'radio'))
				$attr = ' checked="checked"';
		}
		return $attr;
	}

	private function filterData($dataArray, $filterArray){

		//print '<pre>';
		//print_r ($dataArray);

		$filter = '';
		if($filterArray){

			foreach($filterArray as $k => $v){

				$type = !is_numeric($k) ? $k : 'string';
				$column = $v;
				$value = $dataArray[str_replace('.', '-', $column)];
				$filter .= $this->setFilterValue($column, $value, $type, $filter);
			}
		}
		return $filter;
	}

	private function setFilterValue($column, $value, $type, $filter){

		if( !is_array($value) && is_array(json_decode($value)) )
			$value = json_decode($value);
		if( is_array($value) && (!$value['min'] || !$value['max']) ){

			$value = implode(',', $value);
			$type = 'int';
		}

		if( $type == 'string' && isset($value) ){

			$return = $filter ? " OR `".$column."` LIKE '%".$value."%' " : " `".$column."` LIKE '%".$value."%' ";
		}
		if( $type == 'string_before' && isset($value) ){

			$return = $filter ? " OR `".$column."` LIKE '".$value."%' " : " `".$column."` LIKE '".$value."%' ";
		}
		if( $type == 'string_after' && isset($value) ){

			$return = $filter ? " OR `".$column."` LIKE '%".$value."' " : " `".$column."` LIKE '%".$value."' ";
		}
		if( $type == 'int' && isset($value) ){

			$return = $filter ? " AND `".$column."` IN(".$value.") " : " `".$column."` IN(".$value.") ";
		}
		if( $type == 'date' && isset($value) ){

			$return = $filter ? " AND ".$column." = '".$value."'" : "".$column." = '".$value."'";
		}

		if( $type == 'between' && isset($value) ){

			$min = is_array($value) ? $value['min'] : '';
			$max = is_array($value) ? $value['max'] : '';

			if( $min && $max ){

				$return = $filter ? " AND ".$column." BETWEEN '".$min."' AND '".$max."'" : " ".$column." BETWEEN '".$min."' AND '".$max."'";
			}
			else if( $min ){

				$return = $filter ? " AND ".$column." >= ".$min." " : " ".$column." >= ".$min." ";
			}
			else if( $max ){

				$return = $filter ? " AND ".$column." <= ".$max." " : " ".$column." <= ".$max." ";
			}
			else{

				$return = $filter ? " AND ".$column." BETWEEN '".$value."' AND '".$value."'" : " ".$column." BETWEEN '".$value."' AND '".$value."'";
			}
		}
		return $return;
	}

	/**
	* automated call of element
	* @example $this->elementName(array('type=checkbox'))
	*/
	public function __call($method, $args){

		if(property_exists($this, $method)){

			if(is_callable($this->$method)){

				if(!$args[1]){

					$this->setParams($method, $args[0], 'input');
				}
				else{
					
					$this->setParams($method, $args[0], $args[1]);
				}
			}
		}
	}
}

?>