<?php

/**
 * Description of BaseDatos
 *
 * @author pedroTHDC
 * @version 0.7
 * 0.7 => Añadida función estática para enlazar campos con alias
 *
 */

class SuperBaseDatos {

    private static $conexion = NULL;
	public static $dictionary = NULL;
	public static $consultas_realizadas = 0;
	
	private $resultado;
	
    function __construct($db_name = '', $user = '', $password = '', $host = '127.0.0.1') {
		if (self::$conexion == NULL) {
			//Si no hemos recibido los parámetros, lanzamos una excepción:
			if ( ($db_name == '') || ($user == '') || ($password == '') ){
				//throw new Exception('Imporsible conectar a la base de datos. Faltan parámetros.');
			}else{
				self::openDBconnection($db_name, $user, $password, $host = 'localhost');
			}
		}
    }

    public function isConectado() {
        if (self::$conexion != NULL) {
            return true;
        } else {
            return false;
        }
    }

//

    public function closeConexion() {
        self::$conexion = null;
    }

//
    public function getAutonumerico() {
		$retorno = false;
		//Modifado por Pedro el 11/Enero/2019 ==> Si recibimos el nombre de la tabla como primer valor, cargamos dicho valor de la tabla "last_insert_id":
		if (func_num_args() > 0){
			$table_name = func_get_arg(0);
			$statement = 'SELECT `ID` FROM `last_insert_id` WHERE `table_name` = \'' . $table_name . '\' LIMIT 1';
			//echo("$statement<br />\n");
			$this->setConsulta($statement);
			if ($fila = $this->getFila()){
				$retorno =  $fila['ID'];
			}
		}else{
			if ($id = self::$conexion->lastInsertId()) {
				$retorno =  $id;
			} 
		}
		return($retorno);
    }

    public function getFila($style = NULL) {
		$style = ($style == NULL) ? PDO::FETCH_BOTH : $style;
        if ($this->resultado != null) {
            return $this->resultado->fetch($style);
        } else {
            return false;
        }
    }

    public function getNumeroFilas() {
        if ($this->resultado != null) {
            return $this->resultado->rowCount();
        }
        return -1;
        //según la documentación no devuelve siempre el número de filas después de un select (depende del SGBD)
    }

    public function setBaseDatos($bd) {
        return self::$conexion->query("use $baseDatos") !== false;
    }

    public function closeConsulta() {
        $this->resultado->closeCursor();
    }

    /**
     * Realiza un query de la consulta utilizando  consultas preparadas y haciendo un bind de los valores por nombre
     * @param type $sql
     * @param type $param
     */
    public function setConsulta($sql, $param = array()) {
        $this->resultado = self::$conexion->prepare($sql);
        foreach ($param as $indice => $valor) {
            $this->resultado->bindValue($indice, $valor);
        }
		static::$consultas_realizadas++;
        return $this->resultado->execute();
    }

    /**
     * Realiza el query con consulta preparada con id.
     * @param type $sql
     * @param type $param
     */
    public function setConsultaPreparada($sql, $param = array()) {
        $this->resultado = self::$conexion->prepare($consulta);
        $pos = 1;
        foreach ($parametros as $valor) {
            $this->resultado->bindValue($pos, $valor);
            $pos++;
        }

        return $this->resultado->execute();
    }

    /**
     * 
     * @param type $sql
     * @return boolean
     */
    public function setConsultaSQL($sql) {
        $this->resultado = self::$conexion->query($sql);
        if ($this->resultado === false) {
            $this->resultado = null;
            return false;
        } else {
            return true;
        }
    }

    public function setTransaccion() {
        self::$conexion->beginTransacion();
    }

    public function setValidarTransaccion() {
        self::$conexion->commit();
    }

    public function setAnularTrasaccion() {
        self::$conexion->rollBack();
    }

    public function getError() {
        return $this->resultado->errorInfo();
    }

    public function getErorres() {
        mysql_errno(self::$conexion) . ": " . mysql_error(self::$conexion) . "\n";
    }

	public static function dameAlias($tabla){
		return(BaseDatos::$dictionary->{$tabla . 'Alias'});
	}
	public static function dameCampos($nombreTabla){
		return(BaseDatos::$dictionary->{$nombreTabla . 'Campos'});
	}
	public static function dameCamposAlias($campos = array(), $alias = ''){
		$retorno = '';
		$alias_tabla = '';
		//Si "campos" no es un array es porque nos han pasado sólo el nombre de la tabla y componemos el resto a mano:
		if ( (!is_array($campos)) && ($campos !== NULL) ){
			$retorno = BaseDatos::dameCamposAlias(
				BaseDatos::$dictionary->{$campos . 'Campos'}, 
				BaseDatos::$dictionary->{$campos . 'Alias'}
			);
		}else{
			if ($alias != ''){
				$alias_tabla = '`' . $alias . '`.';
			}
			if (is_array($campos)){
				foreach($campos as $clave => $campo){
					$retorno .= (($retorno != '') ? ', ' : '') . $alias_tabla . '`' . $campo . '` `' . $alias . '_' . $campo . '` ';
				}
			}else{
				throw new Exception('Imposible obtener los campos de: ' . $alias);
			}
		}
		return($retorno);
	}	
	
	public static function initDB(){
		//Esta función es la encargada de conectarse a la base de datos.
		//-------------------------------------//
		//          RETROCOMPATIBILIDAD        //
		//-------------------------------------//
		GLOBAL $conexionBD;
		$cargarBD = false;
		if (isset($GLOBALS['conexionBD'])) {
			$cargarBD = true;
		} else if (!$GLOBALS['conexionBD']) {
			$cargarBD = true;
		}

		if ($cargarBD) {
			$GLOBALS['conexionBD'] = false;
			$GLOBALS['conexion_sql_activa'] = false;
			$GLOBALS['bd'] = null;
			$ruta_config = Shop::localizaConfigSys();
			//Ésta línea es la única que deberíamos mantener en las versiones futuras de WebStore
			if ($ruta_config != NULL){
				static::connectDBFromFile($ruta_config);
			}
		}
		//-------------------------------------//
		//          RETROCOMPATIBILIDAD        //
		//-------------------------------------//
	}
	
	private static function connectDBFromFile($ruta_fichero = 'config.sys') {
		//Lo primero es abrir el fichero que contiene el usuario y la contraseña y leer su contenido
		$fichero = @fopen($ruta_fichero, 'r');
		if ($fichero) {
			//Tenemos que leer la primera línea del fichero
			$linea = fgets($fichero);
			//Desencriptamos la línea obtenida
			$linea = BaseDatos::decrypt($linea);
			//Dividimos la línea en 3, y así obtendremos la base de datos, el usuario y la contraseña de la misma
			$linea = explode('|', $linea);
			fclose($fichero);
			$ruta = 'localhost';
			if ( count($linea) > 3 ){
				$ruta = $linea[3];
			}
			//var_dump($linea);
			//En linea tenemos un array con la base de datos, el usuario y la contraseña
			//var_dump($linea);
			$link = static::openDBconnection($linea[0], $linea[1], $linea[2], $ruta);
			if (!$link){
				$link = 'false';
				echo('Error al intentar abrir la base de datos, no existe el fichero de configuraci&oacute;n');
			}else{
				////Si la conexión es correcta, vamos a intentar que las comunicaciones sean siempre en UTF8
				$sentenciaSql = 'SET NAMES \'utf8\'';
				mysqli_query($link, $sentenciaSql);
			}
		}
		return($link);
	}
	
	private static function openDBconnection($db_name, $user, $password, $host = 'localhost') {
		include('comunes/globals.php');
		//Antes de nada tenemos en cuenta si estamos o no ya conectados a la base de datos
		if (self::$conexion == NULL) {
			//-------------------------------------//
			//          RETROCOMPATIBILIDAD        //
			//-------------------------------------//
			//No hay conexión, tenemos que crear una nueva
			//echo('connect $host con el usuario $user y el password: $password<br />\n');
			$link = mysqli_connect($host, $user, $password);
			if (!$link) {
				$error = '<br />Error conectando a la base de datos. ' . mysqli_error($link) . '<br />\n';
				$correcto = false;
			} else if (!mysqli_select_db($link, $db_name)) {
				$error = '<br />Error seleccionando la base de datos: ' . mysqli_error($link) . '<br />\n';
				$correcto = false;
			} else {
				//Ya estamos conectados
				$correcto = true;
			}
			//-------------------------------------//
			//          RETROCOMPATIBILIDAD        //
			//-------------------------------------//
			
			
			/* Conectar a una base de datos de MySQL invocando al controlador */
			$dsn = 'mysql:dbname=' . $db_name . ';host=' . $host;
			try {
				self::$conexion = new PDO($dsn, $user, $password);
			} catch (PDOException $e) {
				self::$conexion = null;
				echo 'Falló la conexión: ' . $e->getMessage();
			}
			//Vamos a establecer las comunicaciones en UTF8
			$sentenciaSql = 'SET NAMES \'utf8\'';
			$bd = new BaseDatos();
			$bd->setConsultaSQL($sentenciaSql);
			
			
		} else {
			//-------------------------------------//
			//          RETROCOMPATIBILIDAD        //
			//-------------------------------------//
			//Ya hay conexión
			$link = $GLOBALS['conexionBD'];
			$correcto = true;
			//-------------------------------------//
			//          RETROCOMPATIBILIDAD        //
			//-------------------------------------//
		}

		//-------------------------------------//
		//          RETROCOMPATIBILIDAD        //
		//-------------------------------------//
		//Si todo ha ido correcto, ya tenemos nuestra base de datos cargada
		if ($correcto) {
			$conexionBD = $GLOBALS['conexionBD'] = $link; //==>Asignamos la variable de conexión
			$GLOBALS['conexion_sql_activa'] = true; //=>Indicamos que la conexión activa está creada
			return($link);
		} else {
			$conexionBD = $GLOBALS['conexion_sql_activa'] = false;
			echo($error);
			return(false);
		}
		//-------------------------------------//
		//          RETROCOMPATIBILIDAD        //
		//-------------------------------------//
	}
	
	
	public static function decrypt($string){
	   $result = '';
		$key = 'ARMINET555';
	   $string = base64_decode($string);
	   for($i=0; $i<strlen($string); $i++) {
		  $char = substr($string, $i, 1);
		  $keychar = substr($key, ($i % strlen($key))-1, 1);
		  $char = chr(ord($char)-ord($keychar));
		  $result.=$char;
	   }
	   return $result;
	}

	public static function encrypt($string){
	   $result = '';
   	   $key = 'ARMINET555';
	   for($i=0; $i<strlen($string); $i++) {
		  $char = substr($string, $i, 1);
		  $keychar = substr($key, ($i % strlen($key))-1, 1);
		  $char = chr(ord($char)+ord($keychar));
		  $result.=$char;
	   }
	   return base64_encode($result);
	}
	
	private static function getDictionaryPath(){
		$dictionaryPath = _WS_DYNAMIC_DIR_ . 'cache';
		//Si no existe lo creamos:
		if (!file_exists($dictionaryPath)){
			@mkdir($dictionaryPath);
		}
		$dictionaryPath .= '/dictonary.php';
		return($dictionaryPath);
	}
	
	public static function getDictionary(){
		$dictionaryPath = static::getDictionaryPath();
		if (!file_exists($dictionaryPath)){
			static::createDictornary();
		}
		static::$dictionary = new BasicObject();
		include($dictionaryPath);
		//Vamos a cargar el fichero:
		return($dictionaryPath);
	}
	
	private static function createDictornary(){
		$dictionaryPath = static::getDictionaryPath();
		$nombreClase = static::class;
		//Nos aseguramos de que no haya ya un diccionario:
		if(file_exists($dictionaryPath)){
			unlink($dictionaryPath);
		}
		$bdTablas = new BaseDatos();
		$bdCampos = new BaseDatos();
		$consultaTablas = 'SHOW TABLES';
		$consultaCamposBase = 'SHOW COLUMNS FROM ';
		$bdTablas->setConsultaSQL($consultaTablas);
		//Vamos a abrir también un fichero aquí para el diccionario:
		if ($file = fopen($dictionaryPath, 'w')){
			fputs($file, '<?php ');
			$contador = 0;
			while ($filaTablas = $bdTablas->getFila()){
				$filaTablas[0] = str_replace('-', '_', $filaTablas[0]);
				//Escribimos un alias para la tabla
				fputs($file, $nombreClase . '::$dictionary->' . $filaTablas[0] . 'Alias = ' . '\'al_' . $contador . '_\'; ');
				//Escribimos los campos de la tabla
				fputs($file, $nombreClase . '::$dictionary->' . $filaTablas[0] . 'Campos =  array(');

				$selectTabla = $consultaCamposBase . '`' . $filaTablas[0] . '`';
				$bdCampos->setConsultaSQL($selectTabla);
				$cadenaGrabar = '';
				while ($filaCampos = $bdCampos->getFila()){
					$filaCampos['Field'];
					//Si no es el primero, entonces 
					$cadenaGrabar .= (($cadenaGrabar != '')? ', ':'') . '\'' . $filaCampos['Field'] . '\'';
				}
				fputs($file, $cadenaGrabar);
				fputs($file, ');');
				$contador++;
			}
			fputs($file,' ?>');
			fclose($file);
		}
	}
}
