<?php

class Model {

    protected static $db = null;
    private static $column;

    public function __construct()
    {
        $this->initDatabase();
    }
    public static function initDatabase(){
        if(!Model::$db){
            try {
                /*
                 * Init connection to the DB
                 */
                Model::$db = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PASSWORD);
                Model::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            } catch(Exception $e){
                die($e);
            }
        }
    }
    /*
     * Fetch
     */
    public static function fetch($filters = []): array
    {
        $query = 'SELECT * FROM ' . get_called_class();
        $args = [];
        $c = 0;
        $output = [];
        $_col = get_called_class()::getColumns();
        forEach($filters as $filter){
            if (is_array($filter) && count($filter) === 3 && array_key_exists($filter[0], $_col) && in_array($filter[1], ['=','<','>','<>','LIKE'])){
                if($c === 0){
                    $query .= ' WHERE';
                }else{
                    $query .= ' AND';
                }
                $query .= ' ' . $filter[0] . ' ' . $filter[1] . ' ?';
                $args[] = $filter[2];
            }else{
                throw new Exception('Invalid SQL filters');
            }
            $c++;
        }
        $q = Model::$db->prepare($query);
        $q->execute($args);
        $d = $q->fetchAll(PDO::FETCH_ASSOC);
        forEach($d as $row){
            $class=get_called_class();
            $output[] = new $class($row);
        }
        return $output;
    }

    /*
     * Insert
     */
    public static function insert($data){
        $query = 'INSERT INTO ' . get_called_class() . ' (';
        $_col = get_called_class()::getColumns();
        $c = 0;
        $args = [];
        if($data !== null){
            forEach($data as $key=>$value){
                if(!key_exists($key, $_col)){
                    throw new Exception('Invalid data entry: ' . $key);
                }else{
                    $args[] = $value;
                    if($c+1 === sizeof($data)){
                        $query .= $key . ') VALUES ( ' . join(',',array_fill(0, sizeof($data), '?')) . ' );';
                    }else{
                        $query .= $key . ', ';
                    }
                    $c++;
                }
            }
            $q = Model::$db->prepare($query);
            return ($q->execute($args) == true);
        }
        return false;
    }
    /*
     * Update
     */
    public static function update($data,$filters = []){
        $query = 'UPDATE ' . get_called_class() . ' SET ';
        $_col = get_called_class()::getColumns();
        $c = $z = 0;
        $args = [];
        if($data !== null){
            forEach($data as $key=>$value){
                if(!key_exists($key, $_col)){
                    throw new Exception('Invalid data entry: ' . $key);
                }else{
                    $args[] = $value;
                    if($c+1 === sizeof($data)){
                        $query .= $key . ' = ?';
                    }else{
                        $query .= $key . ' = ?, ';
                    }
                    $c++;
                }
            }
            forEach($filters as $filter){
                if (is_array($filter) && count($filter) === 3 && array_key_exists($filter[0], $_col) && in_array($filter[1], ['=','<','>','<>','LIKE'])){
                    if($z === 0){
                        $query .= ' WHERE';
                    }else{
                        $query .= ' AND';
                    }
                    $query .= ' ' . $filter[0] . ' ' . $filter[1] . ' ?';
                    $args[] = $filter[2];
                }else{
                    throw new Exception('Invalid SQL filters');
                }
                $z++;
            }
            $q = Model::$db->prepare($query);
            return ($q->execute($args) == true);
        }
        return false;
    }

    /*
     * DELETE
     */
    public static function delete($filters = []): bool
    {
        $query = 'DELETE FROM ' . get_called_class();
        $args = [];
        $c = 0;
        $output = [];
        $_col = get_called_class()::getColumns();
        forEach($filters as $filter){
            if (is_array($filter) && count($filter) === 3 && array_key_exists($filter[0], $_col) && in_array($filter[1], ['=','<','>','<>','LIKE'])){
                if($c === 0){
                    $query .= ' WHERE';
                }else{
                    $query .= ' AND';
                }
                $query .= ' ' . $filter[0] . ' ' . $filter[1] . ' ?';
                $args[] = $filter[2];
            }else{
                throw new Exception('Invalid SQL filters');
            }
            $c++;
        }
        $q = Model::$db->prepare($query);
        return ($q->execute($args) == true);
    }

    protected function getColumns(): array
    {
        if(!isset(get_called_class()::$column[get_called_class()])) {
            get_called_class()::$column[get_called_class()] = [];
            $q = Model::$db->prepare('SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ?');
            $q->execute(array(get_called_class()));
            $d = $q->fetchAll(PDO::FETCH_ASSOC);
            $out = [];
            foreach ($d as $col) {
                $out[$col['COLUMN_NAME']] = $col;
            }
            get_called_class()::$column[get_called_class()] = $out;
        }
        return get_called_class()::$column[get_called_class()];
    }
}
/*
 * Load our models
 */
foreach (glob(MODELS_PATH . '/*.php') as $filename)
{
    require_once $filename;
}