<?php

/**
 * Description of Action
 *
 * @author arson
 */
class Eppe_Crud_Controller_Action extends Eppe_Backend_Controller_Action {

	/**
	 * Włączone opcje cruda
	 * a - aktywacja/deaktywacja
	 * c - dodawanie
	 * r - podgląd (N/A)
	 * u - edycja
	 * d - usuwanie
	 * R - nadanie pola refresh (napisz ajax-refresh)
	 *
	 * @var string
	 */
	protected $features;

	/**
	 * @var Eppe_Jqgrid_Jqgrid Początkowo należy podać nazwę klasy jako string
	 */
	protected $grid;

	/**
	 * @var Rtn_CRUD Początkowo należy podać nazwę klasy jako string
	 */
	protected $crud;

	public function init() {
		parent::init();
		$this->_selfTest();
		$this->_initCRUD();
		$this->_initGrid();
	}

	public function indexAction() {
		if ($this->isAjax) {
			$this->ajaxResponse->data = $this->grid->render();
		}
		else {
			$this->view->grid = $this->grid->render();
		}
	}

	public function addAction() {
		if(!$this->isAjax){
			$this->_add();
		}
		else{
			$this->_ajaxAdd();
		}
	}

	public function showAction() {
		$beanId = $this->_getParam('id');
		$this->_show($beanId);
	}

	public function editAction() {
		$beanId = $this->_getParam('id');
		if(!$this->isAjax){
			$this->view->bean_id = $beanId;
			if ($this->_edit($beanId)) {
				$this->_redirectIndex();
			}
		}
		else{
			$this->_ajaxEdit($beanId);
		}
	}

	public function cloneAction() {
		$beanId = $this->_getParam('id');
		if ($this->_clone($beanId)) {
			$this->_redirectIndex();
		}
	}

	/**
	 * Akcja do kasowania z grida
	 */
	public function ajaxRemoveAction() {
		$this->_disableView();
		$beanId = $this->_getParam('id');

		if ($this->crud->delete($beanId)) {
			$this->ajaxResponse->evalJS = 'new Success("' . __('Element został usunięty') . '"); return true;';
		} else {
			$this->ajaxResponse->evalJS = 'new Warning("' . __('Element nie może być usunięty') . '");';
		}
	}

	/**
	 * Akcja do zmiany kolejności
	 */
	public function ajaxReorderAction() {
		$this->_disableView();

		$newRows = json_decode($this->_request->getParam('newRowsOrder')); 
		
		$this->ajaxResponse->evalJS = $this->_reorderElements($newRows);
	}
	
	private function _getMinElements($elementsId){
		$minOrder = INF;
		foreach($elementsId as $rowId){
			
			$row = R::findOne($this->crud->beanName, "WHERE `id` = $rowId");
			if($row->order < $minOrder){
				$minOrder = $row->order;
			}
		}
		return $minOrder;
	}
	
	private function _getMaxElements($elementsId){
		$maxOrder = 0;
		foreach($elementsId as $rowId){
			$row = R::findOne($this->crud->beanName, "WHERE `id` = $rowId");
			if($row->order > $maxOrder){
				$maxOrder = $row->order;
			}
		}
		return $maxOrder;
	}
	
	private function _reorderElements($elementsId){
		$num = 0;
		try{
			if(strtolower($this->grid->sortorder) == 'asc'){
				$orderOffset = $this->_getMinElements($elementsId);
				foreach($elementsId as $rowId){
					$row = R::findOne($this->crud->beanName, "WHERE `id` = $rowId");
					$row->order = $orderOffset + $num;
					R::store($row);
					$num++;
				}
			}else{
				$orderOffset = $this->_getMaxElements($elementsId);
				foreach($elementsId as $rowId){
					$row = R::findOne($this->crud->beanName, "WHERE `id` = $rowId");
					$row->order = $orderOffset - $num;
					R::store($row);
					$num++;
				}
			}
			return 'new Success("' . __('Kolejność elementów została zmieniona') . '"); return true;';
		} catch (Exception $ex) {
			return 'new Warning("' . __('Kolejność elementów nie została zmieniona') . '")';
		}
	}

	public function ajaxReplaceAction() {
		$this->_disableView();

		$newRowId = $this->_request->getParam('newRowId');
		$oldRowId = $this->_request->getParam('oldRowId');

		$this->_replaceElements($oldRowId, $newRowId);

		echo Zend_Json::encode(array('result' => 'success', 'msg' => __('Elementy zostały zamienione miejscami')));
	}

	/**
	 * Akcja do zmiany znacznika aktywacji
	 */
	public function ajaxToggleActiveAction() {
		$this->_disableView();

		$beanId = $this->_getParam('id');

		$result = $this->crud->toggleActive($beanId);

		if ($result['result'] == true) {
			$this->ajaxResponse->evalJS = 'new Success("' . __('Znacznik aktywności został zmieniony') . '"); return true;';
		} else {
			$this->ajaxResponse->evalJS = 'new Warning("' . __($result['msg']) . '")';
		}
	}

	/**
	 * Wczytywanie danych grida
	 */
	public function ajaxLoadDatagridAction() {
		// echo
		echo $this->grid->loadDatagrid();
		exit;
	}

	/**
	 * Gets page rows sidx sord
	 *
	 * @return array jqgrid post parameters
	 */
	static public function get_prss() {
		$page = strip_tags($_POST['page']);
		$rows = strip_tags($_POST['rows']);
		$sidx = strip_tags($_POST['sidx']);
		$sord = strip_tags($_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(@$_POST['filters']);
		$filters = json_decode($filters);

		if ($filters != NULL) {
			return $filters->rules;
		} else {
			return array();
		}
	}

	/**
	 * Zamienia parametry wyszukiwania na fragment kodu SQL
	 * o ile wyszukiwanie dotyczy kolumn tabeli lub widoku
	 *
	 * @return string
	 */
	protected function _searchRulesToSql() {
		$sql_arr = array();
		foreach (self::getSearchRules() as $rule) {
			if ($rule->data) {
				if (!static::_lookupField($rule->field, $this->beanName)) {
					continue;
				}

				$op2op = array('eq' => '=', 'bw' => 'like');
				$op = $op2op[$rule->op];

				$value = $rule->data;
				$value = ($op == 'like') ? ('%' . $value . '%') : ($value);

				$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 (static::_lookupField($rule->field, $this->beanName)) {
				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 === strpos($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 (static::_lookupField($grid_params['sidx'], $this->beanName)) {
			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 (!static::_lookupField($grid_params['sidx'], $this->beanName)) {
			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);
				}
			}
		}
	}

	protected function _lookupField($field, $beanName) {
		return in_array($field, array_keys(R::findOne($beanName)->getProperties()));
	}

	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);
	}

	/**
	 * Tworzenie wersji roboczej elementu, wykorzystywane w generatorze stron statycznych
	 */
	public function ajaxCreateElementAction() {
		echo Zend_Json::encode(array('result' => 'success',
			'msg' => __('Element został poprawnie dodany'),
			'response' => $this->_add())
		);
		exit;
	}

	/**
	 * Utworzenie instancji klasy grida
	 */
	protected function _initGrid() {
		$this->grid = new $this->grid($this);
	}

	/**
	 * Utworzenie instancji klasy CRUD
	 */
	protected function _initCRUD() {
		$this->crud = empty($this->crud) ? $this->crud : new $this->crud;
	}

	/**
	 * Sprawdza poprawność klasy dziedziczącej
	 * @throws Exception
	 */
	protected function _selfTest() {
		$required = array('grid');
		foreach ($required as $property) {
			if (empty($this->$property)) {
				$class = get_class($this);
				$msg = __('Class `:class` self test failed with property `:property`', array(
					':class' => $class,
					':property' => $property
				));
				throw new Exception($msg);
			}
		}
	}

	/**
	 * Przekierowuje do edycji rekordu
	 * @param type $beanId
	 */
	protected function _redirectEdit($beanId) {
		$module = $this->_request->getModuleName();
		$controller = $this->_request->getControllerName();
		$action = 'edit';

		$this->_redirect($this->view->url(array('module' => $module, 'controller' => $controller, 'action' => $action, 'id' => $beanId), null, true));
	}

	protected function _redirectIndex() {
		$this->_redirect($this->_getIndexUrl());
	}
	
	protected function _getIndexUrl(){
		$module = $this->_request->getModuleName();
		$controller = $this->_request->getControllerName();
		$action = 'index';

		return $this->view->url(array('module' => $module, 'controller' => $controller, 'action' => $action), null, true);
	}

	protected function _add() {
		$formClassName = $this->crud->getFormClassName();

		$form = new $formClassName();

		if ($this->_isPost()) {
			$post = $this->_getPost();

			if (isset($post['cancel'])) {
				$this->_redirectIndex();
			}

			if ($form->isValid($post) && $this->crud->create($post)) {
				$this->_addMessage(__('Zmiany zostały zapisane'));
				$this->_redirectIndex();
			}
			else {
				$form->populate($this->_getPost());
			}
		}

		$this->view->form = $form;
	}

	protected function _ajaxAdd() {
		$formClassName = $this->crud->getFormClassName();
		$form = new $formClassName();

		if($this->_isPost() && $this->_getPost('buttonValue')=='cancel'){
			$this->ajaxResponse->evalJS = 'ajx.loader.show(); window.location = "'.$this->_getIndexUrl(). '"';
			return false;
		}
		
		$view = new Zend_View();
		$view->setScriptPath(Rtn_Finder_File_View::find('views/Eppe/CRUD/', 'ajax-add.phtml'));
		
		$viewFile = [
			'view' => $view,
			'file' => 'ajax-add.phtml'
		];

		$this->commonAjaxForm($form, $viewFile, function($form) {
			$this->crud->create($form->getValues());
			
			$ajaxResponse = new Rtn_Ajax_Response();
			$ajaxResponse->evalJS = 'ajx.loader.show(); window.location = "'.$this->_getIndexUrl(). '"';
			return $ajaxResponse;
		});
	}

	protected function _edit($beanId) {
		$bean = $this->crud->findBean($beanId);

		$formClassName = $this->crud->getFormClassName();

		$form = new $formClassName(array('bean' => $bean));

		if ($this->_isPost()) {
			$post = $this->_getPost();

			if (isset($post['cancel'])) {
				$this->_redirectIndex();
			}

			if ($form->isValid($post)) {
				if ($this->crud->update($beanId, $post)) {
					$this->_addMessage(__('Zmiany zostały zapisane'));
					$this->_redirectIndex();
				}
			}
			else {
				$form->populate($this->_getPost());
			}
		} else {
			$form->populateWithBean($bean);
		}


		$this->view->form = $form;
	}

	protected function _ajaxEdit($beanId) {
		$bean = $this->crud->findBean($beanId);
		$formClassName = $this->crud->getFormClassName();

		$form = new $formClassName([
			'bean' => $bean,
			'attribs' => [
				'beanId' => $beanId
			]
		]);
		
		if($this->_isPost() && $this->_getPost('buttonValue')=='cancel'){
			$this->ajaxResponse->evalJS = 'ajx.loader.show(); window.location = "'.$this->_getIndexUrl(). '"';
			return false;
		}
		
		$view = new Zend_View();
		$view->setScriptPath(Rtn_Finder_File_View::find('views/Eppe/CRUD/', 'ajax-edit.phtml'));
		
		$viewFile = [
			'view' => $view,
			'file' => 'ajax-edit.phtml'
		];

		$this->commonAjaxForm($form, $viewFile, function($form) {
			$beanId = $form->getAttrib('beanId');
			$this->crud->update($beanId, $form->getValues());
			
			$ajaxResponse = new Rtn_Ajax_Response();
			$ajaxResponse->evalJS = 'ajx.loader.show(); window.location = "'.$this->_getIndexUrl(). '"';
			return $ajaxResponse;
		});
	}
	
	
	protected function _clone($beanId) {
		$bean = R::load($this->beanName, $beanId);
		R::store(R::dup($bean));
	}

	protected function _show($beanId) {
		$this->view->bean = $this->crud->findBean($beanId);
		$this->view->indexUrl = $this->_getIndexUrl();
	}

}
