<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * TKD Model Wrapper Class.
 *
 * @package		TKDModel
 * @author		Muhammad Uzair Khan (Muhammad.Uzair@tradekey.com)
 * @version		1.0
 * @since		Version 1.0 2014
 *
 * @ways_to_setup_fields:
 *
 *                    *****************HIDDEN PRIMARY****************
 *    	 				// Can define this attribute in construct
 *          			$this->relations = array(
 *          		        'model_job_categories_department'=>array('pk'=>'job_category_id' , 'search_attr'=>'department_id'),
 *          		    );
 *
 *
 *               	array(
 *                       'field'   => $this->_table.'[id]',
 *                       'name'   => 'id',
 *                       'label'   => 'id',
 *                       'primary'   => 'primary',
 *                       'type'   => 'hidden',
 *                       'attributes'   => array(),
 *                       'foreign_keys' => $this->relations, //Define relations somewhere
 *                       'js_rules'   => '',
 *                       'rules'   => 'trim'
 *                    ),
 *
 *                    *****************TEXT****************
 *
 * 	                array(
 *                       'field'   => $this->_table.'[dep_head]',
 *                       'name'   => 'dep_head',
 *                       'label'   => 'HoD ',
 *                       'type'   => 'text',
 *                       'attributes'   => array(),
 *                       'js_rules'   => 'required',
 *                       'rules'   => 'required|trim|htmlentities'
 *                    ),
 *
 *                    *****************EDITOR****************
 *                 array(
 *                       'field'   => $this->_table.'[dep_detail]',
 *                       'name'   => 'dep_detail',
 *                       'label'   => 'Detail Description',
 *                       'type'   => 'editor',
 *                       'attributes'   => array(),
 *                       'js_rules'   => '',
 *                       'rules'   => 'trim|htmlentities'
 *                    ),
 *
 *                    *****************SWITCH****************
 *                  array(
 *                       'field'   => $this->_table.'[status]',
 *                       'name'   => 'status',
 *                       'label'   => 'Status?',
 *                       'type'   => 'switch',
 *                       'default'   => '1',
 *                       'attributes'   => array(),
 *                       'rules'   => 'trim'
 *                    ),
 *
 *                    *****************AJAX POPULATE****************
 *                                   array(
 *                       'field'   => $this->_table.'[department_id]',
 *                       'name'   => 'department_id',
 *                       'label'   => 'Department',
 *                       'type'   => 'multiselect',
 *                       'list_data'    => $department_options,
 *                       'list_fields'    => array('value'=>"id","label"=>"dep_name"),
 *                       'relation_model' => '',
 *                       'multi_value' => false,
 *                       'attributes'   => array("class"=>" populate-ajax department",
 *                                                "additional" => 'data-model="section"  data-target=".section_id"  data-key="department"  data-action="department" '
 *                                              ),
 *                       'js_rules'   => 'required',
 *                       'rules'   => 'required|trim'
 *                    ),
 *
 *                array(
 *                       'field'   => $this->_table.'[section_id]',
 *                       'name'   => 'section_id',
 *                       'label'   => 'Section',
 *                       'type'   => 'multiselect',
 *                       'list_data'    => array(),
 *                       'list_fields'    => array('value'=>"id","label"=>"name"),
 *                       'multi_value' => false,
 *                       'attributes'   => array('class'=>'section_id'),
 *                       'js_rules'   => 'required',
 *                       'rules'   => 'required|trim'
 *                    ),
 *
 *                    *****************IMAGE****************
 * 	 			 array(
 *                       'field'   => $this->_table.'[image]',
 *                       'name'   => 'image',
 *                       'label'   => 'Image',
 *                       'name_path'   => 'image_path',
 *                       'upload_config'   => 'site_upload_emblem',  //DEFINE PATH IN CONFIG VARIABLE with key 'site_upload_emblem' OR whatever
 *                       'thumb'   => array(	//Thumb - optional
 *                                          array('name'=>'image_thumb','max_width'=>150, 'max_height'=>150),
 *                                      ),
 *                       'type'   => 'fileupload',
 *                       'randomize' => true,
 *                       'preview'   => 'true',
 *                       'attributes'   => array(),
 *                       'rules'   => 'trim|htmlentities'
 *                    ),
 *
 *                    *****************Fields with multi RELATIONAL DATA(Mapping , sort of)****************
 *					// IN MAIN MODEL , WHOSE CONTROLLER IS CALLED, add following in PK field:
 *                     'foreign_keys' => $this->relations,
 *
 * 	 				// Can define this attribute in construct
 *          			$this->relations = array(
 *          		        'model_job_categories_department'=>array('pk'=>'job_category_id' , 'search_attr'=>'department_id'),
 *          		    );
 *		
 *          		    // Define in get_fields():
 *          		    $dept_options = $this->model_department->find_all(array('status !='=>2),"id,dep_name");
 * 	        		 $related_data = $this->get_relateional_data();
 *
 * 	         	// Finally, provide field relations
 *              array(
 *                     'field'   =>  $this->_table.'[department_id]',
 *                     'name'   => 'department_id',
 *                     'label'   => 'Departments',
 *                     'type'   => 'multiselect',
 *                     'list_data'    => $dept_options,
 *                     'list_fields'    => array('value'=>"id","label"=>"dep_name"),
 *                     'related_data'  =>  $related_data,
 *                     'relation_type' => 'many_to_many',
 *                     'relation_model' => 'model_job_categories_department',
 *                     'multi_value' => true,
 *                     'attributes'   => array(),
 *                     'rules'   => 'required|trim'
 *                  ),
 *
 */

class MY_Model extends CI_Model {

	private static $instance;

	/**
	 * Constructor
	 */
	protected $layout_data = array();
	protected $layout;
	public $_attributes = array();

	public function __construct()
	{
		parent::__construct();
		if($this->uri_data['id'])
			$this->_id = intval($this->uri_data['id']);
	}
	
	public function get_rules()
	{
		$fields = $this->get_fields() ;
		if(is_array($fields))
			foreach($fields AS $key=>$field)
			{
				$rules[$key]['field'] = $field['field'];
				$rules[$key]['label'] = $field['label'];
				$rules[$key]['rules'] = $field['rules'];
			}
		return $rules;
		
	}
	
	public function find_by_pk($id=0)
	{
		return $this->find_one(array("id"=>intval($id)));
	}
	
	public function find_all_active($params=array())
	{
		$params['where']['status'] = 1 ;
		return $this->find_all($params); 
	}

	public function find_all_list($params = array() , $field )
	{
		$find_all_rs = $this->find_all($params);
		if($params['return_count'])
			$resultset = $find_all_rs[data];
		else
			$resultset = $find_all_rs;

		foreach ($resultset as $key => $value) {
			if($value['id'])
				$resultant[$value['id']] = $value[$field];
			else
				$resultant[] = $value[$field];
		}
		if($params['return_count'])
			return array("count"=>$find_all_rs['count'] , "data"=>$resultant);
		else
			return $resultant;
	}

	public function find_all_list_active($params = array() , $field )
	{
		$params['where']['status'] = 1 ;
		return $this->find_all_list($params,$field); 
	}

	public function find_all_list_grouping($params = array() , $field )
	{
		$params['where']['status'] = 1 ;
		$list = $this->find_all_list($params,$field); 
		foreach ($list as $key => $value) {
			$return_list[$value][] = $key;
		}
		return $return_list;
	}

	public function find_all_grouping($params = array() , $group_field = "" , $key_field = "" , $value_field = ""  )
	{
		$params['where']['status'] = 1 ;
		$list = $this->find_all($params); 

		foreach ($list as $key => $data) {

			$value = $value_field ? $data[$value_field] : $data ;
			
			if($key_field)
				$return_list[$data[$group_field]][$data[$key_field]] = $value;
			else	
				$return_list[$data[$group_field]][] = $value;
		}
		return $return_list;
	}

	public function find_all($params=array())
	{
		extract($params);
		if(count($where))
			$this->db->where($where);
		if(count($having))
			$this->db->having($having);
		if(count($where_like))
			$this->db->like($where_like);
		if(count($or_where))
			$this->db->or_where($or_where);
		if(trim($where_string))
			$this->db->where($where_string);
		
		if($return_count)
            $fields = "SQL_CALC_FOUND_ROWS " . ($fields ? $fields : "*")  ;
		if($fields)
			$this->db->select($fields,FALSE);
		if($offset!="" && $limit!="")
			$this->db->limit($limit,$offset);
		if($order!="" )
			$this->db->order_by($order);
		if($group!="" )
			$this->db->group_by($group);
		if(count($joins))
		{
			foreach ($joins as $join) {
				$this->db->join($join['table'],$join['joint'],$join['type']);
			}
		}
		if($limit!="")
			$this->db->limit($limit);
		
		$result = $this->db->get($this->_table)->result_array();

		if($return_count)
        {
        	$query = $this->db->query('SELECT FOUND_ROWS() AS counter');
            $return["count"] = $query->row()->counter;       
            $return['data'] = $result ;
            return $return;
        }
		return $result;
	}

	public function update_model($where=array(),$data=array(),$addition_wheres=array())
	{
		extract($addition_wheres);

		if(!$where && !$where_like && !$or_where && !$where_string )
			return false;
		
		if(count($where))
			$this->db->where($where);
		if(count($where_like))
			$this->db->like($where_like);
		if(count($or_where))
			$this->db->or_where($or_where);
		if(trim($where_string))
			$this->db->where($where_string);

		$this->db->update($this->_table, $data);
		return $this->db->affected_rows();
		
	}

	public function find_one($where = array() , $params=array())
	{
		if($params['where'] && $where)
			unset($params['where']);
		extract($params);
		if(count($where))
			$this->db->where($where);
		if(count($having))
			$this->db->having($having);
		if(count($or_where))
			$this->db->or_where($or_where);
		if(trim($where_string))
			$this->db->where($where_string);
		
		if($fields)
			$this->db->select($fields,FALSE);
		if($order!="" )
			$this->db->order_by($order);
		if($group!="" )
			$this->db->group_by($group);
		if(count($joins))
		{
			foreach ($joins as $join) {
				$this->db->join($join['table'],$join['joint'],$join['type']);
			}
		}
		
		$result = $this->db->get($this->_table,1,0)->row_array();

		return $result;
	}

	/*
	*
	* @params: where=>array, fields=>string, group=>string, order->string , joins->array,, 
	*
	**/
    public function pagination_query($params= array())
    {
    	$params['where'] = $params['where'] ? $params['where'] : ($this->pagination_params['where'] ? $this->pagination_params['where'] : "*") ;
    	$params['fields'] = $params['fields'] ? $params['fields'] : $this->pagination_params['fields'] ? $this->pagination_params['fields'] : "*" ;
    	$params['group'] = $params['group'] ? $params['group'] : $this->pagination_params['group'] ;
    	$params['order'] = $params['order'] ? $params['order'] : $this->pagination_params['order'] ;
    	$params['joins'] = $params['joins'] ? $params['joins'] : $this->pagination_params['joins'] ;
    	$params['return_count'] = true ;
        $params['offset'] = intval($_GET['iDisplayStart']) ; 
    	$params['limit'] = intval($_GET['iDisplayLength']) ? intval($_GET['iDisplayLength']) : $this->_per_page ;
    	//For fields that are honored to allow search from datatables
    	//Create LIKE string for them
    	if(is_array($this->pagination_params['searchable']) && count($this->pagination_params['searchable']) && trim($_GET['sSearch']))
    	{
    		foreach ($this->pagination_params['searchable'] as $searchable) {
    			$like_strings[] = $searchable." LIKE '%".trim(mysql_real_escape_string($_GET['sSearch']))."%'";
    		}
    		$params['where_string'] = "(".implode(" OR ", $like_strings).")";
    	}
    	return $this->find_all($params);
    }
	
	/*
	*
	* @params: where=>array, fields=>string, group=>string, order->string , joins->array,, 
	*
	**/
    public function single_pagination_query($params= array())
    {
    	$params['where'] = $params['where'] ? $params['where'] : ($this->pagination_params['where'] ? $this->pagination_params['where'] : "*") ;
    	$params['fields'] = $params['fields'] ? $params['fields'] : $this->pagination_params['fields'] ? $this->pagination_params['fields'] : "*" ;
    	$params['group'] = $params['group'] ? $params['group'] : $this->pagination_params['group'] ;
    	$params['order'] = $params['order'] ? $params['order'] : $this->pagination_params['order'] ;
    	$params['joins'] = $params['joins'] ? $params['joins'] : $this->pagination_params['joins'] ;
    	$params['return_count'] = true ;
        $params['offset'] = intval($_GET['iDisplayStart']) ; 
    	$params['limit'] = intval($_GET['iDisplayLength']) ? intval($_GET['iDisplayLength']) : $this->_per_page ;
    	//For fields that are honored to allow search from datatables
    	//Create LIKE string for them
    	if(is_array($this->pagination_params['searchable']) && count($this->pagination_params['searchable']) && trim($_GET['sSearch']))
    	{
    		foreach ($this->pagination_params['searchable'] as $searchable) {
    			$like_strings[] = $searchable." LIKE '%".trim(mysql_real_escape_string($_GET['sSearch']))."%'";
    		}
    		$params['where_string'] = "(".implode(" OR ", $like_strings).")";
    	}
    	return $this->find_one($params['where'] , $params);
    }
	
	public function find_one_d_array($where=array(),$fields=array())
	{
		if(count($where))
			$this->db->where($where);
		$result = $this->db->get($this->_table)->result();
		if(is_array($result)){
			foreach ($result as $row) {
				$resultant[$row[$fields['key']]] = $row[$fields['value']];
			}
		}
		return $resultant;
	}

	public function insert_record($record=array())
	{
		if(count($record))
		{
			$insertion = $this->db->insert($this->_table,$record);
			$insert_id = $this->db->insert_id();
			// Sometimes, like in case of Composite key, InsertId is not returned.
			return $insert_id ? $insert_id : ($insertion ? $insertion : false);
		}
		else
			return false;

	}
	
	public function delete_record($where=array())
	{
		if(count($where))
		{
			$this->db->where($where);
			$this->db->delete($this->_table);
			return $this->db->affected_rows();
		}
		else
			return false;

	}
	
    public function save()
	{
		$fields = $this->get_fields();
		$user_data = $this->_attributes ;
		foreach($fields AS $fld)
		{
			if($fld['primary']=='primary')
			{
				$fkeys = $fld['foreign_keys'] ? $fld['foreign_keys'] : $this->relations ;
				if(intval($user_data[$fld['name']])>0)
				{
					$insert_id = $user_data[$fld['name']];
					$old_data = $this->find_one(array('id' => $insert_id));
					//SET WHERE CLAUSE FOR UPDATE QUERY. NO OTHER QUERY MUST RUN BEFORE IT.
					$this->db->where('id', $insert_id);
					$mode = "update";
				}
				else {
					$mode = "insert";
					//Dont add this premium key in $record
					continue;
				}
				
			}

			// Skipping for default value incase it's an insert and user did not set any value for it.
			if(!isset($user_data[$fld['name']]) && $mode == "insert")
				continue;

			if($fld['relation_type'])
			{
				switch($fld['relation_type'])
				{
					case "many_to_many":
						$model = $fld['relation_model'];
						if(is_array($user_data[$fld['name']]))
						{
							foreach ($user_data[$fld['name']]  as $key => $val) {
								$many_to_many_data[$model][$key][$fld['name']] = $val ;
							}
						}

					break;
					case "one_to_many":
					break;
				}

				continue; //Awesomely, Skip remaining flow for this iteration
			}

			switch ($fld['type']) {
				case 'fileupload':
					$random_suffix = "";
					$filename = $_FILES[$this->_table]['name'][$fld['name']] . $random_suffix ;
					if($fld['randomize'])
					{
						$ext = pathinfo($_FILES[$this->_table]['name'][$fld['name']], PATHINFO_EXTENSION);
						$filename = str_replace(".$ext", "", $filename);
						$filename .= time().rand(10,99).".".$ext;
					}

					if($this->config->config[$fld['upload_config']])
						$destination_path = $this->config->config[$fld['upload_config']] ;
					else
						$destination_path = $this->config->config['site_uploads_default'] ;
							
					$destination = $destination_path .$filename ;
					if(is_array($_FILES) && count($_FILES) && $filename)
					{
						if(!is_dir($destination_path))
							pre("ERROR: Folder not found:".$destination_path);
						if(move_uploaded_file($_FILES[$this->_table] ['tmp_name'] [$fld['name']] , $destination))
						{
							$old_file = $old_data[$fld['name']];
							$record[$fld['name']] = $filename ;
							$record[$fld['name_path']] = $destination_path ;
							if(array_filled($fld['thumb']))
							{
								foreach ($fld['thumb'] as $key => $thumb) {
									# code...
									$thumb['upload_path'] = $destination_path;
									$thumb['filename'] = $filename;
									$thumb['thumb_no'] = count($fld['thumb'])>1 ? ($key+1) : "";
									$thumb['old_file'] = $old_data[$thumb['name']];
									$record[$thumb['name']] = create_thumbnail($thumb);
								}
							}
							
							if($old_file != $filename && is_file(($destination_path . $old_file)))
								unlink($destination_path . $old_file);
						}
					}
					continue; //Awesomely, Skip remaining flow for this iteration
				break;
				case 'switch':
					$record[$fld['name']] = intval($user_data[$fld['name']]);
				break;
				default:
					if(($user_data[$fld['name']] !== null))
						$record[$fld['name']] = $user_data[$fld['name']];
				break;
			}
			
			if($fld['index']=='foreign')
			{
				$record[$fld['name']] = isset($record[$fld['name']]) ? $record[$fld['name']] :  $_POST['indices']['pk'][$fld['relation']];
			}
			
		}
		if($mode)
		{	
			if($this->db->$mode($this->_table,$record))
			{
				$insert_id = intval($insert_id) ? intval($insert_id) : $this->db->insert_id();
				if($insert_id && is_array($many_to_many_data) && count($many_to_many_data))
				{

					foreach ($many_to_many_data as $model => $mdata) {
						$this->load->model($model);
						$where = array();
						$where[ $fkeys[$model]['pk'] ] = $insert_id ; 
						$this->$model->delete($where);
						foreach ($mdata as $dt) {
							# code...
							$dt[ $fkeys[$model]['pk'] ] = $insert_id ; 
							$this->$model->set_attributes($dt);
							$this->$model->save();
						}
					}
				}
			}
			else {
				pre("$mode failed for {$this->_table}");
			}
		}
		else {
			pre("No PK set for ".$this->_table." in get_fields function in model");
		}
		$_POST['indices']['pk'][$this->_table] = $insert_id;
		return $insert_id;
	}

	public function get_relateional_data()
	{
		$resultant = array();
		foreach ($this->relations as $model => $key) {
			$this->load->model($model);
			$params['where'] = array($key['pk'] => $this->_id) ;
			$params['fields'] = $key['search_attr'] ;
			$resultant[$model] = $this->$model->find_all($params);
		}
		return $resultant;
	}

	/*DELETE*/
	public function delete($where=array())
	{
		if(is_array($where) && count($where))
  			$this->db->delete($this->_table,$where);
  		return $this->db->affected_rows(); 
	}

	/*SET Attributes that will be used for insert or update*/
	public function set_attributes($data)
	{
		$this->_attributes = $data;
	}
	

}
// END Model class

/* End of file Model.php */
/* Location: ./system/core/Model.php */