<?php

class Model {
    public $data;
    public $id = false;
    public $redis;

    function __construct()
    {
        //redis
        if ($GLOBALS['redis'])
            $this->redis = $GLOBALS['redis'];
    }

    /**
     * Magic getter function
     *
     * @param $name Variable name
     *
     * @return mixed
     */
    public function __get($name)
    {
        if (isset($this->data[$name]))
            return $this->data[$name];
    }

    /**
     * Magic setter function
     *
     * @return mixed
     */
    public function __set($name, $value)
    {
        $this->data[$name] = $value;
    }

    public function getDBFields()
    {
        return $this->dbFields;
    }

    /**
     * Returns all data fields but removes filtered datapoints like passwords, etc
     */
    public function getDataFiltered()
    {
        $data = $this->data;
        if(is_array($this->hidden))
            foreach($this->hidden as $secretfield)
                unset($data[$secretfield]);
        foreach($this->dbFields as $field=>$options)
            if($options['type']=='csv')
                $data[$field] = ($data[$field]?explode(';',$data[$field]):[]);
        return $data;
    }

    public function save()
    {
        if (!$this->validate())
            return false;
        foreach($this->dbFields as $field=>$options)
        {
            if(isset($this->data[$field]))
                $this->redis->hset($this->dbTable.':'.$this->id,$field,$this->data[$field]);
        }
    }

    public function load($id)
    {
        $this->id = $id;
        if(!$this->redis->exists($this->dbTable.':'.$this->id))
            return false;
        $keys = array_keys($this->dbFields);

        foreach($keys as $key)
        {
            $value = $this->redis->hget($this->dbTable.':'.$this->id,$key);

            if($value!==NULL) //we'll leave null values
            switch($this->dbFields[$key]['type'])
            {
                case 'int': $value = intval($value);break;
                case 'bool': $value = boolval($value);break;
                case 'float': $value = floatval($value);break;
                case 'double': $value = doubleval($value);break;
            }
            $this->data[$key] = $value;
        }

        return true;
    }

    /**
     * @param array $data
     */
    private function validate()
    {
        if (!$this->dbFields)
            return true;

        $data = $this->data;

        foreach ($this->dbFields as $key => $options) {
            $type = null;
            $required = false;
            
            if(in_array('autoupdate',$options))
                $this->data[$key] = NULL;

            if (isset($data[$key]))
                $value = $data[$key];
            else
                $value = null;
            
            if (is_array($value))
                continue;

            if (isset($desc[0]))
                $type = $desc[0];
            if (in_array('required',$options))
                $required = true;

            if($value===null && $options['autoValMethod'])
            {
                if(method_exists($this,$options['autoValMethod']))
                    $value = $this->{$options['autoValMethod']}();
                else if(function_exists($options['autoValMethod']))
                    $value = $options['autoValMethod']();
                else
                    $value = null;
                $this->data[$key] = $value;
            }

            if($options['default']!==null && $value===null)
                $value = $options['default'];

            if ($required && strlen($value) == 0) {
                throw new Exception($this->dbTable . "." . $key . " is required");
            }
            if ($value == null)
                continue;

            switch ($type) {
                case 'email':
                    $regexp = null;
                    if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                        throw new Exception("$type validation failed");
                    }
                break;
                case 'csv':
                case "text":
                    $regexp = null;
                    break;
                case "int":
                    $regexp = "/^[0-9]*$/";
                    break;
                case "double":
                    $regexp = "/^[0-9\.]*$/";
                    break;
                case "bool":
                    $regexp = '/^(yes|no|0|1|true|false)$/i';
                    break;
                case "datetime":
                    $regexp = "/^[0-9a-zA-Z -:]*$/";
                    break;
                default:
                    $regexp = $type;
                    break;
            }
            if (!$regexp)
                continue;

            if (!preg_match($regexp, $value)) {
                throw new Exception("$type validation failed");
            }
        }
        return true;
    }

    function delete()
    {
        return $this->redis->del($this->dbTable.':'.$this->id);
    }

    function gen_shorthash(){
        return substr(uniqid(),-7);
    }

    function getDateTime($time=false)
    {
        return date('Y-m-d H:i:s',($time?$time:time()));
    }
}