<?php defined('SYSPATH') or die('No direct access allowed.');

/**
 * This class is for rendering a table of data.
 *
 * @package    lnApp
 * @category   lnApp/Helpers
 * @author     Deon George
 * @copyright  (c) 2009-2013 Deon George
 * @license    http://dev.leenooks.net/license.html
 */
abstract class lnApp_Table {
	private $data = NULL;
	private $columns = array();		// Our columns that we need to display
	private $jssort = FALSE;		// Use the JS pager and sorter
	private $other = '';			// If we are only listing x items, this will be the other summary line
	private $other_col = NULL;		// If we are only listing x items, this will be the other summary line
	private $po = NULL;			// If we are paging the results, this is the page we are displaying
	private $page = FALSE;			// If we should page the results
	private $page_rows = 0;			// Number of rows per page
	private $prepend = array();		// Our datafomrating that we need to use

	public function __toString() {
		return (string) $this->render();
	}

	public function columns($cols) {
		$this->columns = $cols;

		return $this;
	}

	public function data($data) {
		$this->data = $data;

		return $this;
	}

	private function evaluate($d,$key) {
		if (is_array($d) AND isset($d[$key]))
			$x = $d[$key];

		// If the key is a method, we need to eval it
		elseif (preg_match('/\(/',$key) OR preg_match('/-\>/',$key))
			eval("\$x = \$d->$key;");

		elseif (preg_match('/^__VALUE__$/',$key))
			$x = $d;

		else
			$x = $d->display($key);

		if (isset($this->prepend[$key])) {
			foreach ($this->prepend[$key] as $act => $data) {
				switch ($act) {
					case 'url': $x = HTML::anchor($data.$x,$x);
					break;
				}
			}
		}

		return $x;
	}

	public static function factory() {
		return new Table;
	}

	public function jssort($bool) {
		$this->jssort = $bool;

		return $this;
	}

	public function page_items($num) {
		$this->page = TRUE;
		$this->page_rows = $num;

		return $this;
	}

	public function prepend($cols) {
		$this->prepend = $cols;

		return $this;
	}

	private function process() {
		$result = array();

		$row = 0;
		foreach ($this->data as $o) {
			$row++;
			$c = 0;

			// If we are HTML paging
			if ($this->page) {
				if ($row < $this->po->current_first_item())
					continue;
				elseif ($row > $this->po->current_last_item())
					break;
			}

			// If we are just listing page_rows items and a summary line as a result of exceeding that
			if ($this->other_col AND $row>$this->page_rows) {
				$this->other += Table::resolve($o,$this->other_col);

			// Otherwise rendering our rows
			} else {
				foreach ($this->columns as $col => $label) {
					$c++;
	
					$result[$row]['val'][$c] = $this->evaluate($o,$col);
				}
			}
		}

		return $result;
	}

	public function render() {
		$output = '';

		// If we need to page the results
		if ($this->page) {
			$this->po = new Pagination(array(
				'total_items'=>count($this->data),
				'items_per_page'=>$this->page_rows,
			));

			$output .= (string)$this->po;

		}

		$output .= View::factory('table')
			->set('jssort',$this->jssort AND ! $this->page)
			->set('other',$this->other)
			->set('th',$this->columns)
			->set('td',$this->process());

		// Use the javascript paging
		if ($this->jssort AND ! $this->page) {
			Script::factory()
				->type('stdin')
				->data('
$(document).ready(function() {
	$.extend($.tablesorter.themes.bootstrap, {
		// these classes are added to the table. To see other table classes available,
		// look here: http://twitter.github.com/bootstrap/base-css.html#tables
		table      : "table table-striped",
		header     : "bootstrap-header", // give the header a gradient background
		footerRow  : "",
		footerCells: "",
		icons      : "", // add "icon-white" to make them white; this icon class is added to the <i> in the header
		sortNone   : "bootstrap-icon-unsorted",
		sortAsc    : "icon-chevron-up",
		sortDesc   : "icon-chevron-down",
		active     : "", // applied when column is sorted
		hover      : "", // use custom css here - bootstrap class may not override it
		filterRow  : "", // filter row class
		even       : "", // odd row zebra striping
		odd        : ""  // even row zebra striping
	});

	$("#list-table").tablesorter({
		theme: "bootstrap",
		widthFixed : true,
		headerTemplate : "{content} {icon}", // Add icon for jui theme; new in v2.7!
		widgets: [ "uitheme", "stickyHeaders", "filter" ],

	}).tablesorterPager({
		// target the pager markup - see the HTML block below
		container  : $(".pager"),
		output     : "{startRow} - {endRow} / {filteredRows} ({totalRows})",
		fixedHeight: true,
		removeRows : false,
		cssGoto    : ".gotoPage"

	});
});
				');

			Script::factory()
				->type('file')
				->data('media/vendor/mottie-tablesorter/js/jquery.tablesorter.min.js');

			Script::factory()
				->type('file')
				->data('media/vendor/mottie-tablesorter/js/jquery.tablesorter.widgets.min.js');

			Script::factory()
				->type('file')
				->data('media/vendor/mottie-tablesorter/js/jquery.tablesorter.pager.min.js');

			Style::factory()
				->type('file')
				->data('media/vendor/mottie-tablesorter/css/theme.bootstrap.css');
			Style::factory()
				->type('file')
				->data('media/vendor/mottie-tablesorter/css/jquery.tablesorter.pager.css');
		}

		return $output;
	}

//ZZ
	public static function display($data,$rows,array $cols,array $option) {
		$prepend = $headers = array();

		foreach ($cols as $k=>$v) {
			if (isset($v['label']))
				$headers[$k] = $v['label'];
			if (isset($v['url']))
				$prepend[$k] = array('url'=>$v['url']);
		}

		return static::factory()
			->data($data)
			->jssort(TRUE)
			->page_items($rows)
			->columns($headers)
			->prepend($prepend);

/*
					if (! empty($option['button']))
						$button = implode('',$option['button']);
					else
						$button = Form::button('Submit','View/Edit',array('class'=>'form_button','type'=>'submit'));

// This JS is failing, any pressing of select all, unselect all, toggle is propaging up and submitting the form

					Script::factory()
						->type('stdin')
						->data('
(function($) {
	// Enable Range Selection
	$.fn.enableCheckboxRangeSelection = function() {
		var lastCheckbox = null;
		var followOn = 0;
		var $spec = this;
		$spec.bind("click", function(e) {
			if (lastCheckbox != null && e.shiftKey) {
				x = y = 0;
				if (followOn != 0) {
					if ($spec.index(lastCheckbox) < $spec.index(e.target)) {
						x = 1 - ((followOn == 1) ? 1 : 0);
					} else {
						y = 1 - ((followOn == -1) ? 1 : 0);
					}
				}

				$spec.slice(
					Math.min($spec.index(lastCheckbox) - x, $spec.index(e.target)) + 1,
					Math.max($spec.index(lastCheckbox), $spec.index(e.target)) + y
				).attr("checked",function() { return ! this.checked; })
				.parent().parent().toggleClass("selected");

				followOn = ($spec.index(lastCheckbox) < $spec.index(e.target)) ? 1 : -1;
			} else {
				followOn = 0;
			}
			lastCheckbox = e.target;
		});

		return $spec;
	};

	// Enable Toggle, (De)Select All
	$.fn.check = function(mode) {
		// if mode is undefined, use "on" as default
		var mode = mode || "on";

		switch(mode) {
			case "on":
				$("#select-table tr:not(.head)")
					.filter(":has(:checkbox:not(checked))")
					.toggleClass("selected")
				break;
			case "off":
				$("#select-table tr:not(.head)")
					.filter(":has(:checkbox:checked)")
					.toggleClass("selected")
				break;
			case "toggle":
				$("#select-table tr:not(.head)")
					.toggleClass("selected");
				break;
		}

		return this.each(function(e) {
			switch(mode) {
				case "on":
					this.checked = true;
					break;
				case "off":
					this.checked = false;
					break;
				case "toggle":
					this.checked = !this.checked;
					break;
			}
		});
	};
})(jQuery);

// Bind our actions
$(document).ready(function() {
	$("#select-table :checkbox").enableCheckboxRangeSelection();
	$("#select-menu > #toggle").bind("click",function() {
		$("#select-table :checkbox").check("toggle");
	});
	$("#select-menu > #all_on").bind("click",function() {
		$("#select-table :checkbox").check("on");
	});
	$("#select-menu > #all_off").bind("click",function() {
		$("#select-table :checkbox").check("off");
	});

	// Click to select Row
	$("#select-table tr:not(.head)")
		.filter(":has(:checkbox:checked)")
		.addClass("selected")
		.end()
		.click(function(e) {
			$(this).toggleClass("selected");
			if (e.target.type !== "checkbox") {
				$(":checkbox", this).attr("checked", function() {
					return !this.checked;
				});
			}
		});

	// Double click to select a row
	$("#select-table tr:not(.head)")
		.dblclick(function(e) {
			window.location = $("a", this).attr("href");
		});
});
					');
*/
	}

	// This enables us to page through many selected items
	// @todo This is currently not usable, since our JS above needs to be fixed to work with tablesorter
	public static function page($key) {
		// We have preference for parameters passed to the action.
		if (is_null($id = Request::current()->param('id'))) {
			// First save our POST id data into the session, so we dont need it when going to each page
			if (isset($_POST['id']) AND is_array($_POST['id']))
				Session::instance()->set('page_table_view'.$key,'id');

			if ($ids = Session::instance()->get('page_table_view'.$key)) {
				$pag = new Pagination(array(
					'total_items'=>count($ids),
					'items_per_page'=>1,
				));

				return array($ids[$pag->current_first_item()-1],(string)$pag);
			}
		}

		// If we get here, then there is no previous data to retrieve.
		return array($id,'');
	}
}
?>
