/*  Xsqlmenu
 *  Copyright (C) 1996-2000 Kees Lemmens
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "Xsqldefs.h"

int CheckTableSelected(FD_Xsql *fd_Xsql)
{  Info_t *I = (Info_t *)fd_Xsql->vdata;
   
   if(fl_get_choice(fd_Xsql->XsqlTable) == 1 ||
      I->Numflds == 0)
   {
      fl_show_message("Select a table first !","","");
      return -1; /* none selected */
   }
   else
     return 0;
}

int ExecuteQuery(Info_t *I,char *query)
{
   Info(I->Xsql,"Executing: %s",query);
   if (sql_query(sock,query) < 0)
   {
      SqlError("Query failed");
      return -1;
   }
   return 0;
}
   
char *TypeConvert(char *target,const char *string,int type)
{
 /* JJG 8-DEC-98 Support new mSQL v4.0.3 variables */
   if(
#ifdef USE_MYSQL
      type == FIELD_TYPE_DATE || type == FIELD_TYPE_TIME ||
      type == FIELD_TYPE_DATETIME ||
      type == FIELD_TYPE_VAR_STRING || type == FIELD_TYPE_STRING
#else
      type == DATE_TYPE || type == TIME_TYPE ||
      type == CHAR_TYPE || type == TEXT_TYPE
#endif
      )
     sprintf(target,"'%s'",string);
   else
     sprintf(target,"%s",string); 
   
   return target;
}

void FreeInfoStruct(Info_t *I)
{
   int x;
   
   for(x=0;x<I->Numflds;x++)
     free(I->Fields[x].name);
   free(I->Fields);
   free(I->Table);
   free(I);
}

Info_t *CopyInfoStruct(Info_t *S)
{  int   x;
   Info_t *D;
   
   D = (Info_t *) malloc(sizeof(Info_t));
   D->Numflds = S->Numflds;
   D->Allflds = S->Allflds;
   D->Primkey = S->Primkey;
   D->Table   = (char *)malloc(strlen(S->Table) + 1);
   strcpy(D->Table,S->Table);
   D->Xsql    = S->Xsql;
   D->Res     = NULL; /* avoid closing a Result by accident */
   
   D->Fields = (SQL_FIELD *)malloc(S->Allflds * sizeof(SQL_FIELD));
   for(x=0;x<S->Allflds;x++)
   {
      memcpy(&D->Fields[x],&S->Fields[x],sizeof(SQL_FIELD));

      /* now save (copy) the pointer elements (name and table) */
      /* as they'll be lost after release of the selection */
      
      if((D->Fields[x].name = (char *)malloc(strlen(S->Fields[x].name) + 1)) == NULL)
      {
	 SqlError("Not enough memory to store fieldnames !");
	 exit(1);
      }
      strcpy(D->Fields[x].name,S->Fields[x].name);
      D->Fields[x].table = D->Table; /* useless to copy  */
   }
   return D;
}

Info_t *SetInfoStruct(char *table,FD_Xsql *fd_Xsql)
{  char *ptr;
   int   x;
   SQL_RES *res;
   SQL_FIELD *field;
   Info_t *I;
   
   if ((res = sql_list_fields(sock,table, 0)) == NULL) /* obtain all fields in table */
   {
      SqlError("Cannot fetch fieldnames for %s",table);
      return 0;
   }
   
   I = (Info_t *) malloc(sizeof(Info_t));

   I->Numflds = 0;
   I->Allflds = sql_num_fields(res); /* get number of fields */
   
   I->Table   = (char *)malloc(strlen(table) + 1);
   strcpy(I->Table,table);
   I->Xsql    = fd_Xsql;
   I->Res     = NULL;
   
   I->Fields = (SQL_FIELD *)malloc(I->Allflds * sizeof(SQL_FIELD));

   for(x=0; x<I->Allflds;x++)
   {
      field = sql_fetch_field(res);
#ifndef USE_MYSQL
      if(field->type == IDX_TYPE && I->Numflds == 0)
	I->Numflds=x;  /* rest are just index "fields" */
#endif
      
      memcpy(&I->Fields[x],field,sizeof(SQL_FIELD));
  /* JJG 8-DEC-98 override length of mSQL variables internal representation */
      /* SAW, Don't override mysql lengths */
#ifndef USE_MYSQL
     if ( field->type != CHAR_TYPE && field->type != TEXT_TYPE)
                  I->Fields[x].length = JJGWIDTH;
#endif

      /* now save (copy) the pointer elements (name and table) */
      /* as they'll be lost after release of the selection */
      
      if((ptr = (char *)malloc(strlen(I->Fields[x].name) + 1)) == NULL)
      {
	 SqlError("Not enough memory to store fieldnames !");
	 exit(1);
      }
      strcpy(ptr,I->Fields[x].name);
      I->Fields[x].name = ptr;
      I->Fields[x].table = I->Table; /* useless to copy */
   }
   I->Primkey = GetPrimaryKey(I);

   if(I->Numflds == 0)
     I->Numflds = I->Allflds;
   
   sql_free_result(res);
   return I;
}

int GetNumRecords(Info_t *I)
{  SQL_RES *res;
   char query[MAXQUERY];
   int numrecs;
   
   if(countflag == NOCOUNT)
     return 0;
   
   sprintf(query,SELECT,I->Table);

   if (ExecuteQuery(I,query))
      return 0;
   
   res = sql_store_result(sock);
   numrecs = sql_num_rows(res);

   sql_free_result(res);
   return numrecs;
}

void SetCounters(int NrFields,int NrRecords,FD_Xsql *fd_Xsql)
{  char string[MAXSTRING];
   
   sprintf(string,"%d",NrFields);
   fl_set_object_label(fd_Xsql->XsqlFieldCount,string);
   sprintf(string,"%d",NrRecords);
   fl_set_object_label(fd_Xsql->XsqlRecordCount,string);
}

void ClearList(FL_OBJECT *ob)
{
   fl_clear_choice(ob);
   fl_addto_choice(ob,"None selected"); 
}

void SetDatabaseList(FL_OBJECT *ob)
{
   SQL_RES    *res;
   SQL_ROW    row;
   
   if (sock == 0)
   {
      Message("Cannot fetch databases");
      return;
   }
   res = sql_list_dbs(sock,0);

   ClearList(ob);
   while((row = sql_fetch_row(res)) != NULL)
      fl_addto_choice(ob,row[0]);
   sql_free_result(res);
}

void SetTableList(FL_OBJECT *ob)
{
   SQL_RES     *res;
   SQL_ROW     row;
   
   if (sock == 0)
   {  
      Message("Cannot fetch tables");
      return;
   }
   res = sql_list_tables(sock, 0);
   ClearList(ob);
   
   while((row = sql_fetch_row(res)) != NULL)
     fl_addto_choice(ob,row[0]);
   sql_free_result(res);
}

void SetNewTable(char *table,FD_Xsql *fd_Xsql)
{
   Info_t *Info;
   
   /* First free previous info struct to avoid memory leaks */
   if(fd_Xsql->vdata != NULL)
   {
      FreeInfoStruct((Info_t *)fd_Xsql->vdata);
      fd_Xsql->vdata = NULL;
   }
   
   fl_set_choice_text(fd_Xsql->XsqlTable,table);

   if(fl_get_choice(fd_Xsql->XsqlTable) == 1) /* None selected */
   {
      SetCounters(0,0,fd_Xsql);
      return;
   }
   Info = SetInfoStruct(table,fd_Xsql);
   
   fd_Xsql->vdata = (void *)Info; /* attach Table Info to form structure ! */
   SetCounters(Info->Numflds, GetNumRecords(Info),fd_Xsql);
}

void SetNewDatabase(char *database,FD_Xsql *fd_Xsql)
{
   fl_set_choice_text(fd_Xsql->XsqlDatabase,database);

   if(fl_get_choice(fd_Xsql->XsqlDatabase) > 1) /* None selected */
   {
      if(sql_select_db(sock,database) < 0)
      {
	 SqlError("Error opening database %s",database);
	 return;
      }
      SetTableList(fd_Xsql->XsqlTable);
   }
   else
     ClearList(fd_Xsql->XsqlTable);
   SetCounters(0,0,fd_Xsql);
}

void SetNewServer(char *server,FD_Xsql *fd_Xsql)
{
   if(server != NULL)
   {
      fl_set_input(fd_Xsql->XsqlServer,server);
      if (*server == '\0')
	server = NULL;  /* provide for empty but not NULL string */
   }
      
   if ((sock = sql_connect(sock, server, "", "")) < 0)
   {  SqlError("Error connecting to server");
      ClearList(fd_Xsql->XsqlDatabase);
   }
   else
     SetDatabaseList(fd_Xsql->XsqlDatabase);

   ClearList(fd_Xsql->XsqlTable);
   SetCounters(0,0,fd_Xsql);
}
