<?php

/**
 * Description of Core
 *
 * @author Arkadiusz Rychlik <a.rychlik at eppe.com.pl>
 */
abstract class Rtn_JqGrid_Core {

	/**
	 * @var bool Czy można zmieniać
	 */
	public $canReorder = false;
	public $actions = array(
		'add' => null,
		'clone' => null,
		'remove' => null,
		'show' => null,
		'edit' => null,
		'export' => null,
		'active' => null,
		'refresh' => null,
		'reorder' => null,
		'replace' => null,
	);
	public $extraData = [];

	/**
	 * @var bool Czy widoczne domyślne akcje (edycja/usuń)
	 */
	public $showDefaultActions = true;
	public $name;
	public $autowidth = true;
	public $caption = '';
	public $options = array();
	public $url;
	public $url_remove;
	public $url_clone;
	public $url_view;
	public $url_edit;
	public $url_export;
	public $url_send_test;
	public $url_show;
	public $url_add;
	public $url_active;
	public $url_reorder;
	public $url_replace;
	public $url_refresh;
	public $id_col = 'id';
	public $multiselect = false;
	public $sortname = 'order';
	public $sortorder = 'desc';
	public $rownum = 10;
	public $rowlist = array(10, 20, 30);
	public $colmodel;
	public $custom_buttons = array();
	public $toolbar = array();
	public $custom_js;
	public $custom_actions;
	public $height = 'auto';
	public $scroll = false;
	public $shrinktofit = true;
	public $search_button = false;
	public $search_toolbar = true;
	public $loadonce = false;
	public $hiddengrid = false;
	public $tree_grid = false;
	public $expand_column = '';
	public $view = 'jq/grid';
	public $beanName = '';

	/**
	 * @var Eppe_Crud_Controller_Action
	 */
	protected $controller;

	public function set($key, $value = null) {
		if (!in_array($key, get_object_vars($this)))
			throw new Exception('Property not found');

		$this->$key = $value;

		return $this;
	}

	/**
	 * @return array colmodel
	 */
	protected function _renderColmodel() {
		$this->shrinktofit = false;

		$cols = array();

		foreach (R::$writer->getColumns($this->beanName) as $name => $type) {
			$cols[] = array(
				'name' => $name,
				'label' => $name
			);
		}

		return $cols;
	}

	protected function _renderCustomActions() {
		return array();
	}

	protected function _fixColmodel() {

		// domyślne akcje typu dodaj/usun

		if ($this->showDefaultActions OR !empty($this->custom_actions)) {
			$colmodelActions = array(
				array(
					'name' => '', 'label' => __('Akcje'),
					'sortable' => false,
					'width' => '80',
					'custom_formatter' => 'actions',
					'align' => 'center',
					'search' => false
				)
			);
			if ($this->url_reorder) {
				array_unshift($colmodelActions, array(
					'name' => 'reorder', 'label' => __('Sortuj'),
					'sortable' => false,
					'width' => '35',
					'custom_formatter' => 'move',
					'align' => 'center',
					'search' => false
				));
			}
		}
		else {
			$colmodelActions = array();
		}

		// aktywowanie / deaktywowanie elementów

		if (!empty($this->url_active)) {
			$colmodelActive = array(
				array(
					'name' => 'active', 'label' => __('Aktywny'),
					'width' => '80',
					'custom_formatter' => 'active',
					'align' => 'center',
					'stype' => 'select',
					'_type' => 'boolean',
					'searchoptions' => array ('value' => array ('' => '') + array ('true' => 'Tak', 'false' => 'Nie'))
				)
			);
		}
		else {
			$colmodelActive = array();
		}

		return array_merge($colmodelActive, $colmodelActions, $this->_renderColmodel());
	}

	protected function _getColmodelColumn($column){
		foreach($this->colmodel as $cm){
			if($cm['name']===$column){
				return $cm;
			}
		}
	}
	
	/**
	 * @return array
	 */
	protected function fix_custom_buttons() {

	}

	protected function fix_toolbar() {

	}

	protected function fix_custom_js() {

	}

	public function __construct(Eppe_Crud_Controller_Action $controller) {
		$this->controller = $controller;

		$this->custom_actions = $this->_renderCustomActions();
		$this->custom_buttons = $this->fix_custom_buttons();
		$this->toolbar = $this->fix_toolbar();
		$this->custom_js = $this->fix_custom_js();

		$this->caption = __($this->caption);
		
		$this->name = $this->name?:get_called_class();

		$this->setUrls();
	}

	protected function setUrls() {
		$module = $this->controller->getRequest()->getModuleName();
		$controller = $this->controller->getRequest()->getControllerName();

		$helper = new Zend_View_Helper_Url();

		if (array_key_exists('add', $this->actions))
			$this->url_add = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'add'));
		if (array_key_exists('clone', $this->actions))
			$this->url_clone = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'clone', 'id' => false));
		if (array_key_exists('remove', $this->actions))
			$this->url_remove = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'ajax-remove', 'id' => false), 'default', true);
		if (array_key_exists('show', $this->actions))
			$this->url_show = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'show', 'id' => false));
		if (array_key_exists('edit', $this->actions))
			$this->url_edit = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'edit', 'id' => false));
		if (array_key_exists('export', $this->actions))
			$this->url_export = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'export', 'id' => false));
		if (array_key_exists('active', $this->actions))
			$this->url_active = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'ajax-toggle-active', 'id' => false));
		if (array_key_exists('refresh', $this->actions))
			$this->url_refresh = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'ajax-refresh', 'id' => false));
		if (array_key_exists('reorder', $this->actions))
			$this->url_reorder = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'ajax-reorder'));
		if (array_key_exists('replace', $this->actions))
			$this->url_replace = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'ajax-replace'));
		$this->url = $helper->url(array('module' => $module, 'controller' => $controller, 'action' => 'ajax-load-datagrid'));
	}

	public function selfTest() {
		$required = array('name', 'url', 'sortname', 'colmodel');
		foreach ($required as $property) {
			if (empty($this->$property)) {
				throw new Exception("Jq_Grid selftest failed($property)");
			}
		}
	}

	public function render() {
		$this->colmodel = $this->_fixColmodel(); // nie może być w konstruktorze (za wczesnie)

		$this->selfTest();

		$view = new Zend_View();
		$view->grid = $this;
		$view->isMobile = FALSE;
		$view->setScriptPath(__DIR__);

		static::includeHead();

		return $view->render('Jqgrid.phtml');
	}

	static function includeHead() {
		$view = Zend_Layout::startMvc()->getView();
		$view->headScript()->appendFile(Core_Module_Module::getInstance()->getAdminJSPath() . 'jqgrid/jquery.jqGrid.src.js');
		$view->headScript()->appendFile(Core_Module_Module::getInstance()->getAdminJSPath() . 'jqgrid/plugins/jquery.tablednd.js');
		$view->headScript()->appendFile(Core_Module_Module::getInstance()->getAdminJSPath() . 'jqgrid/i18n/grid.locale-' . Eppe_Localization::getCurrentLang() . '.js');
		$view->headLink()->appendStylesheet(Core_Module_Module::getInstance()->getAdminCSSPath() . 'jqgrid/ui.jqgrid.css');
	}

	/**
	 * Gets page rows sidx sord
	 *
	 * @return array jqgrid post parameters
	 */
	static public function get_prss() {
		$page = strip_tags(filter_input(INPUT_POST, 'page'));
		$rows = strip_tags(filter_input(INPUT_POST, 'rows'));
		$sidx = strip_tags(filter_input(INPUT_POST, 'sidx'));
		$sord = strip_tags(filter_input(INPUT_POST, 'sord'));

		return array(
			'page' => $page, 'rows' => $rows, 'sidx' => $sidx, 'sord' => $sord
		);
	}

	/**
	 * Wyciąga filtry wyszukiwania ze zmiennej POST
	 * @return array
	 */
	static public function getSearchRules() {
		$filters = strip_tags(filter_input(INPUT_POST, 'filters'));
		$filters = json_decode($filters);

		if ($filters != NULL) {
			return $filters->rules;
		}
		else {
			return array();
		}
	}

	/**
	 * @REMOVE: deprecated
	 */
	public function renderData() {
		$query = R::$f->begin();
		$grid_params = static::get_prss();

		if (NULL != $rules_to_sql = $this->_searchRulesToSql()) {
			$query->where($rules_to_sql);
		}

		if (NULL != $order_rules_to_sql = $this->_orderRulesToSql()) {
			$query->order($order_rules_to_sql);
		}

		$query->limit(($grid_params['rows'] * ($grid_params['page'] - 1)), $grid_params['rows']);

		$beans = R::findAll($this->beanName, $query);
		$rows = array();

		foreach (array_keys($beans) as $bean_k) {
			$beans[$bean_k] = $this->_transformBean($beans[$bean_k]);

			$beans[$bean_k]['_grid_extra'] = array(
				'can_edit' => $this->_canRowBeEdited($beans[$bean_k]),
				'can_clone' => $this->_canRowBeCloned($beans[$bean_k]),
				'can_send_test' => $this->_canRowBeSendTest($beans[$bean_k]),
				'can_delete' => $this->_canRowBeDeleted($beans[$bean_k]),
				'can_refresh' => $this->_canRowBeRefresh($beans[$bean_k])
			);

			array_push($rows, $beans[$bean_k]);
		}

		$this->_searchArray($rows);
		$this->_orderArray($rows);


		$response = $this->_renderResponse(R::count($this->beanName), $grid_params['rows'], $grid_params['page'], $rows);

		echo $response;
	}

	/**
	 * Zamienia parametry wyszukiwania na fragment kodu SQL
	 * o ile wyszukiwanie dotyczy kolumn tabeli lub widoku
	 *
	 * @return string
	 */
	protected function _searchRulesToSql() {
		$sql_arr = array();
		foreach (static::getSearchRules() as $rule) {
			if (isset($rule->data)) {
				if (!$this->lookupField($rule->field)) {
					continue;
				}
				
				$op2op = array('eq' => '=', 'bw' => 'like');
				$op = $op2op[$rule->op];

				$value = $rule->data;
				$value = ($op == 'like') ? ('%' . $value . '%') : ($value);

				$col = $this->_getColmodelColumn($rule->field);
				if(isset($col['_type']) && $col['_type'] === 'boolean'){
					if($value==='true'){
						$sql_arr[] = "`{$rule->field}` = TRUE";
					}
					elseif($value==='false'){
						$sql_arr[] = "(`{$rule->field}` = FALSE OR `{$rule->field}` IS NULL)";
					}
				}
				else{
					$sql_arr[] = "`{$rule->field}` $op '$value'";
				}
			}
		}
		return join(' AND ', $sql_arr);
	}

	/**
	 * Jeśli wyszukiwanie nie dotyczy kolumn tabeli lub widoku,
	 * to przeszukiwana jest końcowa tablica
	 *
	 * @return array
	 */
	protected function _searchArray(&$rows) {
		foreach (self::getSearchRules() as $rule) {
			if ($this->lookupField($rule->field)) {
				continue;
			}

			foreach (array_keys($rows) as $k) {
				if ($rule->op == 'eq') {
					if ($rows[$k][$rule->field] != $rule->data) {
						unset($rows[$k]);
					}
				}
				elseif ($rule->op == 'bw') {
					if (false === stripos($rows[$k][$rule->field], $rule->data)) {
						unset($rows[$k]);
					}
				}
			}
		}
		$rows = array_values($rows);
	}

	/**
	 * Ustala, czy sortowanie wyników nastąpiło po jednej z kolumn
	 * tabeli lub widoku i zwraca kod SQL
	 * @return string
	 */
	protected function _orderRulesToSql() {
		$grid_params = static::get_prss();

		if ($this->lookupField($grid_params['sidx'])) {
			return ' by `' . $grid_params['sidx'] . '` ' . $grid_params['sord'];
		}
	}

	/**
	 * Ustala, czy sortowanie wyników NIE nastąpiło po jednej z kolumn
	 * tabeli lub widoku i to sortowana jest końcowa tablica
	 * @return string
	 */
	protected function _orderArray(&$rows) {
		$grid_params = static::get_prss();

		if (!$this->lookupField($grid_params['sidx'])) {
			if (count($rows)) {
				foreach ($rows as $row) {
					$sortArray[] = @$row[$grid_params['sidx']];
				}

				if ($grid_params['sord'] == 'desc') {
					array_multisort($sortArray, SORT_DESC, $rows);
				}
				else {
					array_multisort($sortArray, SORT_ASC, $rows);
				}
			}
		}
	}

	public function lookupField($field) {
		return array_key_exists($field, R::$writer->getColumns($this->beanName));
	}

	public function loadDatagrid() {
		$this->colmodel = $this->_fixColmodel(); // nie może być w konstruktorze (za wczesnie)
		
		$query = R::$f->begin();
		$grid_params = static::get_prss();

		$this->extraTransformQuery($query);

		// add where?
		$_q = clone $query;
		if(preg_match('/^\s*where/i', $_q->getQuery()[0] ) === 0 ){
			$query->addSQL(' WHERE 1=1 ');
		}
		
		if (NULL != $rules_to_sql = $this->_searchRulesToSql()) {
			$query->addSQL(' AND '. $rules_to_sql);
		}
		
		if (NULL != $order_rules_to_sql = $this->_orderRulesToSql()) {
			$query->order($order_rules_to_sql);
		}
		
		$countQ = clone $query;
		$count = R::count($this->beanName, $countQ->getQuery()[0]);

		$query->limit(($grid_params['rows'] * ($grid_params['page'] - 1)), $grid_params['rows']);
		
		$beans = R::findAll($this->beanName, $query);
		
		$rows = array();

		foreach (array_keys($beans) as $bean_k) {
			$beans[$bean_k] = $this->_transformBean($beans[$bean_k]);

			$beans[$bean_k]['_grid_extra'] = array(
				'can_edit' => $this->_canRowBeEdited($beans[$bean_k]),
				'can_clone' => $this->_canRowBeCloned($beans[$bean_k]),
				'can_send_test' => $this->_canRowBeSendTest($beans[$bean_k]),
				'can_delete' => $this->_canRowBeDeleted($beans[$bean_k]),
				'can_refresh' => $this->_canRowBeRefresh($beans[$bean_k])
			);

			array_push($rows, $beans[$bean_k]);
		}

		$this->_searchArray($rows);
		$this->_orderArray($rows);


		$response = $this->_renderResponse($count, $grid_params['rows'], $grid_params['page'], $rows);

		return $response;
	}

	/**
	 * Przetwarzanie beana na array
	 *
	 * @param RedBean_OODBBean $bean
	 * @return array
	 */
	protected function _transformBean($bean) {
		$row = $bean->export();
		return $this->_extraTransformRow($row, $bean);
	}

	protected function _renderResponse($rows_count, $rows_per_page, $page, $rows) {
		$response = array(
			'totalpages' => ceil($rows_count / $rows_per_page),
			'currpage' => $page,
			'totalrecords' => $rows_count,
			'rows' => $rows
		);

		return json_encode($response);
	}

	/**
	 * zaimplementowanie dodatkowej logiki w celu pobrania np wierszy z relacji
	 *
	 * @param array $row
	 * @param RedBean_OODBBean $bean
	 * @return array
	 */
	protected function _extraTransformRow($row, $bean) {
		return $row;
	}

	/**
	 * @param array $bean Wiersz do przetworzenia
	 * @return boolean Czy można edytować ten wiersz
	 */
	protected function _canRowBeEdited($bean) {
		return true;
	}

	/**
	 * @param array $bean Wiersz do przetworzenia
	 * @return boolean Czy można klonować ten wiersz
	 */
	protected function _canRowBeCloned($bean) {
		return true;
	}

	protected function _canRowBeSendTest($bean) {
		return false;
	}

	protected function _canRowBeRefresh($bean) {
		return false;
	}

	/**
	 * @param array $bean Wiersz do przetworzenia
	 * @return boolean Czy można usunąć ten wiersz
	 */
	protected function _canRowBeDeleted($bean) {
		return true;
	}

	protected function extraTransformQuery(&$query) {

	}

}
