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

#include <speedy.h>
#include <speedydb.h>

#ifdef _TEST1
#include <time.h>
typedef struct {
  DB_ConnStatus status;
  int sock;
  char * dbname;
  char DBerrorMsg[DB_STRGLEN];
} db_conn;

extern int send_data(int sock, char * data, int size);
extern int recv_data(int sock, char * data, int max, char ** pdata, int * psize);
#endif

#ifdef _WIN32_WINNT
#include <windows.h>
#endif

#define MAXSTRG        10000

main(int argc, char * argv [])
{
  DBconn * conn;
  DBresult * res;
  char * filename = NULL;
  char * dbname = NULL, * host = NULL, * port = NULL, * options = NULL;
  int kz_create = FALSE, kz_drop = FALSE;
  int i, j;
  char strg[MAXSTRG], str1[MAXSTRG], cmd[MAXSTRG], * pstr;
  int icnt;
  FILE * fp;
  int kz_silent = FALSE;

  for (i = 1; i < argc; i++) {
    if (strncmp(argv[i], "-?", 2) == 0) {
      dbname = NULL; break;
    } else if (strcmp(argv[i], "create") == 0 || strcmp(argv[i], "CREATE") == 0) {
      kz_create = TRUE;
    } else if (strcmp(argv[i], "drop") == 0 || strcmp(argv[i], "DESTROY") == 0) {
      kz_drop = TRUE;
    } else if (strncmp(argv[i], "-i", 2) == 0) {
      if (strlen(&(argv[i][2])) > MAXSTRG - 2) {
        fprintf(stdout, "(speedysh) Filename %s is too long (max. %d)\n",
                &(argv[i][2]), MAXSTRG - 2);
        exit(1);
      }
      filename = strdup(&(argv[i][2]));
    } else if (strncmp(argv[i], "-h", 2) == 0) {
      if (strlen(&(argv[i][2])) > MAXSTRG - 2) {
        fprintf(stdout, "(speedysh) HOST-name %s is too long (max. %d)\n",
                &(argv[i][2]), MAXSTRG - 2);
        exit(1);
      }
      host = strdup(&(argv[i][2]));
    } else if (strncmp(argv[i], "-p", 2) == 0) {
      if (strlen(&(argv[i][2])) > MAXSTRG - 2) {
        fprintf(stdout, "(speedysh) PORT-string %s is too long (max. %d)\n",
                &(argv[i][2]), MAXSTRG - 2);
        exit(1);
      }
      port = strdup(&(argv[i][2]));
    } else if (strcmp(argv[i], "-s") == 0 ||
               strcmp(argv[i], "-silent") == 0) {
      kz_silent = TRUE;
    } else {
      dbname = strdup(argv[i]);
    }
  } 
  if (dbname == NULL) {
    if (dbname == NULL && (kz_create || kz_drop)) {
      fprintf(stdout, "(speedysh) Usage: speedysh dbname [CREATE|DESTROY] " \
                      "[-i<filename>] [-h<HOST>] [-p<PORT>] [-s|-silent]\n");
      exit(1);
    } else {
      dbname = strdup("");
    }
  }
  if (filename != NULL) {
    fp = fopen(filename, "rb");
    if (fp == NULL) {
      fprintf(stderr, "(speedysh) File '%s' does not exist!\n", filename);
      exit(1);
    }
  } else {
    fp = stdin;
  }

  if (kz_create) {
    conn = DBcreatedb(host, port, options, dbname);
    if (DBstatus(conn) == DB_CONN_BAD) {
      fprintf(stderr, "(speedysh) Create database '%s' failed:\n", dbname);
      fprintf(stderr, "  %s", DBerrorMessage(conn));
      exit(1);
    }
  } else {
    conn = DBsetdb(host, port, options, dbname);
    if (DBstatus(conn) == DB_CONN_BAD) {
      fprintf(stderr, "(speedysh) Connect to database '%s' failed:\n", dbname);
      fprintf(stderr, "  %s", DBerrorMessage(conn));
      exit(1);
    }
  } 
  if (kz_drop) {
    if (! DBdropdb(conn)) {
      fprintf(stderr, "(speedysh) Drop database '%s' failed:\n", dbname);
      fprintf(stderr, "  %s", DBerrorMessage(conn));
      exit(1);
    }
    exit(0);
  }

  /* ------------------------------------------------------- */

  icnt = 0; str1[0] = '\0';
  for (;;) {
    if (str1[0] != '\0') {
      i = 0;
      if (icnt == 0) {
        while (str1[i] == ' ') i++;
      }

      while (str1[i] != '\0') {
        cmd[icnt++] = str1[i++];
      }
    }
    if (filename == NULL) {
      if (icnt > 0) {
        printf("  ");
      } else {
        printf("> ");
      }
    }
    while ((pstr = fgets(strg, MAXSTRG, fp)) != NULL) {
      if (strg[0] == '-' && strg[1] == '-')
        continue;
      if (strg[0] == '#')
        break;
      i = 0;
      while (strg[i] != '\0' && strg[i] != ';') {
        if (strg[i] == '\n')
          cmd[icnt++] = ' ';
        else if (strg[i] == '\\') {
          if (strg[i + 1] == 'q') 
            exit(0);
          else 
            cmd[icnt++] = strg[i];
        } else 
          cmd[icnt++] = strg[i];
        i++;
      }
      if (strg[i] == ';') {
        i++; cmd[icnt] = '\0';
        icnt = 0; j = 0;
        while (strg[i] != '\0') {
          if (strg[i] == '\n')
            str1[j++] = ' ';
          else 
            str1[j++] = strg[i];
          i++;
        } 
        str1[j] = '\0';
        break;
      } else {
        if (filename == NULL) {
          if (icnt > 0) {
            printf("  ");
          } else {
            printf("> ");
          }
        }
      }
    }
    if (strg[0] == '#')
      break;

    if (pstr == NULL) {
      exit(0);
    }
    strcat(cmd, ";");
    if (! kz_silent) {
      int i = 0;

      printf("---\nsql = '");
      while (cmd[i] != '\0' && isspace(cmd[i])) 
        i++;
      while (cmd[i] != '\0') {
        if (cmd[i] == '\r') {
          printf("\n      ");
        } else {
          printf("%c", cmd[i]);
        }
        i++;
      }
      printf("'\n");
    }
    
    res = DBexec(conn, cmd);
    if (res != NULL) {
      int i, j, fields, tuples;

      if (DBresultStatus(res) == DB_TUPLES_OK ||
          DBresultStatus(res) == DB_NOTALL_TUPLES_OK) {
        tuples = DBntuples(res);
        fields = DBnfields(res);
        strcpy(strg, "");
        for (i = 0; i < fields; i++) {
          strcat(strg, DBfname(res, i));
          if (i < fields - 1)
            strcat(strg, ", ");
        }
        printf("%s\n", strg);

        for (i = 0; i < tuples; i++) {
          strcpy(strg, "");
          for (j = 0; j < fields; j++) {
            strcat(strg, DBgetvalue(res, i, j));
            if (j < fields - 1)
              strcat(strg, ", ");
          }
          printf("%s\n", strg);
        }
      }
      if (DBresultStatus(res) == DB_NOTALL_TUPLES_OK) {
        printf("not all results evaluated\n");
      }
    }

    i = 0; j = 0;
    while (isspace(cmd[i])) i++; 
    while (isalpha(cmd[i])) strg[j++] = cmd[i++]; 
    strg[j] = '\0';

    if (res == NULL) {
      printf("%s: An error occurred (no result)\n", strg);
    } else {
      int status = DBresultStatus(res);
      int tuples = DBntuples(res);
      if (status == DB_BAD_RESPONSE) {
        printf("BAD RESPONSE to %s command.\n", strg);
        printf("Error: %s", DBresultErrorMessage(res));
      } else if (status == DB_FATAL_ERROR) {
        printf("FATAL ERROR occured in %s command.\n", strg);
        printf("Error: %s", DBresultErrorMessage(res));
      } else if (status == DB_NONFATAL_ERROR) {
        printf("NONFATAL ERROR occured in %s command.\n", strg);
        printf("Error: %s", DBresultErrorMessage(res));
      } else {
        if (tuples > 0) {
          printf("%s successfully executed for %d items\n", 
                 strg, tuples);
        } else {
          printf("%s successfully executed\n", strg);
        }
      }
      DBclear(res);
    }
    strcpy(cmd, "");
  }

  exit(0);
}

