#include    <stdio.h>
#include    <string.h>
#include    <ctype.h>
#include    "fl.h"

#define MAXDELIM                10


//
//    formletter program version 1.0
//
//    usage: fl format < datafile
//
//    data comes from stdin, output goes to stdout
//

static char *myname;                            // used by fatal()

int main(int ac, char *av[])
{
    FILE *fpfmt, *fpdata;
    
    int i;

    myname = *av;

    // check that there is at least one arg: the format file
    if ( ac == 1 )
        fatal("usage: fl format [datafile..]","");

    // open format file
    if ((fpfmt = fopen( av[1] , "r")) == NULL )
        fatal("Cannot open format file:", *av);

    if (ac == 2)
        process(fpfmt, stdin);
    else {
        for (i = 2; i < ac; i++) {
            if ((fpdata = fopen( av[i] , "r")) == NULL )
                fatal("Cannot open data file:", av[i]);
            else
                process(fpfmt, fpdata);
        }
    }
    return 0;
}


void fatal(char *s1, char *s2)
//
//    fatal error handler
//    purpose: print error message to stderr then exit
//    input:   two strings that are printed 
//    never returns
//
{
    fprintf(stderr, "%s: %s%s\n",  myname, s1, s2 );
    exit(1);
}

int get_record(symtab_t tp, FILE *fp)
{
    int  itemDelim[MAXDELIM] = {':','\n','\t', '=', '\0'};

    char line[BUFLEN],
         fieldName [BUFLEN],
         fieldValue[BUFLEN],
         mChar = '\0';
    
    initArray(fieldName,  BUFLEN);

    do {

        // read segment
        mChar = readSeg(itemDelim, fp, line);
        // trimWhiteSpace(line);

        if (mChar == '=') {                              // read field name
            if (! *line)
                fatal("Field with blank fieldname.", "");
            else
                strncpy(fieldName, line, MAXFLD);
            
            // remove '=' from item delim list
            // allows for field entry containing equals.
            itemDelim[3] = '\0';
        }
        else if (*fieldName) {                           // read field value
            
            // save values
            strncpy(fieldValue, line, MAXVAL);
            insert(tp,  fieldName, fieldValue);
            
            // empty first val
            initArray(fieldName,  BUFLEN);
            
            // include '=' in item delim list
            itemDelim[3] = '=';
        }
        else if (*line)                                 // bad value
            fatal("Field entry without equals: ", line);
        else if (! *line && mChar == '\n')              // empty line
            mChar = '\0' ;
                        
    } while (mChar != EOF && mChar != '\n');
    
    return (mChar == EOF ? NO : YES);
}


void mailmerge(symtab_t tp, FILE *fmt)
{
    //
    // copies characters from the format stream at *fmt to stdout
    // inserting values for fields when it sees an insertion point ('%')
    //

    int  itemDel[MAXDELIM] = {'%','\n','\0'};
    char line[BUFLEN],
         mChar = '\0';
    int  mode = 0;                     // mode 1 when getting var

    static int recordCount = 0;        // static counter of records processed

    recordCount++;

    do {

        mChar    = readSeg(itemDel, fmt, line);

        if (mChar == '%') {            // ... start reading string
            if (mode) {
                if (! *line)           // two % in a row              
                    printf("%%");
                else if (strcmp(line, "=RECORDNUMBER") == 0)
                    printf("%d", recordCount);
                else
                    if (lookup(tp, line) != NULL)   // lookup and display var
                        printf("%s", lookup(tp, line));
                mode = 0;              // mode off
            }
            else {
                printf("%s", line);    // print text preceeding '%'
                mode = 1;              // mode on
            }
        }
        else {
            if (mode)
                fatal("Unterminated fieldname:", line);
            printf("%s", line);
        }

        if (mChar == '\n')
            printf("\n");
                
    } while (mChar != EOF);
    
    // rewind format file
    fseek(fmt, 0L, 0);
}


char readSeg(int itemDel[], FILE *fp, char line[BUFLEN])
{
    //
    // read chars into targetField until reaching
    // an item delimiter (itemDel[]), return delimiter reached
    //
    
    char mChar;               // my char from stream
    int  i, 
         endStr    = NO,
         charCount = 0;
    
    // empty target String
    initArray(line, BUFLEN);

    do {

        // get a char
        mChar = fgetc(fp);

        // check for delimiter
        for (i = 0; itemDel[i]; i++)
            if (mChar == itemDel[i] || mChar == EOF )
                endStr = YES;

        // append char to target string
        if ( ! endStr)
            line[charCount] = mChar;
        
        charCount++;

    } while (! endStr);

    // conclude target string
    line[charCount] = '\0';

    return mChar;
}


// Lib

void initArray(char mArray[], int arraySize)
{
    //
    // ensure all values in array are set to '\0'

    int i;
    
    for (i = 0;  i <= arraySize-1 ; i++) {
        mArray[i] = '\0';
    }
}


void trimWhiteSpace(char source[])
{
    //
    // remove all leading and trailing whitespace (including '\n')
    
    int  i;
    char target[BUFLEN];
    
    // strip trailing whitespace
    for (i = strlen(source)-1; isspace((int)source[i]) && i >= 0 ; i-- ) {
        source[i] = '\0';
    }

    // count leading whitespace
    for (i = 0; isspace((int)source[i]) ; i++) {
    }

    // copy into target
    strcpy(target, &source[i]);

    // copy back to source
    strcpy(source, target);
}
