<?php
namespace WpBookingEvent\Mvc\Model;

use Exception;
use WpBookingEvent\Factory;
use WpBookingEvent\Language\Text;
use WpBookingEvent\Utilities\Utility;
use WpBookingEvent\Form\Form;
use WpBookingEvent\Filesystem\Path;
use WpBookingEvent\Object\CMSObject;
use WpBookingEvent\FOFInput\FOFInput;

class Model extends BaseDatabaseModel
{
    public $model = "";
    public $modelItem = "";
    public $modelList = "";
    public $state = "";
    public $context = "";
    public $table_name = null;
    public $__state_set = null;
    public static $instance = array();
    public $key_table = "id";
    public $_errors = array();
    public $db = null;
    private $filter_fields=array();

    public function __construct($config = array())
    {
        if (!$this->context) {
            echo ('PUBLIC_VAR_CONTEXT_THIS_MODEL_CANNOT_NULL_PLEASE_DEFINE_IT_IN_CLASS'.get_called_class().'PLEASE_SEE_OTHER_MODEL_IN_NEBASE_APP');
            die;
        }

        if (!$this->table_name) {
            echo ('PUBLIC_VAR_CONTEXT_THIS_MODEL_CANNOT_NULL_PLEASE_DEFINE_IT_IN_CLASS'.get_called_class().'PLEASE_SEE_OTHER_MODEL_IN_NEBASE_APP');
            die;
        }
        $this->state = new CMSObject();
        $this->_db = Factory::getDBO();
        $this->db = Factory::getDBO();
    }

    public function buildQuery()
    {

    }
    public function duplicate($id){
        $table=$this->getTable();
        $table->load($id);
        $table->{$this->key_table}=0;
        if($table->store())
        {
            return (object)$table->getProperties();
        }
        return false;
    }

    public function getModel($model = "")
    {
        if (!$model) {
            $model = $this->model;
        }
        $Ucfmodel = ucfirst($model);
        $model_path = WPBOOKINGEVENT_APP_PATH . "/models/$Ucfmodel.php";
        if (file_exists($model_path)) {
            require_once $model_path;
            $model_name = "{$model}Model";
            $model_class = Model::getInstance($model);
            $model_class->model = $model;
            return $model_class;
        } else {
            throw new Exception(Text::_("Error model <b>$model_path</b> not exits, please create first"));
        }

    }

    public function getModelItem($model = "")
    {
        if (!$model) {
            $model = $this->modelItem;
        }
        if (!$model) {

            throw new Exception(Text::_("please defined publish var modelItem in file " . get_called_class()));
        }
        $model_path = WPBOOKINGEVENT_APP_PATH . "/models/$model.php";
        if (file_exists($model_path)  && !class_exists("{$model}Model")) {
            $model_name = "{$model}Model";
            $model_class = Model::getInstance($model);
            $model_class->model = $model;
            return $model_class;
        } else {
            throw new Exception(Text::_("Error model <b>$model_path</b> not exits, please create first"));
        }

    }

    public function getModelList($model = "")
    {
        if (!$model) {
            $model = $this->modelList;
        }
        $model_path = WPBOOKINGEVENT_APP_PATH . "/models/$model.php";
        if (file_exists($model_path)) {
            require_once $model_path;
            $model_name = "{$model}Model";
            $model_class = Model::getInstance($model);
            $model_class->model = $model;
            return $model_class;
        } else {
            throw new Exception(Text::_("Error model <b>$model_path</b> not exits, please create first"));
        }

    }

    /**
     * Method to get model state variables
     *
     * @param string $property Optional parameter name
     * @param mixed $default Optional default value
     *
     * @return  mixed  The property where specified, the state object where omitted
     *
     * @since   3.0
     */
    public function getState($property = null, $default = null)
    {

        if (!$this->__state_set) {
            // Protected method to auto-populate the model state.
            $this->populateState();

            // Set the model state set flag to true.
            $this->__state_set = true;
        }

        return $property === null ? $this->state : $this->state->get($property, $default);
    }

    public function setState($property, $value = null)
    {
        return $this->state->set($property, $value);
    }

    /**
     * Method to auto-populate the model state.
     *
     * This method should only be called once per instantiation and is designed
     * to be called on the first call to the getState() method unless the model
     * configuration flag to ignore the request is set.
     *
     * Note. Calling getState in this method will result in recursion.
     *
     * @param string $ordering An optional ordering field.
     * @param string $direction An optional direction (asc|desc).
     *
     * @return  void
     *
     * @since   1.6
     */
    protected function populateState($ordering = null, $direction = null)
    {


    }


    public static function getInstance($model, $prefix = '', $config = array()):Model
    {
        $model = preg_replace('/[^A-Z0-9_\.-]/i', '', $model);
        $model = ucfirst($model);
        $model_path = WPBOOKINGEVENT_APP_PATH . "/models/{$model}Model.php";

        if (file_exists($model_path)) {
            if (!array_key_exists($model, self::$instance)) {
                if(strpos(WPBOOKINGEVENT_APP_PATH,"admin/app")!==false){
                    $class_name = "WpBookingEventAdmin\\app\\models\\{$model}Model";
                }else{
                    $class_name = "WpBookingEventFrontend\\app\\models\\{$model}Model";
                }


                self::$instance[$model] = new $class_name();
                self::$instance[$model]->model = $model;
            }

        } else {
            throw new Exception(Text::_("can not found model:" . Utility::get_short_file_by_path($model_path) . ',please create it'));
        }
        return self::$instance[$model];
    }

    protected static function _createFileName($type, $parts = array())
    {
        $filename = '';

        switch ($type) {
            case 'model':
                $filename = strtolower($parts['name']) . '.php';
                break;
        }

        return $filename;
    }

    public static function addIncludePath($path = '', $prefix = 'Model')
    {
        static $paths;

        if (!isset($paths)) {
            $paths = array();
        }

        if (!isset($paths[$prefix])) {
            $paths[$prefix] = array();
        }

        if (!isset($paths[''])) {
            $paths[''] = array();
        }

        if (!empty($path)) {

            foreach ((array)$path as $includePath) {
                if (!in_array($includePath, $paths[$prefix])) {
                    array_unshift($paths[$prefix], Path::clean($includePath));
                }

                if (!in_array($includePath, $paths[''])) {
                    array_unshift($paths[''], Path::clean($includePath));
                }
            }
        }

        return $paths[$prefix];
    }

    public function getName()
    {
        return $this->model;
    }

    public function getHeader()
    {

        $db = Factory::getDBO();
        $fields = $db->getTableColumns(self::getTableName());
        $list = array_keys($fields);
        return $list;


    }

    public function getForm($data = array(), $loadData = true)
    {


        // Get the form.
        $form = $this->loadForm($this->model, array('control' => 'jform', 'load_data' => $loadData));

        if (empty($form)) {
            return false;
        }
        return $form;
    }


    protected function loadForm($source = null, $options = array(), $clear = false, $xpath = false)
    {
        Form::addFieldPath(__DIR__ . '/../../form/fields');
        Form::addFormPath(WPBOOKINGEVENT_APP_PATH . '/models/forms');
        Form::addFieldPath(WPBOOKINGEVENT_APP_PATH . '/models/fields');
        try {
            $form = Form::getInstance($source, $options, false, $xpath);
            if (isset($options['load_data']) && $options['load_data']) {
                // Get the data for the form.
                $data = $this->loadFormData();
            } else {
                $data = array();
            }


            // Load the data into the form after the plugins have operated.
            $form->bind($data);
        } catch (\Exception $e) {
            $this->setError($e->getMessage());

            return false;
        }


        return $form;
    }

    public function delete($id)
    {
        $table = $this->getTable();


        if ($table->delete($id)) {
            return true;
        }
        return false;
    }

    public function save($data)
    {
        $table = $this->getTable();


        if ($table->save($data)) {
            return $table->getProperties();
        }
        return false;
    }

    protected function loadFormData()
    {
        return array();
    }

    public function setError($error)
    {
        $this->_errors[] = $error;
    }

    public function getItem($id = 0)
    {

        $db = Factory::getDBO();

        $query = $db->getQuery(true)
            ->select("*")
            ->from($this->getTableName())
            ->where("{$this->key_table}=" . (int)$id);
        return $db->setQuery($query)->loadObject();
    }

    public function getTableName($table = "")
    {
        if (!$table) {
            $table = $this->table_name;
        }
        return WPBOOKINGEVENT_PREFIX_TABLE . "$table";
    }

    public function setTableName($table)
    {
        $this->table_name = $table;
    }

    public function getTable($table = "", $prefix = 'Table', $options = array())
    {
        if (!$table) {
            $table = $this->table_name;
        }
        $UCFtable = ucfirst($table);
        $table_path = WPBOOKINGEVENT_APP_BACKEND_PATH . "/tables/{$UCFtable}Table.php";
        if (file_exists($table_path)) {
            $table_name = "WpBookingEventAdmin\\app\\tables\\{$UCFtable}Table";
            $db = Factory::getDBO();
            $table_class = new $table_name($this->getTableName($table), 'id', $db);

            return $table_class;
        } else {
            throw new Exception(Text::_("Error: table <b>" . Utility::get_short_file_by_path($table_path) . "</b> not exits,plese create it first"));
        }
    }

    public function getList()
    {

        $db = Factory::getDBO();
        $query = $db->getQuery(true)
            ->select("*")
            ->from(self::getTableName());
        $limit_per_page=$this->get_limit_per_page();
        return $db->setQuery($query,0,$limit_per_page)->loadObjectList();

    }
    public function getArrayList()
    {

        $db = Factory::getDBO();
        $query = $db->getQuery(true)
            ->select("*")
            ->from(self::getTableName());
        $limit_per_page=$this->get_limit_per_page();
        return $db->setQuery($query,0,$limit_per_page)->loadRowList();

    }
    public function get_limit_per_page()
    {
        $appConfig=Factory::getAppConfig();
        return $appConfig->get('limit_per_page',20000);
    }

    //them phan service
    public function savelist()
    {

        if ($this->input->post('list')) {
            $this->do_update($this->input->post('list'));
        }
    }

    public function do_update($list, $parent_id = 0, &$m_order = 0)
    {

        foreach ($list as $item) {

            $m_order++;
            $data = array(
                'parent_id' => $parent_id,
                'm_order' => $m_order,
            );
            if ($parent_id != $item['id']) {

                $where = array('id' => $item['id']);
                var_dump($data . ':' . $where);
                $this->db->where($where);
                $this->db->update('nav', $data);
            }
            if (array_key_exists("children", $item)) {
                $this->do_update($item["children"], $item["id"], $m_order);
            }
        }
    }
    //het them
}
