<?php

namespace apexl\Vault\operators;
use apexl\Vault\interfaces\operators;

abstract class pdo implements operators {

    protected $database;
    protected $host;
    protected $user;
    protected $pass;
    protected $schema;

    protected $sql = '';
    protected $queryFields = [];
    protected $table; //The current primary table

    protected $options;
    protected $statement;
    protected $connectionDetails;
    public $statementError;

    /** @var PDO */
    protected $pdo;

    public function __construct($connectionDetails)
    {
        $this->connectionDetails = $connectionDetails;
        $this->setHost($connectionDetails->dbhost ?? '')
            ->setDatabase($connectionDetails->dbname ?? '')
            ->setUser($connectionDetails->dbuser ?? '')
            ->setPass($connectionDetails->dbpass ?? '')
            ->setSchema($connectionDetails->driver ?? '')
            ->setOptions($connectionDetails->options ?? []);
    }

    public function setHost($host)
    {
        $this->host = $host;
        return $this;
    }

    /**
     * Function to set the name of the database we're connecting to
     * @param $name
     * @return $this
     */
    public function setDatabase($name = NULL)
    {
        $this->database = $name;
        return $this;
    }

    /**
     * Function to set the username to connect with
     * @param $user
     * @return $this
     */
    public function setUser($user = NULL)
    {
        $this->user = $user;
        return $this;
    }

    public function setPass($pass = NULL)
    {
        $this->pass = $pass;
        return $this;
    }

    public function setSchema($schema = NULL)
    {
        $this->schema = $schema;
        return $this;
    }

    public function setOptions($options = NULL)
    {
        $this->options = $options;
        return $this;
    }

    public function getDatabase()
    {
        return $this->database;
    }

    public function getUser()
    {
        return $this->user;
    }

    public function getPass()
    {
        return $this->pass;
    }

    /**
     * Initiate the connection to the database.
     * @param bool $test
     * @return $this | boolean
     */
    protected function connection($test = FALSE)
    {
        $dsn = $this->schema . ':host=' . $this->host;
        //allow us to connect to a mysql server, but without a database if one isn't specified.
        if($this->database){
            $dsn .= ';dbname=' . $this->database;
        }
        //don't store the PDO connection, we just want to know if we can open a connection or not.
        if($test){
            $pdo = new \PDO($dsn, $this->user, $this->pass, $this->options);
            //if the above doesn't fatal, close the connection and return TRUE since we could connect.
            $pdo = null;
            return TRUE;
        } else {
            $this->pdo = new \PDO($dsn, $this->user, $this->pass, $this->options);
        }
        return $this;
    }

    /**
     * Function to execute the query;
     * @param array $fields
     * @param bool $empty
     * @return $this
     */
    public function execute(){
        //Allow us to connect as late as possible.
        if(empty($this->pdo)){
            $this->connection();
        }
        $prepare = $this->pdo->prepare($this->sql);
        if(!$prepare){
            $error = $this->pdo->errorInfo();
        }
        $this->statement = $prepare;
        $this->statement->execute($this->queryFields);
        $this->statementError = $this->statement->errorInfo();
        if($this->statementError[0] != '00000'){
            error_log($this->sql);
            throw new \Exception(implode(', ', $this->statementError));
        }
        return $this;
    }

    public function testConnection(){
        return $this->connection(TRUE);
    }

    /**
     * @return mixed
     */
    public function fetchAll(){
        return $this->statement->fetchAll(\PDO::FETCH_OBJ);
    }

    /**
     * @return array
     */
    public function fetchAssoc(){
        return $this->statement->fetch(\PDO::FETCH_ASSOC);
    }

    /**
     * Kill the DB connection only on destruct.
     * Magic __destruct function
     */
    public function __destruct(){
        $this->pdo = null;
    }
}