#include "fillHash.h"
#include "tools.h"
#include "hashtable.h"
#include "hashtypes.h"

/* Log Management */
#define FATAL_FILLHASH
#define ERROR_FILLHASH
//#define INFO_FILLHASH
//#define WARN_FILLHASH
//#define DEBUG_FILLHASH
//#define DEBUG_FILLHASH_RECVSIZE
//#define DEBUG_FILLHASH_HASH

void procInit(Opt_M message) {
  char * bufrecv = NULL;
  int rval;

#ifdef DEBUG_FILLHASH
  printf("(GroupComm) Procedure to fill table hash whith datas of confilct_classes\n");
#endif

  Init_Delivery(message);

#ifdef DEBUG_FILLHASH_RECVMESSAGE
  printf("JSALAS Waiting message ...6 (QMSpecial)\n");
#endif
  if ((rval = recvWithSizeMem(sock[MAXQM], & bufrecv, 0)) < 0) {
    printf("(GroupComm) ERROR : receiving datas of tables 1\n");
  } else {
#ifdef DEBUG_FILLHASH_RECVSIZE
    printf("(RECVSIZE 6) Bytes <%d> Message <%s>\n", rval, bufrecv);
#endif
    if (bufrecv[0] != 'E') {
      fillHash(bufrecv, 1);
    } else
      printf("(GroupComm) ERROR : %s\n", bufrecv);
  }
  Free(bufrecv);
}

void procFillHash(T_Mess message) {

  Opt_M mess;
  int stp, rval, pos, end_tables;
  struct itemhMiddler * found = NULL;
  struct itemhDBConns * found_conn = NULL;

  char * k = NULL;
  char * bufrecv = NULL;
  char token[MAX_TXT /*+ EXTRASIZE - RMEXTRASIZE*/];
  char sqlcode[MAX_TXT /*+ EXTRASIZE - RMEXTRASIZE*/];
  char tables[MAX_TXT /*+ EXTRASIZE - RMEXTRASIZE*/];
  char dbname[MAXDBNAME /*+ EXTRASIZE - RMEXTRASIZE*/];
  char tableName[MAXTABLENAME /*+ EXTRASIZE - RMEXTRASIZE*/];

  /**  */
  /* Fill table hash */
  /**  */
  mess = message.opt;

#ifdef DEBUG_FILLHASH
  printf("(GroupComm) Procedure to fill table hash\n");
#endif

  sscanf(& mess.trans.sqlcode[0], "%d", & stp);

  if ((stp == CON) || (stp == CON_RESPONSE)){
//printf("CON %d\n", mess.trans.tid);
    sscanf(& mess.trans.sqlcode[3], "%s", sqlcode);//CPG
    bzero(dbname, sizeof(dbname));//CPG
    strcpy(dbname, sqlcode);//CPG

#ifdef DEBUG_FILLHASH
    printf("(GroupComm) Connection to %s\n", dbname);
#endif

    /**  */
    /* find bdname.pg_class in table hash */
    /**  */

    /*if (!(k = (char *) malloc(sizeof(char) * (strlen(dbname) + 9 + EOF_SIZE)))) {//CPG
#ifdef FATAL_FILLHASH
      printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
      exit(0);
    }
    strcpy(k, dbname);
    strcat(k, ".");
    strcat(k, "pg_class");*/

#ifdef DEBUG_FILLHASH
    printf("(GroupComm) Finding bdname in table hash\n");
#endif

#ifdef DEBUG_FILLHASH_HASH
    printf("(HASHTABLE) Table <hMiddler> Operation <hash_lookup> Key <%s> File <%s> Line <%d>\n", k, __FILE__, __LINE__);
#endif
    if ((found_conn = (struct itemhDBConns *)get_hashtable(&hDBConns, dbname)) == NULL) {
      //if ((found = (struct itemhDBConns *)get_hashtable(&hDBConns, dbname)) == NULL) {
      struct itemhDBConns *item = (struct itemhDBConns *) malloc(sizeof(struct itemhDBConns));
      strcpy(item->name, dbname);
      item->open_conns=1;
        	  
      item->reuseQM = Dllist_create(free);      
            
      //printf("[PostConnect 1] Open Connections <%d>\n", item->open_conns, message.opt.trans.tid);
      if (!insert_hashtable(&hDBConns, &item->name, item)) {
        #ifdef ERROR_TRANSMNG
          printf("(Transmng) Not possible insert connection in hashtable\n");
        #endif
      }

    //if ((found = (struct itemhMiddler *)get_hashtable(&hMiddler, k)) == NULL) {//CPG
#ifdef DEBUG_FILLHASH
      printf("(GroupComm) Not found\n");
#endif

      // do not exist bdname.pg_class
      mess.qmId = MAXQM;

#ifdef DEBUG_FILLHASH
      printf("(GroupComm) endpoint6 = %s\n", mess.trans.endpoint.name);
#endif

      Opt_Delivery(mess);

#ifdef DEBUG_FILLHASH_RECVMESSAGE
      printf("JSALAS Waiting message ...7(QMSpecial)\n");
#endif

      if ((rval = recvWithSizeMem(sock[MAXQM], &bufrecv, 0)) < 0) {
        printf("(GroupComm) ERROR : receiving datas of tables 2\n");

      } else {
#ifdef DEBUG_FILLHASH_RECVSIZE
        printf("(RECVSIZE 7) Bytes <%d> Message 1 <%s>\n", rval, bufrecv);
#endif
        if (bufrecv[0] != 'E') {
          if (bufrecv[0] != '.') { fillHash(bufrecv, 0); }

#ifdef DEBUG_FILLHASH
          else { printf("(GroupComm) The database is in conflict_classes\n"); }
#endif

        } else {
          printf("(GroupComm) ERROR : %s\n", bufrecv);
        }
      }
      Free(bufrecv);
    }else{
      found_conn->open_conns++;
      //printf("[PostConnect 2] Open Connections <%d>\n", found_conn->open_conns);
    }

    //Free(k);//CPG

  } /* CON */
  else {
    strcpy(sqlcode, & mess.trans.sqlcode[3]);
    if ((stp != DISCON) && (stp != DISCON_RESPONSE) && (stp != EARLY_DISCON)) {
      if (mess.trans.typeSQL == 'C') {
//printf("CREATE %d\n", mess.trans.tid);
#ifdef DEBUG_FILLHASH
        printf("(GroupComm) Create table = %s\n", sqlcode);
#endif
        /**  */
        /* find bdname.tablename in table hash */
        /**  */
        if (!(k = (char *) malloc(sizeof(char) * (MAXDBNAME + MAXTABLENAME + 1 + EOF_SIZE)))) {
#ifdef FATAL_FILLHASH
          printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
          exit(0);
        }

        bzero(token, sizeof(token));
        pos = getToken(sqlcode, ';', 0, token);
        pos = getToken(sqlcode, ';', pos, token);
        strcpy(k, token);
        strcat(k, ".");

        bzero(token, sizeof(token));
        pos = getToken(sqlcode, ' ', 0, token);
        pos = getToken(sqlcode, ' ', pos, token);
        pos = getToken(sqlcode, ' ', pos, token);
        strcat(k, token);

#ifdef DEBUG_FILLHASH
        printf("(GroupComm) key = %s\n", k);
#endif

#ifdef DEBUG_FILLHASH_HASH
        printf("(HASHTABLE) Table <hMiddler> Operation <hash_lookup> Key <%s> File <%s> Line <%d>\n", k, __FILE__, __LINE__);
#endif
        if ((found = (struct itemhMiddler *)get_hashtable(&hMiddler, k)) == NULL) {
#ifdef DEBUG_FILLHASH
          printf("(GroupComm) Not found\n");
#endif

          mess.qmId = MAXQM;

#ifdef DEBUG_FILLHASH
          printf("(GroupComm) endpoint7 = %s\n", mess.trans.endpoint.name);
#endif

          Opt_Delivery(mess);

#ifdef DEBUG_FILLHASH_RECVMESSAGE
          printf("JSALAS Waiting message ...8(QMSpecial)\n");
#endif
          //printf("sock[MAXQM]=%d\n", sock[MAXQM]);
          if ((rval = recvWithSizeMem(sock[MAXQM], &bufrecv, 0)) < 0) {
            //printf("Error sock[MAXQM]=%d\n", sock[MAXQM]);
            printf("(GroupComm) ERROR : receiving datas of tables 3\n");

          } else {
            //printf("sock[MAXQM]=%d\n", sock[MAXQM]);
#ifdef DEBUG_FILLHASH_RECVSIZE
            printf("(RECVSIZE 8) Bytes <%d> Message <%s>\n", rval, bufrecv);
#endif
            if (bufrecv[0] != 'E') { fillHash(bufrecv, 0); }

            else { printf("(GroupComm) ERROR : %s\n", bufrecv); }
          }
          Free(bufrecv);
        }
        Free(k);

      } else {
        if (mess.trans.typeSQL == 'R') {
//printf("DROP %d\n", mess.trans.tid);
          #ifdef DEBUG_FILLHASH
            printf("(GroupComm) drop table = %s\n", sqlcode);
          #endif
          mess.qmId = MAXQM;
          Opt_Delivery(mess);

          // Delete tables of table hash middler
          bzero(token, sizeof(token));
          pos = getToken(sqlcode, ';', 0, token);
          pos = getToken(sqlcode, ';', pos, dbname);

          if (!(k = (char *) malloc(sizeof(char) * (MAXDBNAME + MAXTABLENAME + 1 + EOF_SIZE)))) {
#ifdef FATAL_FILLHASH
            printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
            exit(0);
          }

          bzero(token, sizeof(token));
          pos = getToken(sqlcode, ' ', 0, token);
          pos = getToken(sqlcode, ' ', pos, token);
          pos = getToken(sqlcode, ';', pos, tables);


          end_tables = 1;
          pos = 0;

          bzero(tableName, sizeof(tableName));
          while (end_tables != 0) {
            pos = getToken(tables, ',', pos, tableName);
            if (pos == 0) {
              end_tables = 0;
            }
            // Delete table of table hash middler
            strcpy(k, dbname);
            strcat(k, ".");
            strcat(k, tableName);
#ifdef DEBUG_FILLHASH_HASH
            printf("(HASHTABLE) Table <hMiddler> Operation <hash_remove> Key <%s> File <%s> Line <%d>\n", k, __FILE__, __LINE__);
#endif
            delete_hashtable(&hMiddler, k);

#ifdef DEBUG_FILLHASH
            printf("(GroupComm) delete key = %s\n", k);
#endif
          }
          Free(k);
        }
      }
    }
  }
}

// 210703
// Fill the tabla hash "h" with the buffer's data
int fillHash(char * buffer /* [1000] */, int init) {
  struct itemhMiddler * middler;
  struct itemhCC * CC;
  char * bdnameAux = NULL;
  char * token = NULL;
  int pos;
  int end = 0;

#ifdef DEBUG_FILLHASH
    printf("FillHash <%s>\n", buffer);
#endif
  pos = 0;
  if (strcmp(buffer, "$$$.") != 0) {
    if (!(middler = (struct itemhMiddler *) malloc(sizeof(struct itemhMiddler)))) {
      #ifdef FATAL_FILLHASH
          printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
      #endif
      exit(0);
    }

    if (!(token = (char *) malloc(sizeof(char) * (strlen(buffer) + EOF_SIZE)))) {
      #ifdef FATAL_FILLHASH
          printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
      #endif
      exit(0);
    }

    if (init) {
      pos += getToken(& buffer[pos], '.', 0, token);
      strcpy(middler->key, token);
      strcat(middler->key, ".");
      pos += getToken(& buffer[pos], '.', 0, token);
      strcat(middler->key, token);

    } else {
      pos += getToken(& buffer[pos], '.', 0, token);
      strcpy(middler->key, token);
      if (!(bdnameAux = (char *) malloc(sizeof(char) * (strlen(token) + EOF_SIZE)))) {
#ifdef FATAL_FILLHASH
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
      }
      strcpy(bdnameAux, token);
      strcat(middler->key, ".");
      pos += getToken(& buffer[pos], '.', 0, token);
      strcat(middler->key, token);

      //04112004
      if (strcmp(token, "$$$") == 0) {
        //printf("%s:%d [fillHash] %s is empty <%d>\n", __FILE__, __LINE__, bdnameAux, pos);
        return;
      } else {
        //printf("%s:%d [fillHash] %s is not empty <%d> <%s>\n", __FILE__, __LINE__, bdnameAux, pos, token);
      }
    }
#ifdef DEBUG_FILLHASH
    printf("(GroupComm) key : %s;   ", middler->key);
#endif

    memcpy(& middler->id_CC, & buffer[pos], sizeof(int));
    pos += sizeof(int) + 1;

#ifdef DEBUG_FILLHASH
    printf("(GroupComm) id_CC : %d\n", middler->id_CC);
#endif
    while (!end) {
#ifdef DEBUG_FILLHASH_HASH
      printf("(HASHTABLE) Table <hMiddler> Operation <hash_add> Key <%s> File <%s> Line <%d>\n", middler->key, __FILE__, __LINE__);
#endif
      if (!insert_hashtable(&hMiddler, middler->key, middler)) {
        printf("ERROR (GroupComm) id_CC : %d\n", middler->id_CC);
        return -1;
      }

      // Create conflict class and assign its master
      if (!(CC = (struct itemhCC *) malloc(sizeof(struct itemhCC)))) {
#ifdef FATAL_FILLHASH
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
      }
      CC->id_CC = middler->id_CC;
      CC->queue = Q_create();
      CC->master = (middler->id_CC % REAL_MEMBERS);

#ifdef DEBUG_FILLHASH
      printf("(GroupComm) CC = %d  Master = %d\n", CC->id_CC, CC->master);
#endif

#ifdef DEBUG_FILLHASH_HASH
      printf("(HASHTABLE) Table <hCC> Operation <hash_add> Key <%d> File <%s> Line <%d>\n", CC->id_CC, __FILE__, __LINE__);
#endif
      if (!insert_hashtable(&hCC, &CC->id_CC, CC)) {
        return -1;
      }

      if (!(middler = (struct itemhMiddler *) malloc(sizeof(struct itemhMiddler)))) {
#ifdef FATAL_FILLHASH
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
      }
      bzero(middler->key, sizeof(middler->key));
      if (!init) {
        strcpy(middler->key, bdnameAux);
        strcat(middler->key, ".");
      }

      pos += getToken(& buffer[pos], '.', 0, token);
      if (strcmp(token, "$$$") != 0) {
        if (init) {
          strcpy(middler->key, token);
          strcat(middler->key, ".");
          pos += getToken(& buffer[pos], '.', 0, token);
          strcat(middler->key, token);
        } else {
          strcat(middler->key, token);
        }

#ifdef DEBUG_FILLHASH
        printf("(GroupComm) key : %s;   ", middler->key);
#endif

        memcpy(& middler->id_CC, & buffer[pos], sizeof(int));
        pos += sizeof(int) + 1;

#ifdef DEBUG_FILLHASH
        printf("(GroupComm) id_CC : %d\n", middler->id_CC);
#endif
      } else { end = 1; }
    }

    Free(token);
    Free(bdnameAux);
#ifdef DEBUG_FILLHASH
    printf("(GroupComm) End fill of table hash\n");
#endif
  }
#ifdef DEBUG_FILLHASH
  else {
    printf("(GroupComm) buffer is equal to $$$.\n");
  }
#endif
  return 0;
}

