<?

/**
* EXAMPLE 1 - HEADLIST
* $form = $this->Form;
* $columns = array('name', 'parent_id', 'url', 'is_enabled', 'insert' => '');//if key is number then column value will be value else column value will be key, but in trHeaderList() <th> element html value is array value
* $form->input($columns);//create default <input> from column names
*
* //option list will be created once for increasing performance
* $form->option('parent_id', 0, 'none');//set <option> for <select> elem
* while($row = $this->main_menus->Assoc()){
*
*	$form->option('parent_id', $row['id'], $row['name']);
*	$form->option('parent_name', $row['id'], $row['name']);
* }
*
* $form->select('parent_id');//create <select> elem
*
* $form->is_enabled(array('type=checkbox', 'value=1', 'checked=checked'));//set attributes for is_enabled <input>
* $form->parent_id(array('value='.$option));//set value for parent_id <select> elem
* $form->insert(array('type=submit', 'value='.$this->Language('Insert')));//set attributes for insert <input>
*
* $form->trHeaderList($columns, array('name' => 'http://', 'url' => 'some'));//create <tr> list with <th> and <td>
*
*
* EXAMPLE 2 - LIST WITH HEADCOLUMNROW
* $columns = array('name', 'parent_name', 'url', 'is_enabled', 'update_admin_menu,cancel' => '');
* $form->trHeader($columns);//create header <tr> with <th>
* while($row = $this->menus->Assoc()){
*
*	if($_GET['action'] == 'edit' && $_GET['id'] == $row['id']){
*
*		$form->input($columns);//create default <input> from column names
*		$form->select('parent_name')->selected('parent_name', $row['parent_id']);//create <select> elem
*		$form->a('cancel');//create cancel <a> elem
*
*		$form->name()->after('some')->before('some2');//append or prepend text to current elem
*		$form->is_enabled(array('type=checkbox', 'value=1', ($row['is_enabled'] == 1 ? 'checked="checked"' : '')));
*		$form->update_admin_menu(array('type=submit', 'value='.$this->Language('Update')));//create update <input>
*		$form->cancel(array('href='.$this->Link(), 'value='.$this->Language('Cancel')));//create cancel <a>
*
*		$form->tr($columns, $row, array('tr' => 'id="some"', 'td' => 'class="jaja"', 'td(0)' => 'class="eiei"'));//create <tr> with <td>
*	}
*	else{
*
*		$form->a('name');//it will create <a> element
*		$form->name(array('href='.$this->Link('?action=edit&id='.$row['id'])));
*		$form->exception('is_enabled', array(0 => $this->Language('no'), 1 => $this->Language('yes')));
*		$form->tr($columns, $row);
*	}
* }
*/
class Form extends engine{
	/**
	* what fields is required
	* @param Array $columnsArray AS Array('column' => array('before' => 'text' OR 'after' => 'text' ))
	*/
	function required($columnsArray){

		if(is_array($columnsArray)){

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

				$key = is_array($v) ? $k : $v;
				$required_txt = is_array($v) ? $v : $columnsArray[count($columnsArray)-1];
				$array[$key] = is_array($required_txt) ? $required_txt : array('after' => $required_txt);
			}
			$this->required = $array;
		}
	}

	/**
	* tr header data
	* @param Array $columns AS columns arraylist
	* @param Array $attr = array() AS arraylist
	* @example $form->trHeader(array('name'), array('tr' => 'class=name', 'th' => 'class=name', 'th(0)' => 'class=second'));
	*/
	function trHeader($columns, $attr = array()){

		$columns = $this->setList($columns);

		echo '<tr'.$this->tableChildAttributes('tr', $attr).'>';

		$col = 0;
		foreach($columns as $k => $v){

			$key = is_numeric($k) ? $v : $k;
			$value = isset($v) ? $v : $k;
			$tdAttr = $this->tableChildAttributes('th('.$col.')', $attr, $key);
			if( !$tdAttr )
				$tdAttr = $this->tableChildAttributes('th', $attr, $key);

			echo '<th'.$tdAttr.'>'.$this->Language($value).'</th>';
			$col ++;
		}
		echo '</tr>';

		$this->unsetData();
	}

	/**
	* create <tr> list
	* @param Array $columns AS columnlist
	* @param Array $row = array() AS datalist
	* @param Array $attr = array() AS attrlist
	* @example $form->tr(array('name'), $row, array('tr' => 'class=name', 'td' => 'class=name', 'td(0)' => 'class=second'));
	*/
	function tr($columns, $row = array(), $attr = array()){

		$columns = $this->setList($columns);

		echo '<tr'.$this->tableChildAttributes('tr', $attr).'>';

		$col = 0;
		foreach($columns as $k => $v){

			$key = is_numeric($k) ? $v : $k;
			$exp = explode(',', $key);
			$data = '';
			$this->setOptionsToSelect($key);

			foreach($exp as $key){

				if( $this->elemList[$key] && $row[$key] && !$this->elemAttributes[$key]['value'] )
					$this->elemAttributes[$key]['value'] = $this->value($key, $row[$key]);
				$data .= $this->elemList[$key] ? $this->compile($key, $this->elemList[$key]) : $this->value($key, $row[$key]);
			}
			$tdAttr = $this->tableChildAttributes('td('.$col.')', $attr, $key);
			if( !$tdAttr )
				$tdAttr = $this->tableChildAttributes('td', $attr, $key);
			echo '<td'.$tdAttr.'>'.$data.'</td>';
			$col ++;
		}
		echo '</tr>';

		$this->unsetData();
	}

	/**
	* vertical tr data
	* @param Array $columns AS columnlist
	* @param Array $row = array() AS datalist
	* @param Array $attr = array() AS attrlist
	* $attr = array('tr' => 'id="1"'); - all tr
	* $attr = array('tr(0)' => 'id="1"'); - current tr
	* $attr = array('th' => 'id="1"'); - all th
	* $attr = array('tr(0)th(0)' => 'id="1"'); - current row th
	* $attr = array('td' => 'id="1"'); - all td
	* $attr = array('tr(0)td(0)' => 'id="1"'); - current row td
	* 
	* @example $form->trHeader(array('name'), array('tr' => 'class=name', 'th' => 'class=name', 'th(0)' => 'class=second'));
	*/
	function trHeaderList($columns, $row = array(), $attr = array()){

		$this->setToHidden();
		$columns = $this->setList($columns);

		$col = 0;
		foreach($columns as $k => $v){

			$key = is_numeric($k) ? $v : $k;
			$exp = explode(',', $key);
			$data = '';

			foreach($exp as $key){

				$value = isset($v) ? $v : $k;
				if( $this->elemList[$key] && $row[$key] && !$this->elemAttributes[$key]['value'] )
					$this->elemAttributes[$key]['value'] = $this->value($key, $row[$key]);

				if($this->isHidden[$key]){

					$this->elemList[$key.'_old'] = $this->elemList[$key];
					$this->elemAttributes[$key.'_old'] = $this->elemAttributes[$key];
					$this->elemAttributes[$key.'_old']['type'] = 'hidden';

					$data .= '<div style="display:none;">'.
						'<p style="display:table-cell;height:20px;vertical-align:middle;">'.$this->compile($key, $this->elemList[$key]).'</p>'.
						'<p style="display:table-cell;height:20px;padding-left:3px;padding-top:1px;">'.$this->compile($key.'_old', $this->elemList[$key.'_old']).'<img src="'._HostTemplate.'/images/admin/close_enabled.png" class="can_edit_close"/></p>'.
						'</div>'.
						'<span>'.$this->value($key, $row[$key]).'</span>';
					$attr['tr('.$col.')td(0)'] = 'class="can_edit"';
				}
				else{

					$data .= $this->elemList[$key] ? $this->compile($key, $this->elemList[$key]) : $this->value($key, $row[$key]);
				}
			}

			$tdAttrTR = $this->tableChildAttributes('tr('.$col.')', $attr, $key);
			if( !$tdAttrTR )
				$tdAttrTR = $this->tableChildAttributes('tr', $attr, $key);

			$tdAttrTH = $this->tableChildAttributes('tr('.$col.')th(0)', $attr, $key);
			if( !$tdAttrTH )
				$tdAttrTH = $this->tableChildAttributes('th', $attr, $key);

			$tdAttrTD = $this->tableChildAttributes('tr('.$col.')td(0)', $attr, $key);
			if( !$tdAttrTD )
				$tdAttrTD = $this->tableChildAttributes('td', $attr, $key);

			echo '<tr'.$tdAttrTR.'>
				<th'.$tdAttrTH.'>'.'<span style="color:red;">'.$this->required[$key]['before'].'</span>'.$this->Language($value).'<span style="color:red;">'.$this->required[$key]['after'].'</span>'.'</th>
				<td'.$tdAttrTD.'>'.preg_replace('/""(.*?)""/s', '"\1"', $data).'</td>
			</tr>';
			$col ++;
		}

		$this->unsetData();
	}

	/**
	* create input elements
	* @param Array,String $list
	*/
	function input($list){

		$list = $this->setList($list);

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

			$name = is_numeric($k) ? $v : $k;
			$exp = explode(',', $name);

			foreach($exp as $name){

				if($name){

					$elemList[$name] = '<input type="{type}" name="{name}" value="{value}" {attr}/>';
					$this->$name = create_function('','');
				}
			}
		}
		$this->appendElem($elemList);
	}

	/**
	* create <select> element
	* @param Array,String $list
	*/
	function select($list){

		$list = $this->setList($list);

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

			$name = is_numeric($k) ? $v : $k;
			$exp = explode(',', $name);

			foreach($exp as $name){

				$elemList[$name] = '<select name="{name}" {attr}>{value}</select>';
				$this->$name = create_function('','');
			}
		}
		$this->appendElem($elemList);
		return $this;
	}

	/**
	* create option list for select element
	* @param String $name AS select element name
	* @param String $key AS option value
	* @param String $value AS option html value
	*/
	function option($name, $key, $value){

		$this->optionList[$name] .= '<option value="'.$key.'" {selected='.$key.'} {attr_option}>'.$value.'</option>';
		$option = $name.'_option';
		$this->$option = create_function('','');
	}

	/**
	* what option is selected
	* @param Array $list AS array('name')
	* @param String $selected = '' AS $row['id'] (option value)
	*/
	function selected($list, $selected = ''){

		if( !is_array($list) && !$selected ){

			$name = $this->latestElement;
			$list = array($name => $list);
		}
		elseif( !is_array($list) ){

			$name = $list;
			$list = array($name => $selected);
		}

		foreach($list as $name => $selected){

			//$this->elemAttributes[$name]['value'] = str_replace('{selected='.$selected.'}', 'selected="selected"', $this->elemAttributes[$name]['value']);
			$this->elemAttributes[$name]['selected'][$selected] = true;
		}
	}

	/**
	* create textarea element
	* @param Array,String $list 
	*/
	function textarea($list){

		$list = $this->setList($list);

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

			$name = is_numeric($k) ? $v : $k;
			$exp = explode(',', $name);

			foreach($exp as $name){

				$elemList[$name] = '<textarea name="{name}" {attr}>{value}</textarea>';
				$this->$name = create_function('','');
			}
		}
		$this->appendElem($elemList);
	}

	/**
	* create <a> element
	* @param Array,String $list 
	*/
	function a($list){

		$list = $this->setList($list);

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

			$name = is_numeric($k) ? $v : $k;
			$exp = explode(',', $name);

			foreach($exp as $name){

				$elemList[$name] = '<a href="{href}" {attr}>{value}</a>';
				$this->$name = create_function('','');
			}
		}
		$this->appendElem($elemList);
	}

	/**
	* create simple text element
	* @param Array,String $list 
	*/
	function text($list){

		$list = $this->setList($list);

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

			$name = is_numeric($k) ? $v : $k;
			$exp = explode(',', $name);

			foreach($exp as $name){

				$elemList[$name] = '{value}';
				$this->$name = create_function('','');
			}
		}
		$this->appendElem($elemList);
	}

	/**
	* remove element from list
	* @param Array,String $list 
	*/
	function remove($list){

		$list = $this->setList($list);
		foreach($list as $k => $v){

			$name = is_numeric($k) ? $v : $k;
			$exp = explode(',', $name);

			foreach($exp as $name){

				unset($this->elemList[$name]);
			}
		}
	}

	/**
	* make exeption for data to show
	* @param String $name AS data column name
	* @param Array $exception AS array(0 => 'No', 1 => 'Yes') - if $row['is_parent'] value = 0 then it shows "No"
	*/
	function exception($name, $exception){

		$this->exception[$name] = $exception;
	}

	/**
	* add html after to the element
	* @param String $html
	*/
	function after($html){

		$this->after[$this->latestElement] = $html;
		return $this;
	}

	/**
	* add html before to the element
	* @param String $html
	*/
	function before($html){

		$this->before[$this->latestElement] = $html;
		return $this;
	}

	/**
	* shows error label
	* @param Array $error AS $this->error object
	*/
	function errorLabel($error){

		$elem = '';
		$list = array();

		if( !is_array($error) )
			$error = array($error);

		if(is_array($error)){

			echo '<div class="errorContainer">';

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

				$elem .= $elem ? ',[name='.str_replace(' ', '_', $k).']' : '[name='.str_replace(' ', '_', $k).']';
				if($v && !in_array($v, $list))
					echo '<span class="errorMessage">'.$v.'</span>';

				$list[] = $v;
			}
			echo '</div>';
			echo '<div style="clear:both;"></div>';
			if($elem)
				echo '<script type="text/javascript">$(document).ready(function(){$("'.$elem.'").addClass("errorLabel");});</script>';
		}
	}

	/**
	* show message label
	* @param Array $message AS $this->message object
	*/
	function messageLabel($message){

		$elem = '';
		$list = array();
		if( !is_array($message) )
			$message = array($message);

		if(is_array($message)){

			echo '<div class="messageContainer">';

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

				$elem .= $elem ? ',[name='.str_replace(' ', '_', $k).']' : '[name='.str_replace(' ', '_', $k).']';
				if($v && !in_array($v, $list))
					echo '<span class="messageMessage">'.$v.'</span>';

				$list[] = $v;
			}
			echo '</div>';
			echo '<div style="clear:both;"></div>';
			if($elem)
				echo '<script type="text/javascript">$(document).ready(function(){$("'.$elem.'").addClass("messageLabel");});</script>';
		}
	}

	/**
	* is element hidden, then will show $row['column'] value and after hidden label click shows up element
	* @param Array $isHidden AS arraylist
	*/
	function isHidden($isHidden){

		$this->isHidden = $isHidden;
	}

	private function setOptionsToSelect($name){

		if($this->optionList[$name])
			$this->elemAttributes[$name]['value'] = $this->optionList[$name];
		if($this->elemAttributes[$name]['selected']){

			foreach($this->elemAttributes[$name]['selected'] as $k => $v){

				$this->elemAttributes[$name]['value'] = str_replace('{selected='.$k.'}', 'selected="selected"', $this->elemAttributes[$name]['value']);
			}
		}
	}

	private function setToHidden(){

		$tmp = $this->isHidden;
		if(is_array($tmp)){

			foreach($tmp as $v){

				$this->isHidden[$v] = $v;
			}
		}
	}

	private function tableChildAttributes($elem, $attr, $column = ''){

		if(isset($attr[$elem])){

			$attr[$elem] = str_replace('{this.name}', $column, $attr[$elem]);
			$attr[$elem] = str_replace('.', '-', $attr[$elem]);
			return ' '.preg_replace('/""(.*?)""/s', '"\1"', $attr[$elem]);
		}
	}

	private function compile($elemName, $element){

		$attrList = '';
		$attrOptionList = '';
		if(is_array($this->elemAttributes[$elemName])){

			foreach($this->elemAttributes[$elemName] as $k => $v){

				if(!is_array($v) && preg_match('/\=/i', $v) && !preg_match('/\<option/i', $v)){

					$exp = explode('=', $v);
					$list = '';
					foreach($exp as $k => $v){

						if($k > 0){

							$list .= $list ? '='.$v : $v;
						}
					}
					$k = $exp[0];
					$v = $list;
				}
				if($k == 'value'){

					$split = substr(($k.'='.$v), 0, 7);
					if($split == 'value="'){

						$v = substr($v, 1);
						$v = substr($v, 0, -1);
					}
				}
				else{

					$v = preg_replace('/"(.*?)"/s', '\1', $v);
				}
				$element = str_replace('{'.$k.'}', $v, $element);
				if(!in_array($k, array('type', 'name', 'value')))
					$attrList .= ' '.$k.'="'.$v.'"';
			}
		}

		if(is_array($this->elemAttributes[$elemName.'_option'])){

			foreach($this->elemAttributes[$elemName.'_option'] as $k => $v){

				if(!is_array($v) && preg_match('/\=/i', $v)){

					$exp = explode('=', $v);
					$list = '';
					foreach($exp as $k => $v){

						if($k > 0){

							$list .= $list ? '='.$v : $v;
						}
					}
					$k = $exp[0];
					$v = $list;
				}
				$element = str_replace('{'.$k.'}', $v, $element);
				if(!in_array($k, array('type', 'name', 'value')))
					$attrOptionList .= ' '.$k.'="'.$v.'"';
			}
		}

		$element = str_replace('{type}', 'text', $element);
		$element = str_replace('{value}', '', $element);
		$element = str_replace('{name}', $elemName, $element);
		$element = str_replace(' {attr}', $attrList, $element);
		$element = str_replace(' {attr_option}', $attrOptionList, $element);
		$element = preg_replace('/([[:space:]_]+)\{selected=([a-zA-Z0-9[:space:]_]+)\}/s', '', $element);

		return $this->before[$elemName].$element.$this->after[$elemName];
	}

	private function value($key, $value){

		if($this->exception[$key]){

			return $this->exception[$key][$value];
		}
		else{

			return $value;
		}
	}

	private function unsetData(){

		unset($this->elemList);
		unset($this->required);
		unset($this->elemAttributes);
		unset($this->isHidden);
		unset($this->before);
		unset($this->after);
		unset($this->exception);
	}

	private function setList($list){

		if(!is_Array($list) && strlen($list) > 0){

			$tmp[] = $list;
			$list = $tmp;
		}
		return $list;
	}

	private function attr($elemName, $attr){

		$attr = $this->setList($attr);

		if(is_array($attr)){

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

				if($v)
					$this->elemAttributes[$elemName][$k] = $v;
			}
		}
	}

	private function appendElem($elemList){

		if( !is_array($this->elemList) )
			$this->elemList = $elemList;
		else
			$this->elemList = array_merge($this->elemList, $elemList);
	}

	/**
	* 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)){

				$this->attr($method, $args[0]);
				$this->latestElement = $method;
				return $this;
			}
		}
	}
}

?>