/****************************************************************************
*  XARXES DE COMPUTADORS II                                                 
*
*  Practica VoIP
*
*  Realizado por: 
*     Francisco Jose Aguilar Celdran
*     Sergio Blanco Cuaresma
*
*  mysql.c: 
*     Implementación de funciones que interactuan con una base de datos MySQL
*     Utilizado para almacenar la información del servidor (usuarios registrados)
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <dirent.h>
#include <string.h>
#include "cola.h"
#include "mysql.h"


/**
   Conecta a la BD segun los parametros indicados. Establece las variables
   globales para poder trabajar sobre la conexión.
   Devuelve 1 en caso de error.
   */
int mysql_conectar_db (MYSQL *mysql, char *server, char *user, char *password, char *database) {
   
   mysql_init(mysql);
   if ((mysql_real_connect(mysql, server, user, password, database, 0, NULL, 0))==NULL){
#ifdef DEBUG
      fprintf(stderr, "Imposible conectarse al motor!\n\n%s\n\n", mysql_error(mysql));
      perror("");
#endif
      return 1;
   }
   return 0;
}

/**
   Ejecuta la sentencia SQL que le pasamos por parámetro
**/
int mysql_ejecutar_sql (MYSQL *mysql, char *sql) {

#ifdef DEBUG
      fprintf(stderr, "SQL: %s\n", sql);
#endif

   //if (mysql_real_query(mysql, sql, strlen(sql))!=0 ) {
   if (mysql_query(mysql, sql)!=0 ) {
#ifdef DEBUG
      fprintf(stderr, "Error ejecutando sql (%s)\n", mysql_error(mysql));
#endif
      return 1;
   }
   return 0;
}

/**
   Crea tabla en la BD para guardar los usuarios registrados en el servidor
   Devuelve 1 en caso de error
   */
int mysql_crear_tablas (MYSQL *mysql) {
   char *ibuff;
   size_t ibuff_size = 150 * sizeof(char);
   
   /* Guardamos espacio para la longitud de los valores + las instrucciones */
   ibuff=(char *)malloc(ibuff_size);

   if (ibuff==NULL) {
#ifdef DEBUG
      perror("Asignacion de memoria para inserccion insuficiente");
#endif
      return 1;
   }

   snprintf(ibuff, ibuff_size, "CREATE TABLE users (user VARCHAR(%i), port VARCHAR(%i))", TAM_USER, TAM_PORT);
   if (mysql_ejecutar_sql(mysql, ibuff) == 1) {
      free(ibuff);
      return 1;
   }
   
   
   free(ibuff);
   return 0;
}

/**
   Borra una tabla de la BD
   Devuelve 1 en caso de error
   **/
int mysql_ejecutar_drop_table (MYSQL *mysql, char *tabla) {
   char *ibuff;
   size_t ibuff_size = 150 + strlen(tabla) * sizeof(char);
   
   /* Guardamos espacio para la longitud de los valores + las instrucciones */
   ibuff=(char *)malloc(ibuff_size);

   if (ibuff==NULL) {
#ifdef DEBUG
      perror("Asignacion de memoria para inserccion insuficiente");
#endif
      return 1;
   }
   
   snprintf(ibuff, ibuff_size, "DROP TABLE IF EXISTS %s", tabla);
#ifdef DEBUG
   fprintf(stderr, "%s\n", ibuff);
#endif

   int ret = mysql_ejecutar_sql(mysql, ibuff);
   free(ibuff);
   
   return ret;
}

/**
   Borra la tabla que utiliza el servidor para guardar los clientes registrados
   Devuelve 1 en caso de error
   **/
int mysql_borrar_tablas (MYSQL *mysql) {
   if (mysql_ejecutar_drop_table(mysql, "users") == 1) {
      return 1;
   }
   return 0;
}


/**
   Inserta un registro con nombre de usuario y puerto determinado
   Devuelve 1 en caso de error
   **/
int mysql_alta_cliente (MYSQL *mysql, char *user, char *port) {
   char *ibuff;
   size_t ibuff_size = 100 + strlen(user) * sizeof(char) + strlen(port) * sizeof(char);
   
   /* Guardamos espacio para la longitud de los valores + las instrucciones */
   ibuff=(char *)malloc(ibuff_size);

   if (ibuff==NULL) {
#ifdef DEBUG
      perror("Asignacion de memoria para inserccion insuficiente");
#endif
      return 1;
   }

   // No se controla ataques por inyección SQL, mirar función mysql_real_escape_string(...)
   snprintf(ibuff, ibuff_size, "INSERT INTO users (user, port) VALUES ('%s', '%s')", user, port);
   
   int ret = mysql_ejecutar_sql(mysql, ibuff);
   
   free(ibuff);
   return ret;
}



/**
   Borra un registro con el nombre de usuario indicado
   Devuelve 1 en caso de error
   **/
int mysql_baja_cliente (MYSQL *mysql, char *user) {
   char *ibuff;
   size_t ibuff_size = 100 + strlen(user) * sizeof(char);

   /* Guardamos espacio para la longitud de los valores + las instrucciones */
   ibuff=(char *)malloc(ibuff_size);

   if (ibuff==NULL) {
#ifdef DEBUG
      perror("Asignacion de memoria para inserccion insuficiente");
#endif
      return 1;
   }

   // No se controla ataques por inyección SQL, mirar función mysql_real_escape_string(...)
   snprintf(ibuff, ibuff_size, "DELETE FROM users WHERE user = '%s'", user);
   if (mysql_ejecutar_sql(mysql, ibuff) == 1) {
      free(ibuff);
      return 1;
   }
   
   free(ibuff);
   return 0;
}


/**
   Lista los usuarios dados de alta en estructura que contiene nombre de usuario y puerto
   Devuelve 1 en caso de error
   Si no es encontrado devuelve 2.
   */
int mysql_listar_cliente (MYSQL *mysql, Cola *cola) {
   char *ibuff;
   size_t ibuff_size = 100;
   MYSQL_RES *res;
   MYSQL_ROW row;
   unsigned int num_fields;
   UserPort *usuari;
   
   /* Guardamos espacio para la longitud de los valores + las instrucciones */
   ibuff=(char *)malloc(ibuff_size);

   if (ibuff==NULL) {
#ifdef DEBUG
      perror("Asignacion de memoria para inserccion insuficiente");
#endif
      return 1;
   }

   // No se controla ataques por inyección SQL, mirar función mysql_real_escape_string(...)
   snprintf(ibuff, ibuff_size, "SELECT user,port FROM users");

   if (mysql_ejecutar_sql(mysql, ibuff) == 1) {
      free(ibuff);
      return 1;
   }
   
   // Obtenermos resultado
   if (!(res=mysql_store_result(mysql))){
#ifdef DEBUG
      fprintf(stderr,"Couldn't get result: %s\n", mysql_error(mysql));
#endif
      free(ibuff);
      return 1;
   }
   
   if (res)  // Hay resultado
   {
      num_fields = mysql_num_fields(res);
      if ( !(row = mysql_fetch_row(res))) {
         return 2;
      }
      // Por cada resultado
      do{
         usuari = (UserPort *)malloc(sizeof(UserPort));
         snprintf(usuari->user, TAM_USER, "%s", row[0]);
         snprintf(usuari->port, TAM_PORT, "%s", row[1]);
#ifdef DEBUG
         fprintf(stderr, "MySQL Found - Usuari: %s - ", usuari->user);
         fprintf(stderr, "Port: %s\n", usuari->port);
#endif
         encolar(cola, (void *)usuari);
      } while ((row = mysql_fetch_row(res)));
   } else {
      free(ibuff);
      return 2;
   }
    
   mysql_free_result(res);
   free(ibuff);
   return 0;
}



/**
   Busca información sobre un cliente: su nombre de usuario y puerto. 
   Se devolverá en una estructura UserPort (esta debe existir ya antes de 
   pasarla como parámetro).
   En caso de error devuelve 1.
   Si no es encontrado devuelve 2.
**/
int mysql_info_cliente (MYSQL *mysql, char *user, UserPort *usuariOut) {
   char *ibuff;
   size_t ibuff_size = 100 + strlen(user) * sizeof(char);
   MYSQL_RES *res;
   MYSQL_ROW row;
   unsigned int num_fields;
   
   /* Guardamos espacio para la longitud de los valores + las instrucciones */
   ibuff=(char *)malloc(ibuff_size);

   if (ibuff==NULL) {
#ifdef DEBUG
      perror("Asignacion de memoria para inserccion insuficiente");
#endif
      return 1;
   }

   // No se controla ataques por inyección SQL, mirar función mysql_real_escape_string(...)
   // 37 = numero ascii del símbolo %
   snprintf(ibuff, ibuff_size, "SELECT user,port FROM users WHERE user LIKE '%c%s%c'", 37, user, 37);
   
   if (mysql_ejecutar_sql(mysql, ibuff) == 1) {
      free(ibuff);
      return 1;
   }
   
   // Obtenermos resultado
   if (!(res=mysql_store_result(mysql))){
#ifdef DEBUG
      fprintf(stderr,"Couldn't get result: %s\n", mysql_error(mysql));
#endif
      free(ibuff);
      return 1;
   }
   
   if (res)  // Hay resultado
   {
      num_fields = mysql_num_fields(res);
      // Solo debe haber 1 resultado posible ya que los nicks son únicos
      if ((row = mysql_fetch_row(res))) {
         snprintf(usuariOut->user, TAM_USER, "%s", row[0]);
         snprintf(usuariOut->port, TAM_PORT, "%s", row[1]);
#ifdef DEBUG
         fprintf(stderr, "MySQL Info - User: %s Puerto: %s\n", usuariOut->user, usuariOut->port);
#endif
      } else {
         mysql_free_result(res);
         free(ibuff);
         return 2;
      }
   } else {
      free(ibuff);
      return 2;
   }
    
   mysql_free_result(res);
   free(ibuff);
   return 0;
}

/**
   Consulta si un usuario ya ha sido dada de alta.
   Si ha sido dada de alta devuelve 1, sino 0.
   En caso de error devuelve 2.
**/
int mysql_cliente_dado_de_alta (MYSQL *mysql, char *user) {
   char *ibuff;
   size_t ibuff_size = 100 + strlen(user) * sizeof(char);
   MYSQL_RES *res;
   MYSQL_ROW row;
   
   /* Guardamos espacio para la longitud de los valores + las instrucciones */
   ibuff=(char *)malloc(ibuff_size);

   if (ibuff==NULL) {
#ifdef DEBUG
      perror("Asignacion de memoria para inserccion insuficiente");
#endif
      return 2;
   }

   // No se controla ataques por inyección SQL, mirar función mysql_real_escape_string(...)
   snprintf(ibuff, ibuff_size, "SELECT * FROM users WHERE user LIKE '%s'", user);
   
   if (mysql_ejecutar_sql(mysql, ibuff) == 1) {
      free(ibuff);
      return 2;
   }
   
   // Obtenermos resultado
   if (!(res=mysql_store_result(mysql))){
#ifdef DEBUG
      fprintf(stderr,"Couldn't get result: %s\n", mysql_error(mysql));
#endif
      free(ibuff);
      return 2;
   }
   
   if (res) {
      // Si hay resultado
      if ((row = mysql_fetch_row(res))) {
         mysql_free_result(res);
         free(ibuff);
         return 1;
      } else {
         mysql_free_result(res);
         free(ibuff);
         return 0;
      }
   } else {
      free(ibuff);
      return 0;
   }

}


// Prueba del funcionamiento de las funciones anteriores
/*int main (int argc, char *argv[]){
   // Es necesario que la BD phone ya este creada en el servidor
   char *server="localhost", *user="root", *password="hola", *database="phone";
   Cola *cola = (Cola *)crear_cola();
   UserPort cliente;
   MYSQL mysql;

   mysql_conectar_db(&mysql, server, user, password, database);

   mysql_borrar_tablas(&mysql);
   mysql_crear_tablas(&mysql);
   mysql_alta_cliente(&mysql, "sergio@luna", "5555");
   mysql_alta_cliente(&mysql, "alberto@luna", "7272");
   mysql_info_cliente(&mysql, "sergio@luna", &cliente);
   printf("Usuari: %s \t Port: %s\n", cliente.user, cliente.port);
   if (mysql_cliente_dado_de_alta(&mysql, "sergio@luna")) {
      printf("sergio@luna existe!\n");
   } else {
      printf("sergio@luna NO existe!\n");
   }
   if (mysql_cliente_dado_de_alta(&mysql, "anna@tierra")) {
      printf("anna@tierra existe!\n");
   } else {
      printf("anna@tierra NO existe!\n");
   }
   mysql_baja_cliente(&mysql, "sergio@luna");
   mysql_close(&mysql);
   return 0;
}*/
