<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class DynamicModel extends CI_Model {

    protected $table;
    protected $column_order = [];
    protected $column_search = [];
    protected $order = [];

    public function setTable($table)
    {
        $this->table = $table;
        return $this;
    }

    public function setColumn($order = [], $search = [], $default_order = [])
    {
        $this->column_order  = $order;
        $this->column_search = $search;
        $this->order         = $default_order;
        return $this;
    }

    // =========================
    // BASE QUERY (DATATABLE)
    // =========================
    private function _get_datatables_query()
    {
        $this->db->from($this->table);

        // SEARCH
        if (!empty($_POST['search']['value'])) {
            $this->db->group_start();
            foreach ($this->column_search as $i => $item) {
                if ($i === 0) {
                    $this->db->like($item, $_POST['search']['value']);
                } else {
                    $this->db->or_like($item, $_POST['search']['value']);
                }
            }
            $this->db->group_end();
        }

        // ORDER
        if (isset($_POST['order'])) {
            $col = $_POST['order'][0]['column'];
            $dir = $_POST['order'][0]['dir'];

            if (isset($this->column_order[$col])) {
                $this->db->order_by($this->column_order[$col], $dir);
            }
        } elseif (!empty($this->order)) {
            foreach ($this->order as $key => $val) {
                $this->db->order_by($key, $val);
            }
        }
    }

    // =========================
    // DATATABLE GET
    // =========================
    public function get_datatables()
    {
        $this->_get_datatables_query();

        if ($_POST['length'] != -1) {
            $this->db->limit($_POST['length'], $_POST['start']);
        }

        return $this->db->get()->result();
    }

    public function count_filtered()
    {
        $this->_get_datatables_query();
        return $this->db->count_all_results();
    }

    public function count_all()
    {
        return $this->db->count_all($this->table);
    }

    // =========================
    // CRUD BASIC
    // =========================

    public function get_all($orderBy = null, $direction = 'ASC')
    {
        if ($orderBy) {
            $this->db->order_by($orderBy, $direction);
        }
        return $this->db->get($this->table)->result();
    }

    public function get_by_id($id, $pk = 'id')
    {
        return $this->db->where($pk, $id)->get($this->table)->row();
    }

    public function get_where($where = [])
    {
        return $this->db->where($where)->get($this->table)->result();
    }

    public function insert($data)
    {
        $this->db->insert($this->table, $data);
        return $this->db->insert_id();
    }

    public function insert_batch($data)
    {
        return $this->db->insert_batch($this->table, $data);
    }

    public function update($id, $data, $pk = 'id')
    {
        return $this->db->where($pk, $id)->update($this->table, $data);
    }

    public function update_where($where, $data)
    {
        return $this->db->where($where)->update($this->table, $data);
    }

    public function delete($id, $pk = 'id')
    {
        return $this->db->where($pk, $id)->delete($this->table);
    }

    public function delete_where($where)
    {
        return $this->db->where($where)->delete($this->table);
    }

    // =========================
    // ADVANCED QUERY
    // =========================

    public function join($table, $on, $type = 'left')
    {
        $this->db->join($table, $on, $type);
        return $this;
    }

    public function where($where)
    {
        $this->db->where($where);
        return $this;
    }

    public function like($field, $match)
    {
        $this->db->like($field, $match);
        return $this;
    }

    public function order_by($field, $direction = 'ASC')
    {
        $this->db->order_by($field, $direction);
        return $this;
    }

    public function limit($limit, $offset = 0)
    {
        $this->db->limit($limit, $offset);
        return $this;
    }

    public function get()
    {
        return $this->db->get($this->table)->result();
    }

    public function first()
    {
        return $this->db->get($this->table)->row();
    }

    public function query($sql, $binds = null)
    {
        return $this->db->query($sql, $binds)->result();
    }

    public function find($id, $pk = 'id')
    {
        return $this->db->where($pk, $id)->get($this->table)->row();
    }
}