<?php 

/**
 * 
 */
class table
{
	var $action_pos = false;

	public function __construct($id, $items)
	{
		$this->items = $items;
		$this->id = $id;
		$this->dynamic_columns = $this->init_dynamic_columns();
		$this->display_columns = [];
		$this->action_conditioner = $this->init_action_conditioner();
		$this->multirow_actions = [];
		$this->set_notexport_columns();
		$this->set_nosort_columns();
		$this->table_id = "bootstrap-data-table-export";
		$this->table_class = "table bootstrap-data-table-export";
	}

	private function init_dynamic_columns() {
		$init = [
			'sn' => '_tf_get_serial_number',
			'date_created' => '_tf_get_date',
			'posted_on' => '_tf_get_date',
			'dob' => '_tf_get_date',
			'from' => '_tf_get_date',
			'to' => '_tf_get_date',
			'fullname' => '_tf_get_fullname',
			'profile_picture' => '_tf_get_profile_picture',
			'gender' => '_tf_get_gender',
			'username' => '_tf_to_uppercase',
			'user_id' => '_tf_get_fullname_id',
			'posted_by' => '_tf_get_fullname_id',
			'amount' => '_tf_to_money',
			'role' => '_tf_get_role',
			'db_section_id' => '_tf_get_db_section',
			'select_row' => '_tf_select_row'
		];
		return $init;
	}

	private function init_action_conditioner() {
		$init = [
			'default' => '=='
		];
		return $init;
	}

	public function set_dynamic_columns($args = array()) {
		if(is_array($args))
			$this->dynamic_columns = array_merge($this->dynamic_columns, $args);
	}

	public function set_display_columns($args = array()) {
		if(is_array($args))
			$this->display_columns = array_merge($this->display_columns, $args);
	}

	public function set_notexport_columns($args = array()) {
		$defaults = [
			'action', 'image', 'profile_picture', 'select_row'
		];
		$this->notexport_columns = array_merge($defaults, $args);
	}

	public function set_nosort_columns($args = array()) {
		$defaults = [
			'action', 'image', 'profile_picture', 'select_row'
		];
		$this->nosort_columns = array_merge($defaults, $args);
	}

	public function get_columns() {
		if(!isset($this->display_columns)) return false;
		if(!is_array($this->display_columns)) return false;
		if(!_count($this->display_columns)) return false;
		$columns = $this->display_columns;
		if(_count($this->multirow_actions)) {
			$multirow_column = ["select_row" => ""];
			$columns = array_merge($multirow_column, $columns);
		}
		return $columns;
	}

	/**
	 * Remove action from a table
	 */
	public function remove_action(...$actions) {
		foreach ($actions as $action) {
			unset($this->action_links[$action]);
		}
	}

	public function set_properties($properties = false) {
		if(!is_array($properties)) return;
		if(!_count($properties)) return;
		foreach ($properties as $property => $value) {
			$this->{$property} = $value;
		}
	}

	/**
	 * Link to visit when action is clicked with action args as get parameters
	 * Set to false for ajax actions
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_links($args) {
		$this->action_links = $args;
	}

	/**
	 * Sets action access per user
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_access($args) {
		$this->action_access = $args;
	}

	/**
	 * Function to process an action with action args as arguments
	 * Set to false for non-ajax actions
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_callback($args) {
		$this->action_callback = $args;
	}

	/**
	 * Set condition through items result for action to be visible
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_condition($args) {
		$this->action_condition = $args;
	}

	/**
	 * Set relational operators for action conditions
	 * default is ==
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_conditioner($args = array()) {
		if(is_array($args))
			$this->action_conditioner = array_merge($this->action_conditioner, $args);
	}

	/**
	 * Arguments and variables to be passed to an action.
	 * could hold a constant value or variable key from items result
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_args($args) {
		$this->action_args = $args;
	}

	/**
	 * Makes an action button to throw prompt window
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_prompt($args) {
		$this->action_prompt = $args;
	}

	/**
	 * Makes an action button to throw popup window
	 * onreturncb sets the action on focus when you leave the popup window
	 * onreturncbid sets the callbackid for onreturncb method
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_popup($args) {
		$this->action_popup = $args;
	}

	public function set_multirow_actions($args) {
		$this->multirow_actions = $args;
	}

	/**
	 * Set custom message for action success
	 * @param array $args //list of actions as key having true/false value
	 */
	public function set_action_message($args) {
		$this->action_message = $args;
	}

	public function build_link($link = '', $args = array(), $item = '', $row = 1) {
		unset($args['callback']);
		unset($args['callbackid']);
		$link = $link . "?rowid=".$this->table_id."-row-".$row."&";
		if(_count($args)) {
			foreach ($args as $key => $value) {
				$link .= (isset($item[$value])) ? htmlentities($key ."=".urlencode($item[$value]))."&" : htmlentities($key ."=".urlencode($value))."&";
			}
		}
		$link = substr($link, 0, -1);
		return $link;
	}

	public function apply_action_args($args, $item = array(), $row = false) {
		$html = ($row) ? "data-rowid=".$this->table_id."-row-".$row." " : " ";
		if(_count($args) && is_array($args)) {
			foreach ($args as $key => $value) {
				$html .= "data-".$key."=";
				$html .= (isset($item[$value])) ? $item[$value]." " : $value." ";
			}
		}
		return $html;
	}

	public function display() {
		echo $this->table_html();
	}

	public function table_rows($columns = false) {
		$html = "";
		$columns = $columns ? $columns : $this->get_columns();
		$pos = 0;

		if($columns) :
			if(_count($this->items) && is_array($this->items)): 
				foreach ($this->items as $row => $item):
					$item['item_row'] = $row;
					$item['rowid'] = $this->table_id."-row-".$row;
					$html .= "<tr id=\"".$item['rowid']."\">";
					foreach ($columns as $key => $column_name): 
						set_time_limit(60);
						if(isset($this->dynamic_columns) && isset($this->dynamic_columns[$key]) && function_exists($this->dynamic_columns[$key])) {
							$value = $this->dynamic_columns[$key]($item, $key, $this);
						} else $value = isset($item[$key]) ? $item[$key] : "";
						$html .= "<td>".$value."</td>";
						if($this->action_pos === $pos) {
							$html .= $this->build_actions($item, $row);
						}
						$pos++;
					endforeach;
					$pos = 0;
					if($this->action_pos === false) {
						$html .= $this->build_actions($item, $row);
					}
					$html .= "</tr>";
				endforeach; 
			endif; 
		endif;
		return $html;
	}

	public function test_action_condition($action_name, $item) {
		$valid = true;
		if(isset($this->action_condition) && isset($this->action_condition[$action_name])) {
			foreach ($this->action_condition[$action_name] as $c_key => $c_value) {
				if(isset($item[$c_key])) {
					$condition = isset($this->action_conditioner[$action_name]) && isset($this->action_conditioner[$action_name][$c_key]) ? $this->action_conditioner[$action_name][$c_key] : $this->action_conditioner["default"];
					if(is_array($c_value)) {
						$temp_valid = false;
						foreach($c_value as $_c_value) {
							if(varOperatorConditional($item[$c_key], $_c_value, $condition)) {
								// condition met
								$temp_valid = true;
							} else {
								// condition not met
							}
						}
						$valid = !$temp_valid ? false : $valid;
					} else {
						if(varOperatorConditional($item[$c_key], $c_value, $condition)) {
							// condition met
						} else {
							$valid = false;
						}
					}
				} else {
					$function = $c_key."_condition";
					if(function_exists($function)) {
						$valid = $function($item, $c_value);
					} else {
						$valid = false;
					}
				}
			}
		}
		return $valid;
	}

	private function build_actions($item, $row) {
		$html = "<td style=\"text-align: right;\">";
		$hasAction = false;
		if (isset($this->action_links) && _count($this->action_links)):
			$html .= "<span class=\"table-actions dropdown\">";
			$html .= "<button type=\"button\" class=\"btn btn-primary dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">
			    Take Action
			  </button><div class=\"dropdown-menu\">";
			foreach ($this->action_links as $action_name => $action_link):
				set_time_limit(30);
				if (isset($this->action_access) && current_user_can($this->action_access[$action_name])):
					if($this->test_action_condition($action_name, $item)) {
						$hasAction = true;
						if (isset($this->action_callback[$action_name]) && $this->action_callback[$action_name]):
							$html .= "<a class=\"ajax-action dropdown-item\" data-content=\"You are about to perform an action <pre>Button Clicked: <strong>".$action_name."</strong></pre> please confirm that you realy want to continue. Note that this action is not reversible\" href=\"javascript:void(0)\" ";
							if(!isset($this->action_args[$action_name]['callback'])) {
								// $html .= "data-callback=\"refreshPage\"";
							}
							if(isset($this->action_prompt[$action_name])) {
								$html .= " data-prompt='".json_encode($this->action_prompt[$action_name])."' data-continue-btn=\"Submit & Continue\"";
							}
							$html .= " data-action-callback=\"".$this->action_callback[$action_name]."\" ".$this->apply_action_args($this->action_args[$action_name], $item, $row).">".$action_name."</a>";
						else:
							$html .= "<a class=\"dropdown-item ";
							if(isset($this->action_popup[$action_name]) && $this->action_popup[$action_name]) {
								$html .= " popmeup";
							}
							$html .= "\" href=\"".$this->build_link($action_link, $this->action_args[$action_name], $item, $row)."\"";
							if(isset($this->action_popup[$action_name]) && $this->action_popup[$action_name]) {
								$height = 500;
								$width = 700;
								if(is_array($this->action_popup[$action_name])) {
									$height = isset($this->action_popup[$action_name]['height']) ? $this->action_popup[$action_name]['height'] : $height;
									$width = isset($this->action_popup[$action_name]['width']) ? $this->action_popup[$action_name]['width'] : $width;
								}
								$html .= " data-width=".$width." data-height=".$height." ";
								$html .= isset($this->action_popup[$action_name]['onreturncb']) ? " data-onreturncb=\"".$this->action_popup[$action_name]['onreturncb']."\"" : "";
								$html .= isset($this->action_popup[$action_name]['onreturncbid']) ? " data-onreturncbid=\"".$this->action_popup[$action_name]['onreturncbid']."\"" : "";
							}
							$html .= ">".$action_name."</a>";
						endif;
					}
				endif;
			endforeach;
			$html .= "</div></span>";
		endif;
		$html .= "</td>";
		return $hasAction ? $html : "<td></td>";
	}

	public function build_group_actions($columns) {
		$hasAction = false;
		$error = "";
		$html = "";
		if (isset($this->action_links) && _count($this->action_links) && _count($this->multirow_actions)):
			$html .= "<td><input type=\"checkbox\" name=\"".$this->table_id."-allrow\" id=\"".$this->table_id."-allrow\" class=\"table-multi-select-all\" value=\"select_all\" data-table-id=\"".$this->table_id."\" data-group-class=\"".$this->table_id."-selectrow\" style=\"pointer-events: all;\"></td><td colspan="._count($columns)." style=\"text-align: right;\"><div class=\"table-actions dropdown\">";
			$html .= "<div class=\"btn-group\">";
			foreach ($this->multirow_actions as $action_name => $action_group_name):
				set_time_limit(30);
				if (isset($this->action_access) && isset($this->action_access[$action_name]) && current_user_can($this->action_access[$action_name])):
					if (isset($this->action_callback[$action_name]) && $this->action_callback[$action_name]):
						$hasAction = true;
						$html .= "<a id=\"btn-".sha1($action_name)."\" class=\"ajax-group-action btn btn-default\" data-content=\"You are about to perform an action <pre>Button Clicked: <strong>".$action_name."</strong></pre> please confirm that you realy want to continue. Note that this action is not reversible\" href=\"javascript:void(0)\" ";
						if(isset($this->action_prompt[$action_name])) {
							$html .= " data-prompt='".json_encode($this->action_prompt[$action_name])."' data-continue-btn=\"Submit & Continue\"";
						}
						$html .= " data-table-id=\"".$this->table_id."\" data-action-callback=\"".$this->action_callback[$action_name]."\">".$action_group_name."</a>";
					endif;
				endif;
			endforeach;
			$html .= "</div></div></td>";
		endif;
		return $hasAction ? $html : $error;
	}

	public function table_html($is_return = true) {
		ob_start();
		add_page_stylesheet("app/assets/css/table.css", "table-actions");
		add_page_stylesheet("app/assets/plugins/datatables-bs4/css/dataTables.bootstrap4.min.css", "datatable");
		add_page_stylesheet("app/assets/plugins/datatables-buttons/css/buttons.bootstrap4.min.css", "datatable-buttons");
		$pos = 0;
		if($columns = $this->get_columns()) :
			$this->i = 1;
			?>
			<div class="table-responsive" id="<?php echo $this->id ?>">
				<table class="<?php echo $this->table_class ?>" id="<?php echo $this->table_id ?>">
					<thead>
						<tr>
						<?php 
						foreach ($columns as $key => $column_name): ?>
							<th class="<?php echo (in_array($key, $this->notexport_columns)) ? 'notexport ' : ''; echo (in_array($key, $this->nosort_columns)) ? 'no-sort ' : ''; ?>">
								<?php echo $column_name ?>
							</th>
							<?php 
							if($this->action_pos === $pos) {
								if (isset($this->action_links) && _count($this->action_links)): ?>
									<th class="notexport"></th>
								<?php 
								endif;
							}
							$pos++;
						endforeach;
						$pos = 0;
						if($this->action_pos === false) {
							if (isset($this->action_links) && _count($this->action_links)): ?>
								<th class="notexport no-sort"></th>
							<?php
							endif;
						}
						?>
						</tr>
					</thead>
					<tbody>
						<?php echo $this->table_rows() ?>
					</tbody>
					<tfoot>
						<tr>
							<?php echo $this->build_group_actions($columns) ?>
						</tr>
					</tfoot>
				</table>
			</div>
			<?php
		endif;
		add_datatable_scripts();
		$template = ob_get_contents();
		ob_get_clean();
		
		if($is_return) return $template;
		echo $template;
	}

}