#include <stdlib.h>
#include <stdio.h>
#include <sybfront.h>
#include <sybdb.h>
#include <time.h>
#include "sybdbex.h"
#include "people.h"

#define OVERWRITE 1
#define kinBufLen 256
#define ksetEnvironErr 50
#define kalloLogFileErr 51
 
#ifdef BLIMP
#define interface "/usr/dbms/sybase/interfaces"
#define username ""
#define password ""
#define dbName "warehouse"
#define ENV_SYBASE "/usr/dbms/sybase"
#define ENV_DSLISTEN "warehouse"
#define ENV_DSQUERY "warehouse"
#else
#define interface "/dbms/testing/sybase/interfaces"
#define username "thorne"
#define password "foo"
#define dbName "vanguard_a"
#define ENV_SYBASE "/dbms/testing/sybase"
#define ENV_DSLISTEN "RPSSRVRA"
#define ENV_DSQUERY "RPSSRVRA"
#endif

#ifndef onlineDebug
FILE *logFileFp;
#define logFileName "people.err"
#endif

struct person_ *target; 
/* Beginning of forward declarations */
void getPeopleFromTable(struct person_ **first, struct person_ **last);
float evaluation(struct person_ *person, struct person_ *target);
void generateErrTran(unsigned long errCode);
int getChoices(struct person_ *ptr);
int getNewId();
extern long  inProtocolParser(char inProtocol[], 
			      struct arguments_ *original,
			      struct arguments_ *normalized);
int allocateLogFile(char fileName[]);
void deallocateLogFile();
extern void debugPrint(char *format, ...);

/* End of forward declarations */
int main (argc, argv)
     int argc;
     char *argv[];
{
  struct arguments_ originalArguments, normalizedArguments;
  struct person_ *first, *last, *temp;
  unsigned long numOfRec, numOfBytes;
  char inProtocol[kinBufLen];
  long retCode;

  /* send banner */
  printf("You're connected to the people db.\n%s",EOM);
  fflush(stdout);

  /* set environment */
  if (setEnvironment(OVERWRITE)==FAIL)
     generateErrTran(ksetEnvironErr);

#ifndef onlineDebug
  /* allocate log file */
  if ((retCode=allocateLogFile(logFileName))!=SUCCEED)
     generateErrTran(retCode);
#endif
  
  /* get input protocol */
  scanf("%s", inProtocol);

  /* parse input protocol */
  if ((retCode=inProtocolParser(inProtocol, &originalArguments, &normalizedArguments))!=SUCCEED)
  {
    debugPrint("Fail on input parser\n");
    generateErrTran(retCode);
  }

  first = last = NULL;
  target = (struct person_ *)malloc(sizeof(struct person_));
  if (!target)
  { 
    debugPrint("Cannot allocate memory for person, ec = %d\n", msgMemoryError);
    return(FAIL);
  } /* if (!target) */
  strcpy(target->lastName, normalizedArguments.lastName);
  strcpy(target->firstName, normalizedArguments.firstName);
  strcpy(target->middleName, normalizedArguments.middleName);
  strcpy(target->ssn, normalizedArguments.ssn);
  strcpy(target->dob, normalizedArguments.dob);
  debugPrint("Before getPeopleFromTable time = %d\n", time(NULL));
  getPeopleFromTable(&first, &last);
  debugPrint("After  getPeopleFromTable time = %d\n", time(NULL));
  temp = first;
  while(temp)
  {
    displayPerson(temp);
    temp = temp->next;
  }

  if (first!=NULL)
     getChoices(first);
  else
     getNewId();

  while (first)
  {
    temp = first->next;
    free(first);
    first = temp; 
  } 
  
#ifndef onlineDebug
  deallocateLogFile();
#endif

  exit(STDEXIT); 
}

float evaluation(struct person_ *person, struct person_ *target)
{
  char personName[fullNameLength];
  char targetName[fullNameLength];
  char personInfo[ssnLength+dobLength+1];
  char targetInfo[ssnLength+dobLength+1];
  float namePercentage, infoPercentage, dobPercentage;
/*
  if (infoPercentage >= maybeMatch)
    return(infoPercentage);
*/
  strcpy(personName, person->lastName);
  strcat(personName, person->firstName);
  strcat(personName, person->middleName);
  strcpy(targetName, target->lastName);
  strcat(targetName, target->firstName);
  strcat(targetName, target->middleName);
  namePercentage = matchAlphaPercentage(personName, targetName);
  if (namePercentage >= maybeMatch)
    return(namePercentage);
  strcpy(personInfo, person->ssn);
  strcat(personInfo, person->dob);
  strcpy(targetInfo, target->ssn);
  strcat(targetInfo, target->dob);
  infoPercentage = matchDigitPercentage(personInfo, targetInfo);
  return((infoPercentage + namePercentage) /2);
}

void displayPerson(struct person_ *person)
{
  debugPrint("%s, %s %s: %s %s; match percentage = %3.2f\n", 
	     person->lastName, person->firstName,
	     person->middleName, person->ssn, person->dob, person->matchScore);
}

void insertPerson
  (struct person_ *person, struct person_ **first, struct person_ **last)
{
  if (!*last)
  {
    *first = person;
    *last = person;
  } 
  else
    (*last)->next = person;
  person->next = NULL;
  person->prev = *last;
  *last = person;
}

void getPeopleFromTable(struct person_ **first, struct person_ **last)
{
  int counter = 0;
  float matchScore;
  struct person_ *person, *temp;
  DBPROCESS *dbprocess;
  DBCHAR lastName[lastNameLength+1];
  DBCHAR firstName[firstNameLength+1];
  DBCHAR middleName[middleNameLength+1];
  DBCHAR ssn[ssnLength+1];
  DBCHAR dob[dobLength+1];    
  LOGINREC *loginrec;
  RETCODE retcode;
  if (dbinit() == FAIL)
    exit(ERREXIT);
  dberrhandle(err_handler);
  dbmsghandle(msg_handler);
  dbsetifile(interface);
  loginrec = dblogin();
  DBSETLUSER(loginrec, username);
  DBSETLPWD(loginrec, password);
  dbprocess = dbopen(loginrec, NULL);
  dbuse(dbprocess, dbName);
  dbcmd(dbprocess, "select last_name, first_name, middle_name, ssn, ");
  dbcmd(dbprocess, "substring(convert(char(8), ");
  dbcmd(dbprocess, "datepart(year, date_of_birth) * 10000 + ");
  dbcmd(dbprocess, "datepart(month, date_of_birth) * 100 + ");
  dbcmd(dbprocess, "datepart(day, date_of_birth)), 5, 5) ");
  dbcmd(dbprocess, "from warehouse_person ");
  debugPrint("Before dbsqlexec time = %d\n", time(NULL));
  dbsqlexec(dbprocess);
  debugPrint("After  dbsqlexec time = %d\n", time(NULL));
  temp = (struct person_ *) malloc(sizeof(struct person_));
  if (!temp)
  {
    debugPrint(msgMemoryError);
    return;
  }  /* if (!temp) */

  while ((retcode = dbresults(dbprocess)) != NO_MORE_RESULTS)
  {
    if (retcode == SUCCEED)
    {
      counter++;
      debugPrint("Before dbbind time = %d\n", time(NULL));
      
      dbbind(dbprocess, 1, NTBSTRINGBIND, (DBINT)0, temp->lastName);
      dbbind(dbprocess, 2, NTBSTRINGBIND, (DBINT)0, temp->firstName);
      dbbind(dbprocess, 3, NTBSTRINGBIND, (DBINT)0, temp->middleName);
      dbbind(dbprocess, 4, NTBSTRINGBIND, (DBINT)0, temp->ssn);
      dbbind(dbprocess, 5, NTBSTRINGBIND, (DBINT)0, temp->dob);
      debugPrint("After  dbbind time = %d\n", time(NULL));
      debugPrint("Before match time = %d\n", time(NULL));

      while (dbnextrow(dbprocess) != NO_MORE_ROWS)
      {
        matchScore = evaluation(temp, target);
        if (matchScore > maybeMatch)
        {
          person = (struct person_ *) malloc(sizeof(struct person_));
          if (!person)
          {
            debugPrint(msgMemoryError);
            return;
          }  /* if (!person) */
          strcpy(person->lastName, temp->lastName);
          strcpy(person->firstName, temp->firstName);
          strcpy(person->middleName, temp->middleName);
          strcpy(person->ssn, temp->ssn);
          strcpy(person->dob, temp->dob);
          person->matchScore = matchScore;
          insertPerson(person, first, last);
        } /* if (evaluateion() > maybeMatch) */
      } /* while (dbnextrow(dbprocess) != NO_MORE_ROWS) */
      debugPrint("After  match time = %d\n", time(NULL));
    } /*    if (retcode == SUCCEED) */
  } /*  while ((retcode = dbresults(dbprocess)) != NO_MORE_RESULTS) */
  /*  debugPrint("Total Number of counter = %d\n", counter); */
  dbexit();
}

int setEnvironment(int overwrite)
{
  if (setenv("SYBASE", ENV_SYBASE, overwrite))
     return(FAIL);
  if (setenv("DSLISTEN", ENV_DSLISTEN, overwrite))
     return(FAIL);
  if (setenv("DSQUERY", ENV_DSQUERY, overwrite))
     return(FAIL);
  return(SUCCEED);
}

void generateErrTran(unsigned long errCode)
{
  long numOfBytes;
  char errMsg[]="Error has been detected.\nWatch out for what you are doing!!!\n";
  
  numOfBytes=strlen(EOM);
  /* debugPrint("The error code = %d\n", errCode); */
  printf("999:%d:0:%d\n", errCode, (numOfBytes += strlen(errMsg)));
  printf(errMsg);
  printf(EOM);
  exit(errCode);
}

int allocateLogFile(char fileName[])
{
  if ((logFileFp=fopen(fileName, "w"))==NULL)
     return(kalloLogFileErr);

  return(SUCCEED);
}

void deallocateLogFile()
{
  fclose(logFileFp);
}

int getChoices(struct person_ *ptr)
{
  unsigned long numOfRec=0, numOfBytes=strlen(EOM);
  struct person_ *temp;

  if (temp==NULL)
     return(SUCCEED);

  temp=ptr;
  while (temp)
  {
    numOfRec++;
    numOfBytes=numOfBytes+strlen(temp->mitId)+
               strlen(temp->firstName)+strlen(temp->middleName)+
	       strlen(temp->lastName)+strlen(temp->ssn)+
	       strlen(temp->dob)+6; /* 6 for 5':' and 1'\n' */
    temp = temp->next;
  }
  printf("002:0:%u:%u\n", numOfRec, numOfBytes);
  debugPrint("002:0:%u:%u\n", numOfRec, numOfBytes); 
  temp=ptr;
  while (temp)
  {
    printf("%s:%s:%s:%s:%s:%s\n",
	   temp->mitId, temp->firstName, temp->middleName,
	   temp->lastName, temp->ssn, temp->dob);
    temp=temp->next;
  }

  printf(EOM);

  return (SUCCEED);
}

int getNewId()
{
  char newRec[]="234567890:scott:e:thorne:123456789:1010";

  printf("003:0:1:%d\n", strlen(newRec));
  printf("%s\n", newRec);
  printf(EOM);

  return(SUCCEED);
}

