<?php

namespace CorePHP\Models;

:admin-use-class:

use CorePHP\Core\Conexion;
use CorePHP\Core\Utils\Validations;
use CorePHP\Core\Collections\Collection;
use CorePHP\Core\Libraries\ModelDefinition;
use CorePHP\Libraries\QueryMap;

class :class-name: extends ModelDefinition :admin-implements:{

    :model-fields:

    public function __construct(Conexion &$conx = null)
    {
        :init-model-fields:

        $this->initConexion($conx);
    }

    /**
     * Inizializa la conexion del modelo
     * 
     * @param Conexion $conx
     * @throws \Exception
     * @return mixed
     */
    protected function initConexion(&$conx)
    {
        if(empty($conx)){
            try{
                $this->conx = new Conexion();
            }catch(\Exception $e){
                throw new \Exception($e);
            }

        }else{
            $this->conx = $conx;
        }

        $this->query = new QueryMap();
        $this->query->:table:Query();
    }

    /**
     * Busca y carga un elemento basado en su ID
     * 
     * @param int $id
     * @throws \Exception
     * @return bool
     */
    public function getItem($id)
    {
        $query = $this->query->queryList[':table:']['getItem'];
        $data = array(
            "[[id]]" => $id
        );

        $this->conx->initializeQuery($query, $data);
        try{
            $result = $this->conx->getRequest();
        }catch(\Exception $e){
            throw new \Exception($e);
        }

        if($result = $result->fetch_assoc()){
            self::autoSerialize($this, $result);

            return true;
        }else{
            return false;
        }
    }

    :admin-functions:

    /**
     * Carga la totalidad de elemtnos y los devuelve como una clase Collection
     * 
     * @throws \Exception
     * @return \CorePHP\Core\Collections\Collection < :class-name: >
     */
    public function getAllItems()
    {
        $query = $this->query->queryList[':table:']['getAllItems'];

        $this->conx->initializeQuery($query);
        try{
            $result = $this->conx->getRequest();
            
            $array = [];

            while ($row = $result->fetch_assoc()) {
                $aux = new :class-name:($this->conx);

                self::autoSerialize($aux, $row);

                $array[] = $aux;
            }

            return new Collection($array);
        }catch(\Exception $e){
            throw new \Exception($e);
        }
    }

    :foreign-function:

    /**
     * Agrega un nuevo elemento a la tabla designada por el modelo
     * 
     * @param array $data
     * @throws \Exception
     * @return mixed
     */
    public function insertItem(array $data)
    {
        $fields = [:insert-model-validate:];

        $val = Validations::validatePost($fields,$data);
        if($val[0]){
            $query = $this->query->queryList[':table:']['insertItem'];
            $insert = array(
                :insert-model-data:
            );

            $this->conx->initializeQuery($query, $insert);
            try{
                $this->conx->setRequest();
            }catch(\Exception $e){
                throw new \Exception($e);
            }
        }else{
            throw new \Exception($val[1]);
        }
    }

    /**
     * Actualiza la informacion y campos especificados por $data en el elemnto con identificador $id
     * 
     * @param int $id
     * @param array $data
     * @throws \Exception
     * @return mixed
     */
    public function updateItem($id, array $data)
    {
        $query = $this->query->queryList[':table:']['updateItem'];
        $replace = "";

        if(empty($data)){
            throw new \Exception("Informacion de actualizacion invalida.");
        }

        foreach($data as $key => $value){
            if($replace == ""){
                $replace .= is_numeric($value) ? "$key = $value" : "$key = '$value'";
            }else{
                $replace .= is_numeric($value) ? ", $key = $value" : ", $key = '$value'";
            }
        }

        $query = str_replace("[[data]]",$replace,$query);
        $update = array(
            "[[id]]" => $id
        );

        $this->conx->initializeQuery($query, $update);

        try{
            $this->conx->setRequest();
        }catch(\Exception $e){
            throw new \Exception($e);
        }
    }

    /**
     * Elimina un elemento con identificador $id de la tabla especificada en el modelo
     * 
     * @param int $id
     * @throws \Exception
     * @return mixed
     */
    public function deleteItem($id)
    {
        $query = $this->query->queryList[':table:']['deleteItem'];
        $data = array(
            "[[id]]" => $id
        );

        $this->conx->initializeQuery($query, $data);

        try{
            $this->conx->setRequest();
        }catch(\Exception $e){
            throw new \Exception($e);
        }
    }

    /**
     * Retorna un objeto de tipo :class-name: con el ultimo registro disponible
     * 
     * @throws \Exception
     * @return \CorePHP\Models\:class-name:
     */
    public function getLastItem()
    {
        $query = $this->query->queryList[':table:']['getLastItem'];

        $this->conx->initializeQuery($query);

        try{
            $result = $this->conx->getRequest();
            $result = $result->fetch_assoc();

            self::autoSerialize($this, $result);

            return $this;
        }catch(\Exception $e){
            throw new \Exception($e);
        }
    }

}
