<?php
 /**
  * Parent Controller
  *
  * This is the parent controller used to extend our controllers.
  *
  * @author Innoxess Spain, S.L. <hola@innoxess.es>
  * @copyright 2015-2018 Innoxess Spain, S.L.
  * @package  Application
  * @subpackage Controllers
  *
  */
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 /**
  * Class MY_Controller - Controller
  *
  * Parent Controller
  */
class MY_Controller extends CI_Controller
{
	/** @var string This is the title for layout view. */
	protected $main_title;
	/** @var string This is the tip for layout view. */
	protected $main_tip;
	/** @var string This is the icon for layout view. */
	protected $icon;
	/** @var string This is the version for layout view. */
	protected $version;
	/** @var string This is the model associated to the controller. */
	protected $model;
	/** @var string This is the create view associated to the section. */
	protected $create_view		= 'crud/create';
	/** @var string This is the edit view associated to the section. */
	protected $edit_view		= 'crud/edit';
	/** @var string This is the delete view associated to the section. */
	protected $delete_view		= 'crud/delete';
	/** @var string This is the delete title section. */
	protected $delete_title;
	/** @var string This is the delete message to the section. */
	protected $delete_msg;
	/** @var string This is the create message to the section. */
	protected $create_title;
	/** @var string This is the edit message to the section. */
	protected $edit_title;
	/** @var string This is the breadcrum element to the section. */
	private $breadcum			= array();
	/** @var string This is the previos breadcrum to the section. */
	private $pre_breadcum		= array();

	/**
	  * Constructor
	  */
	function __construct()
	{
		parent::__construct();

		$this->load->helper('url');
		$this->load->helper('form');
		$this->load->helper('language');
		$this->load->library('form_validation');
		$this->load->model('login_m');
		$this->load->model('languages_m');
		$this->load->database();

		if(isset($this->model))
		{
			$this->load->model($this->model);
		}

		if(get_class($this) != 'Login' && get_class($this) != 'Ws' && get_class($this) != 'Uploader')
		{
			if(!$this->login_m->is_loged_in())
			{
				redirect('login');
			}
		}

		$user				= $this->login_m->get_user();
		if($user)
		{
			$user_language		= $user["language_id"];
			$language			= $this->languages_m->get_name($user_language);

			$this->lang->load('app', $language);
			$this->lang->load(APP_COMPANY_FORK, $language);
		} else {
			$this->lang->load('app');
			$this->lang->load(APP_COMPANY_FORK);
		}

		$this->config->load('version');

		$this->version		= $this->config->item('version');

		$this->create_title	= lang('create_item');
		$this->edit_title	= lang('edit_item');
		$this->delete_title	= lang('delete_item');
		$this->delete_msg	= lang('delete_msg');
	}

	/**
	  * Set form validation
	  *
	  * @param array $items Multidimensional array containing form elements information
	  */
	function _set_rules($items = array())
	{
		foreach($items as $item)
		{
			if(!isset($item['type']))
			{
				$item['type']		= '';
			}

			switch($item['type'])
			{
				case 'p':
				case 'h2':
				case 'script':
				case 'address_number':
					continue(2);
				case 'twolists':
					if(!empty($item['rules']))
					{
						$this->form_validation->set_rules($item['fields'][0], $item['labels'][0], $item['rules'][0]);
						$this->form_validation->set_rules($item['fields'][1], $item['labels'][1], $item['rules'][1]);
					}
					continue(2);
				case 'address':
					if(stripos($item['rules'], 'required')!==FALSE)
					{
						$add_rule			= 'callback__addr_check['.$item['field'].','.$item['field_number'].',code,required]';
						$item['rules']		= str_ireplace('required', $add_rule, $item['rules']);

						$add_rule			= 'callback__addr_check['.$item['field'].','.$item['field_number'].',addr,required]';
						$this->form_validation->set_rules($item['field'].'_addr', 'Dirección', $add_rule);

						$add_rule			= 'callback__addr_check['.$item['field'].','.$item['field_number'].',cp,required]|numeric|exact_length[5]';
						$this->form_validation->set_rules($item['field'].'_cp', 'Código postal', $add_rule);

						$add_rule			= 'callback__addr_check['.$item['field'].','.$item['field_number'].',number,required]|numeric|max_length[3]';
						$this->form_validation->set_rules($item['field_number'], 'Número', $add_rule);
					} else {
						$add_rule			= 'callback__addr_check['.$item['field'].','.$item['field_number'].',no]';
						$item['rules']		= $item['rules'].'|'.$add_rule;
					}
			}

			$field				= $item['field'];
			if(isset($item['alias']))
			{
				$field				= $item['alias'];
			}

			if(!empty($item['rules']))
			{
				$this->form_validation->set_rules($field, $item['label'], $item['rules']);
			} else {
				$this->form_validation->set_rules($field, $item['label'], '');
			}
		}
	}

	/**
	  * Move upload file
	  *
	  * @param string $source_file Source file
	  * @param string $target_dir Target
	  */
	function _move_not_overwrite($source_file, $target_dir)
	{
		$source_name		= basename($source_file);
		$target_file 		= $target_dir.$source_name;
		$count				= 1;
		do{
			$exist				= file_exists($target_file);
			if($exist == false)
			{
				rename ($source_file, $target_file);
			} else {
				$source_name		= $count.$source_name;
				$target_file		= $target_dir.$source_name;
			}
			$count++;
		}while($exist == true);

		return '/'.$source_name;
	}

	/**
	  * Parse POST data
	  *
	  * @param array $items Multidimensional array containing form elements information
	  *
	  * @return array
	  */
	function _get_data($items = array())
	{
		$data				= array();
		foreach($items as $item)
		{
			if(isset($item['field']))
			{
				$data				= array_merge($data, $this->_get_item_data($item));
			} else if(isset($item['fields'])) {
				foreach($item['fields'] as $field)
				{
					$item['field']		= $field;

					$data				= array_merge($data, $this->_get_item_data($item));
				}
			}
		}

		return $data;
	}

	/**
	  * Parse POST data
	  *
	  * @param array $item Array containing form element information
	  *
	  * @return array
	  */
	function _get_item_data($item)
	{
		$field				= $item['field'];
		$value				= $this->input->post($field);
		$value				= $value=='null'? NULL: $value;
		if(isset($item['type']))
		{
			switch($item['type'])
			{
				case 'file':
					if(isset($item['dir']) && $item['type'] == 'file' && preg_match('/^(\[#POOL#\])/',$value)===1)
					{
						$value				= str_ireplace('[#POOL#]', '', $value);
						$value				= $this->_move_not_overwrite(TEMP_UPLOAD.$value, BASE_UPLOAD.$item['dir'].'/');
					}
					break;
				case 'date':
					if(trim($value) == "")
					{
						$value				= NULL;
					} else {
						if(preg_match("/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/", $value))
						{
							list($day, $month, $year) = explode('/', $value);
							$value				= $year.'-'.$month.'-'.$day;
						}else{
							$value				= date('Y-m-d', strtotime($value));
						}
					}
					break;
			}
		}

		$data				= array();
		if(!isset($item['ignore']) || $item['ignore'] != TRUE)
		{
			$data[$field] = $value;
		}

		return $data;
	}

	/**
	  * Adding dynamic data from private vars to inject into the view for section delete of the crud
	  *
	  * @param array $data Array for inject into layout
	  *
	  * @return array
	  */
	function _delete_msg(&$data)
	{
		$data['msg']		= $this->delete_msg;
		$data['title']		= $this->delete_title;
	}

	/**
	  * Adding dynamic data from private vars to inject into the view for section create of the crud
	  *
	  * @param array $data Array for inject into layout
	  *
	  * @return array
	  */
	function _create_msg(&$data)
	{
		$data['msg']		= '';
		$data['title']		= $this->create_title;
	}

	/**
	  * Adding dynamic data from private vars to inject into the view for section edit of the crud
	  *
	  * @param array $data Array for inject into layout
	  *
	  * @return array
	  */
	function _edit_msg(&$data)
	{
		$data['msg']		= '';
		$data['title']		= $this->edit_title;
	}

	/**
	  * Adding views to make form for sections create/edit/show of the crud
	  *
	  * @param array $items Multidimensional array containing form elements information
	  * @param null|array $values Saved values for edit or show, null for create
	  * @param true|false $view_only Flag for show view
	  *
	  * @return array
	  */
	function _get_fields($items = array(), $values=NULL, $view_only = FALSE)
	{
		$data				= array();
		$view_suffix		= '';
		if($view_only)
		{
			$view_suffix		= '_view';
		}

		foreach($items as $key=>$item)
		{
			if(isset($item['field']))
			{
				if(isset($values[$item['field']]))
				{
					if(!isset($item['type']) || $item['type']!='password')
					{
						$item['value']		= $values[$item['field']];
					}
					if(isset($item['type']) && $item['type']=='date'){
						$item['value']		= date('d-m-Y', strtotime($values[$item['field']]));
					}
				}

				$default_value		= isset($item['value'])? $item['value'] : NULL;
				if($default_value==NULL)
				{
					$value				= set_value($item['field']);
				}else{
					$value				= set_value($item['field'], $default_value);
				}

				$item['value']		= $value;
				if(!isset($item['type']))
				{
					$item['type']		= 'text';
				}

				switch($item['type'])
				{
					case 'address':
						$this->load->model('address_m');

						$default_value		= $this->address_m->get_addr($item['value']);
						$item['value_addr']	= set_value($item['field'].'_addr', $default_value);
						$default_value		= $this->address_m->get_cp($item['value']);
						$item['value_cp']	= set_value($item['field'].'_cp', $default_value);
						break;
					case 'select_inline':
						$item['items_table']= Modules::run($item['module'].'/_get_items', $item['config']);
						break;
					case 'select':
					case 'multiselect_db':
					case 'multiselect':
					case 'twolists':
						if(!empty($item['model']) && !empty($item['method']))
						{
							$model				= $item['model'];
							$method				= $item['method'];

							$this->load->model($model);

							$params				= array();
							if(isset($item['params']))
							{
								if(is_array($item['params']))
								{
									$params				= $item['params'];
								} else {
									$params				= array($item['params']);
								}
							}
							$item['values']		= call_user_func_array(array(&$this->$model,$method), $params);
						}
						break;
					case 'parameter':
						$this->load->model('parameters_m');

						$default_value		= $this->parameters_m->get_by_name($item['param']);
						$item['type']		= 'select';
						$listValues			= (array) json_decode($default_value["value"], true);
						$list				= [];
						foreach($listValues as $keyValue => $value)
						{
							$list[]				= [
								'value'				=> $keyValue+1,
								'text'				=> $value
							];
						}
						$item['values']		= $list;
						break;
				}

				$data_key			= $item['field'];
			}else if(isset($item['fields'])){
				$item['values']		= $values;
				$data_key			= "item_".$key;
			}else{
				$data_key			= "item_".$key;
			}

			$field_view			= $this->load->view('items/'.$item['type'].$view_suffix, array('item' => $item), TRUE);
			if(isset($item['permissions']))
			{
			    if($this->login_m->user_has_role($item['permissions']))
			    {
                    $data[$data_key]	= $field_view;
                }
            } else {
                $data[$data_key]	= $field_view;
            }
		}

		return $data;
	}

	/**
	  * Return layout view for create section of crud.
	  */
	public function create()
	{
		$name				= strtolower(get_class($this));

		$this->show_template($this->create_view, $this->_create($name));
	}

	/**
	  * Help create method to return layout view for create section of crud or to process submit for create section.
	  *
	  * @param string $back Segment url passed to base_url helper used to back when click on cancel button on delete section
	  * @param string $target Segment url passed to base_url helper used to go when click on submit button on delete section
	  * @param string $ok -
	  *
	  * @return mixed
	  */
	protected function _create($back='', $target='', $ok=NULL)
	{
		if($ok==NULL)
		{
			$ok					= $back;
		}
		$model				= $this->model;
		$items				= $this->_get_items('create');

		$this->_set_rules($items);

		$data				= array();
		if($this->form_validation->run() == TRUE)
		{
			$data				= $this->_get_data($items);
			$new_id				= $this->$model->save(NULL, $data);
			$data['id']			= $new_id;
			if($new_id <= 0)
			{
				$data['msg']		= 'Ha ocurrido un error pongase en contacto con el administrador';
				$data['status']		= 0;
			} else {
				$this->session->set_flashdata('success', lang('successful_operation'));
				$data['msg']		= 'Creado correctamente';
			}
		} else {
			$data['fields']		= $this->_get_fields($items);
			$data['icon']		= $this->icon;
			$data['back']		= $back;
			$data['target']		= $target;

			$this->_create_msg($data);
		}

		if(isset($data['id']))
		{
			redirect($ok);
		} else {
			return $data;
		}
	}

	/**
	  * Return layout view for edit section of crud.
	  *
	  * @param int $id ID
	  */
	function edit($id)
	{
		$name = strtolower(get_class($this));

		$this->show_template($this->edit_view, $this->_edit($id, $name));
	}

	/**
	  * Help edit method to return layout view for edit section of crud or to process submit for edit section.
	  *
	  * @param string $id Primary key value
	  * @param string $back Segment url passed to base_url helper used to back when click on cancel button on delete section
	  * @param string $target Segment url passed to base_url helper used to go when click on submit button on delete section
	  * @param string $ok -
	  *
	  * @return mixed
	  */
	function _edit($id, $back='', $target='', $ok=NULL)
	{
		if($ok==NULL)
		{
			$ok					= $back;
		}
		$model				= $this->model;
		$items				= $this->_get_items('edit');

		$this->_set_rules($items);

		$data				= array();
		if($this->form_validation->run() == TRUE)
		{
			$data				= $this->_get_data($items);
			$update_id			= $this->$model->save($id, $data);
			$data['id']			= $update_id;
			if($update_id <= 0)
			{
				$data['msg']		= 'Ha ocurrido un error pongase en contacto con el administrador';
				$data['status']		= 0;
			} else {
				$this->session->set_flashdata('success', lang('successful_operation'));
				$data['msg']		= 'Guardado correctamente';
			}
		} else {
			$data['values']		= $this->$model->get_one($id);
			$data['fields']		= $this->_get_fields($items, $data['values']);
			$data['icon']		= $this->icon;
			$data['back']		= $back;
			$data['target']		= $target;

			$this->_edit_msg($data);
		}

		if(isset($data['id']))
		{
			redirect($ok);
		} else {
			return $data;
		}
	}

	/**
	  * Return layout view for delete section of crud.
	  *
	  * @param int $id ID
	  */
	function delete($id)
	{
		$name				= strtolower(get_class($this));

		$this->show_template($this->delete_view, $this->_delete($id, $name));
	}

	/**
	  * Help delete method to return layout view for delete section of crud or to process submit for delete section.
	  *
	  * @param string $id Primary key value
	  * @param string $back Segment url passed to base_url helper used to back when click on cancel button on delete section
	  * @param string $target Segment url passed to base_url helper used to go when click on submit button on delete section
	  * @param string $ok -
	  * @param true|false $wrap -
	  *
	  * @return mixed
	  */
	function _delete($id, $back='', $target='', $ok=NULL, $wrap=TRUE)
	{
		if($ok==NULL)
		{
			$ok					= $back;
		}
		$model				= $this->model;
		$items				= $this->_get_items('delete');

		$this->_set_rules($items);

		$data				= array();
		if($this->form_validation->run() == TRUE)
		{
			$delete_id			= $this->$model->delete($id);
			$data['id']			= $delete_id;
			if($delete_id <= 0)
			{
				$data['msg']		= 'Ha ocurrido un error pongase en contacto con el administrador';
			} else {
				$data['msg']		= 'Borrado correctamente';
			}
		} else {
			$data['values']		= $this->$model->get_one($id);
			$data['fields']		= $this->_get_fields($items, $data['values']);
			$data['icon']		= $this->icon;
			$data['back']		= $back;
			$data['wrap']		= $wrap;
			$data['target']		= $target;

			$this->_delete_msg($data);
		}

		if(isset($data['id']))
		{
			redirect($ok);
		}else{
			return $data;
		}
	}

	/**
	  * Append new element to private var breadcum.
	  *
	  * @param string $url Segment url passed to base_url helper
	  * @param string $text Label for link
	  */
	function add_breadcum($url, $text)
	{
		$this->breadcum[] = array('url' => $url, 'text' => $text);
	}

	/**
	  * Append new element to private var pre_breadcum.
	  *
	  * @param string $url Segment url passed to base_url helper
	  * @param string $text Label for link
	  */
	function add_pre_breadcum($url, $text)
	{
		$this->pre_breadcum[] = array('url' => $url, 'text' => $text);
	}

	/**
	  * Get breadcrum dynamic array to inject into the view
	  *
	  * @return array
	  */
	private function get_breadcum()
	{
		$breadcum			= array();
		$breadcum[]			= array(
			'url'				=> '',
			'text'				=> '<i class="fa fa-home"></i>'.lang('menu_dashboard')
		);
		foreach($this->pre_breadcum as $key=>$item)
		{
			$breadcum[]			= $item;
		}

		if(lang('menu_dashboard') != $this->main_title)
		{
			$breadcum[]			= array(
				'url'				=> strtolower(get_class($this)),
				'text'				=> '<i class="'.$this->icon.'"></i> '.$this->main_title
			);
		}

		foreach($this->breadcum as $key => $item)
		{
			$breadcum[]			= $item;
		}
		foreach($breadcum as $key => $item)
		{
			$breadcum[$key]['class'] = "";
		}

		$breadcum[(count($breadcum)-1)]['class'] = 'active';

		return $breadcum;
	}

	/**
	  * Get menu dynamic array to inject into the view
	  *
	  * @return array
	  */
	private function get_menu()
	{
		$this->config->load('app/menu');
		$menu			= $this->config->item('main_menu');
		$return			= [];
		foreach($menu as $key=>$item){
			if(isset($item['permissions']))
			{
				if(!$this->login_m->user_has_role($item['permissions']))
				{
					continue;
				}
			}

			$return[]		= $item;
		}

		foreach($return as $key=>$item)
		{
			$return[$key]['class'] = "";
			if($item['url']!='')
			{
				if(preg_match('/^'.$item['url'].'/', $this->uri->uri_string()))
				{
					$return[$key]['class'] = "active";
				}
			}else{
				if($this->uri->uri_string() == ''){
					$return[$key]['class'] = "active";
				}
			}
		}

		return $return;
	}

	/**
	  * Load view into template with all dynamic data
	  *
	  * @param string $view View route
	  * @param null|array $data Dynamic data to inject into layout & view
	  * @param string $template Layout route
	  */
	function show_template($view, $data = NULL, $template = 'templates/main')
	{
		if($data==NULL)
		{
			$data				= array();
		}

		$this->load->view($template, array_merge($data, [
			'main_content'		=> $view,
			'main_title'		=> $this->main_title,
			'main_tip'			=> $this->main_tip,
			'menu'				=> $this->get_menu(),
			'breadcum'			=> $this->get_breadcum(),
			'icon'				=> $this->icon,
			'version'			=> $this->version,
			'main_skin'			=> $this->config->item('skin'),
			'current_user'		=> $this->login_m->get_user(),
		]));
	}

	/**
	  * Load crud table view
	  *
	  * @param string $toolbar HTML buttons to inject on toolbar box
	  * @param string $items_key Key to read off config
	  */
	public function _table($toolbar='', $items_key='table')
	{
		$name				= strtolower(get_class($this));

		$this->show_template('crud/table', [
			'table_id'			=> $name."_table",
			'toolbar'			=> $toolbar,
			'items_source'		=> $name.'/table',
			'items_table'		=> $this->_get_items($items_key)
		]);
	}

	/**
	  * Load tree view
	  *
	  * @param null|array $content Content of tree
	  */
	public function _tree($content = NULL)
	{
		$name				= strtolower(get_class($this));

		$this->show_template('crud/tree', [
			'tree_id'			=> $name."_tree",
			'tree_source'		=> $name."/tree_source",
			'tree_panel'		=> $name."/tree_panel",
			'tree_content'		=> $content
		]);
	}

	/**
	  * Get JSON with table data
	  *
	  */
	public function table()
	{
		$this->load->view('output/json', array('json' => $this->_ajax_table()));
	}

	/**
	  * Load items for table or forms of the crud from config files
	  *
	  * @param string $config Route of config to load
	  */
	function _get_items($config)
	{
		if($config == 'delete')
		{
			return [array(
				'label'				=> 'confirmation',
				'field'				=> 'yes',
				'value'				=> "yes",
				'type'				=> 'hidden'
			)];
		}

		$name				= 'fields/'.strtolower(get_class($this));

		$this->config->load($name, TRUE, TRUE);

		$items				= $this->config->item($config, $name);
		if(empty($items))
		{
			$items				= $this->config->item($config);
			if(empty($items) || !is_array($items))
			{
				$items				= array();
			}
		}
		$return				= [];
		foreach($items as $key => $item)
		{
			if(isset($item['permissions']))
			{
			    if(!$this->login_m->user_has_role($item['permissions']))
			    {
                    continue;
                }
            }

            $return[]			= $item;
        }
		$key_n				= 0;
		foreach($return as $key => $item)
		{
			if($this->session->userdata('user_role') == 2 && strtolower(get_class($this)) == "docs_bundles")
			{
				if($item['field'] == "business_partner")
				{
					unset($items[$key]);
				}
			}

			if(isset($item['type']))
			{
				switch($item['type'])
				{
					case 'password':
						$repeat				= $item['field'].'_repeat';
						$rules				= 'matches['.$repeat.']';
						$rules_repeat		= 'matches['.$item['field'].']';
						if(!empty($item['rules']))
						{
							$rules				= $item['rules'].'|'.$rules;
							$rules_repeat		= $item['rules'].'|'.$rules_repeat;
						}
						$items['password']['rules'] = $rules;

						$item['field']		= $repeat;
						$item['rules']		= $rules_repeat;
						$item['label']		= 'Confirm '.$item['label'];
						$item['ignore']		= TRUE;

						$return				= array_slice($items, 0, $key_n+1, true) + array($item['field'] => $item) + array_slice($items, $key_n+1, count($items) - 1, true);
						break;
				}
			}
			$key_n++;
		}

		return $return;
	}

	/**
	  * Return JSON to table crud
	  *
	  * @param string $items_key Key to read off config
	  */
	function _ajax_table($items_key = 'table')
	{
		$model				= $this->model;
		if(empty($model))
		{
			return FALSE;
		}

		$items_table		= $this->_get_items($items_key);

		/*
		 * Paging
		 */
		$sOffset			= 0;
		$sPagesize			= 0;
		if(isset($_POST['iDisplayStart']) && $_POST['iDisplayLength'] != '-1')
		{
			$sOffset			= $_POST['iDisplayStart'];
			$sPagesize			= $_POST['iDisplayLength'];
		}

		/*
		 * Ordering
		 */
		$sOrder				= array();
		if(isset($_POST['iSortCol_0']))
		{
			for($i = 0; $i < intval($_POST['iSortingCols']); $i++)
			{
				if($_POST['bSortable_'.intval($_POST['iSortCol_'.$i])] == "true")
				{
					$value				= $_POST['sSortDir_'.$i];
					$index				= intval( $_POST['iSortCol_'.$i] );
					$name				= $items_table[$index];
					if(isset($name['alias']))
					{
						$sOrder[$name['alias']] = $value;
					} else {
						$sOrder[$name['field']] = $value;
					}

				}
			}
		}

		/*
		 * Filtering
		 * NOTE this does not match the built-in DataTables filtering which does it
		 * word by word on any field. It's possible to do here, but concerned about efficiency
		 * on very large tables, and MySQL's regex functionality is very limited
		 */
		$sLikeOR			= array();
		if(isset($_POST['sSearch']))
		{
			$SearchString		= $_POST['sSearch'];
		} else {
			$SearchString		= "";
		}
		if($SearchString != "")
		{
			foreach($items_table as $item_table)
			{
				if(!isset($item_table['search']) || $item_table['search'] !== FALSE)
				{
					$sLikeOR[$item_table['field']] = $SearchString;
				}
			}
		}

		$filter				= $this->_callback_filter();

		$TotalRecords		= $this->$model->read_table($items_table, array(), array(), 0, 0, TRUE, $filter);
		$DisplayRecords		= $this->$model->read_table($items_table, $sLikeOR, array(), 0, 0, TRUE, $filter);
		$data_table			= $this->$model->read_table($items_table, $sLikeOR, $sOrder, $sPagesize, $sOffset, FALSE, $filter);

		$aaData				= [];
		foreach($data_table as $rows)
		{
			if(method_exists($this, "_callback_previous_row"))
			{
				$this->_callback_previous_row($rows);
			}

			$row				= [];
			foreach($rows as $key => $item)
			{
				$ret_row			= $this->_callback_row($key, $item, $rows);
				if($ret_row !== NULL)
				{
					$row[]				= $ret_row;
				}
			}
			$aaData[]			= $row;
		}

		return [
			'sEcho'					=> intval($this->input->post('sEcho')),
			'iTotalRecords'			=> $TotalRecords,
			'iTotalDisplayRecords'	=> $DisplayRecords,
			'aaData'				=> $aaData
		];
	}

	/**
	  * This callback runs on query for table of the crud.
	  * Use to add where clause on the query
	  *
	  */
	function _callback_filter()
	{
	}

	/**
	  * This callback runs on each row. It escapes the auto column value and runs the callback.
	  * For this callback the return value is required and must be a string.
	  *
	  * @param string $key Name of column
	  * @param mixed $value Value
	  * @param array $row Array containing all row data
	  *
	  * @return string
	  */
	function _callback_row($key, $value, &$row)
	{
		return $value === NULL ? '' : $value;
	}
}
