/*

Before extraction:
"First:Middle:Last:SSN:DOB[mmdd]"
30c:30c:30c:9d:4d
 
After extraction:
30c[A-Z]:30c[A-Z]:30c[A-Z]:9d:4d

*/
#define _POSIX_SOURCE 1

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

#define kwrongArgErr	21
#define knumColonErr	22
#define kSSNErr		23
#define kDOBErr		24
#define kfirstNameLenErr	25
#define kmiddleNameLenErr	26
#define klastNameLenErr		27
#define kssnLenErr		28
#define kdobLenErr		29
#define kinputNotEnoughErr	30
#define kinvTranTypeErr         31

#define knumOfColon	4
#define DLM		':'
#define knameLen	30
#define kssnLen		9
#define kdobLen		4
#define kfirstVal	16
#define kmiddleVal	8
#define klastVal	4
#define kssnVal		2
#define kdobVal		1

long  inProtocolParser(char inProtocol[], 
		       struct arguments_ *original,
		       struct arguments_ *normalized);
long inStrParser(char inStr[],
		 struct arguments_ *original,
		 struct arguments_ *normalized);
int checkNum(char *str);
void filter_str(char *s1, char *s2);
char *next_field(char **ptr, char delimiter);

#ifdef DebugParserMain
main(int argc, char *argv[])
{
  struct arguments_ original, normalized;
  int rc;

  if ((rc=inProtocolParser(argv[1], &original, &normalized))==SUCCEED)
  {
    printf("Original ttStr = %s\n", original.ttStr);
    printf("Original ttInt = %d\n", original.ttInt);
    printf("Original first name = %s\n", original.firstName);
    printf("Original middle name = %s\n", original.middleName);
    printf("Original last name = %s\n", original.lastName);
    printf("Original ssn = %s\n", original.ssn);
    printf("Original dob = %s\n", original.dob);
    printf("Normalized ttStr = %s\n", normalized.ttStr);
    printf("Normalized ttInt = %d\n", normalized.ttInt);
    printf("Normalized first name = %s\n", normalized.firstName);
    printf("Normalized middle name = %s\n", normalized.middleName);
    printf("Normalized last name = %s\n", normalized.lastName);
    printf("Normalized ssn = %s\n", normalized.ssn);
    printf("Normalized dob = %s\n", normalized.dob);

  }
  else printf("Return code = %d\n", rc);
}
#endif

/*
Function:
  1) It checks the input format and filters the input.
Input:
  1) String with this format "30c:30c:30c:9d:4d" expected.
Output:
  1) return code
     a) 0 if successful
     b) non-zero if failed.
  2) pointer to original input structure.
  3) pointer to normalized input structure.
Return code:
  1) SUCCESS - successful.
  2) FAIL - fail.
*/

long inProtocolParser(char inProtocol[],
                     struct arguments_ *original,
                     struct arguments_ *normalized)
{
  char *strPtr;
  long retCode=SUCCEED;

  strPtr=inProtocol;
  next_field(&inProtocol, DLM);

  strcpy(original->ttStr, strPtr);
  strcpy(normalized->ttStr, strPtr);
  original->ttInt=normalized->ttInt=atoi(strPtr);

  switch (original->ttInt)
  {
  case 1: 
    retCode=inStrParser(inProtocol, original, normalized);
    break;
  default:
    retCode=kinvTranTypeErr;
    break;
  }
  return (retCode);
}

long inStrParser(char inStr[],
		 struct arguments_ *original,
		 struct arguments_ *normalized)
{
  int rc;
  int strCnt;
  int i;
  int inputInd;
  char *firstPtr, *middlePtr, *lastPtr, *ssnPtr, *dobPtr;
  char inputTable[32]={0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1};

/*
First	Middle	Last	SSN	DOB	Accept
-----	------	----	---	---	------
0	0	0	0	0	0
0	0	0	0	1	0
0	0	0	1	0	1
0	0	0	1	1	1
0	0	1	0	0	0
0	0	1	0	1	0
0	0	1	1	0	1
0	0	1	1	1	1
0	1	0	0	0	0
0	1	0	0	1	0
0	1	0	1	0	1
0	1	0	1	1	1
0	1	1	0	0	0
0	1	1	0	1	0
0	1	1	1	0	1
0	1	1	1	1	1
1	0	0	0	0	0
1	0	0	0	1	0
1	0	0	1	0	1
1	0	0	1	1	1
1	0	1	0	0	1
1	0	1	0	1	1
1	0	1	1	0	1
1	0	1	1	1	1
1	1	0	0	0	0
1	1	0	0	1	0
1	1	0	1	0	1
1	1	0	1	1	1
1	1	1	0	0	1
1	1	1	0	1	1
1	1	1	1	0	1
1	1	1	1	1	1
*/ 

#ifdef DebugParser
  printf("Start counting colon\n");
#endif

  i=strCnt=0;
  while (inStr[i])
    if (inStr[i++]==':')
	strCnt++;
  if (strCnt!=knumOfColon)
  {
    rc=knumColonErr;
#ifdef simpleRet
        rc=FAIL;
#endif
     return(rc);
  }

#ifdef DebugParser
  printf("No. of Colon is right\n");
#endif

  firstPtr=inStr;
  middlePtr=next_field(&inStr, DLM);
  lastPtr=next_field(&inStr, DLM);
  ssnPtr=next_field(&inStr, DLM);
  dobPtr=next_field(&inStr, DLM);

  if (strlen(firstPtr) > knameLen)
  {   
     rc = kfirstNameLenErr;
#ifdef simpleRet
     rc = FAIL;
#endif
     return(rc);
  }

  if (strlen(middlePtr) > knameLen)
  {
     rc = kmiddleNameLenErr;
#ifdef simpleRet
     rc = FAIL;
#endif
     return(rc);
  }

  if (strlen(lastPtr) > knameLen)
  {
     rc = klastNameLenErr;
#ifdef simpleRet
     rc = FAIL;
#endif
     return(rc);
  }

  if (strlen(ssnPtr) > kssnLen)
  {
     rc = kssnLenErr;
#ifdef simpleRet
     rc = FAIL;
#endif
     return(rc);
  }

  if (strlen(dobPtr) > kdobLen)
  {
     rc = kdobLenErr;
#ifdef simpleRet
     rc = FAIL;
#endif
     return(rc);
  }

  inputInd=0;
  if (*firstPtr != '\0')
     inputInd += kfirstVal;
  if (*middlePtr != '\0')
     inputInd += kmiddleVal;
  if (*lastPtr != '\0')
     inputInd += klastVal;
  if (*ssnPtr != '\0')
     inputInd += kssnVal;
  if (*dobPtr != '\0')
     inputInd += kdobVal;
  
  if (inputTable[inputInd]==0)
  {
     rc = kinputNotEnoughErr;
#ifdef simpleRet
     rc = FAIL;
#endif
     return(rc);
  }

  strcpy(original->firstName, firstPtr); 
  strcpy(original->middleName, middlePtr); 
  strcpy(original->lastName, lastPtr); 
  strcpy(original->ssn, ssnPtr); 
  strcpy(original->dob, dobPtr); 

#ifdef DebugParser
  printf("Assignment is done\n");
#endif

  if (checkNum(ssnPtr)==FAIL) /* not digit detected */
  {
    rc=kSSNErr;
#ifdef simpleRet
    rc=FAIL;
#endif
    return(rc);
  }

  if (checkNum(dobPtr)==FAIL) /* not digit detected */
  {
    rc=kDOBErr;
#ifdef simpleRet
    rc=FAIL;
#endif
    return(rc);
  }

  filter_str(original->firstName, normalized->firstName);
  filter_str(original->middleName, normalized->middleName);
  filter_str(original->lastName, normalized->lastName);
  strcpy(normalized->ssn, original->ssn);
  strcpy(normalized->dob, original->dob);

  return(SUCCEED);
}

int checkNum(char *str)
{
  while (*str!='\0')
    if (!isdigit(*str++)) /* not digit detected */
        return(FAIL);
  return(SUCCEED);
}

void filter_str(char *s1, char *s2)
{
  while (*s1!='\0')
    if (isalpha(*s1++)) /* not digit detected */
        *s2++ = toupper(*(s1-1));
  *s2='\0';
}

char *next_field(char **ptr, char delimiter)
{
  register char *cp = *ptr;

  while (*cp != NULL && *cp != delimiter)
         cp++;
  if (*cp == NULL)
     return (*ptr = cp);

  *cp = '\0';
  return (*ptr = ++cp);
}
