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

#if defined ( __GNUC__ )  || ( _MSC_VER )
#   if defined ( _MSC_VER ) && ( _MSC_VER >= 1020 )
#       pragma warning ( disable : 4996 )
#       pragma warning ( disable : 4172 )
#   endif

#ifndef BUFSIZ
#define BUFSIZ      512
#endif

#ifndef NULL
#define NULL        0
#endif

#ifndef FALSE
#define FALSE       0
#endif

#ifndef TRUE
#define TRUE        1
#endif

#define MAXREC      10
#define MAXWORKDAYS 5

const float SALARYLEVEL1    =   380.00;
const float SALARYLEVEL2    =   450.00;
const float SALARYLEVEL3    =   550.00;

const float WEEKLYALLOWANCE =   500.00;

/* Nested structs to hold employee data */

typedef struct _DAILYTIMERECORD
{
    double regularhoursworked;
    time_t regulartimein;
    time_t regulartimeout;
    double overtimehoursworked;
    time_t overtimein;
    time_t overtimeout;
    double latehours;
    double undertimehours;
    size_t holiday;

} DAILYTIMERECORD;


typedef struct _WEEKLYTIMERECORD
{
    char coveragedate[BUFSIZ];
    double regularincome;
    double overtimeincome;
    double grossincome;
    double netincome;
    double taxdeductions;
    double sssdeductions;
    double totalweeklyregularhoursworked;
    double totalweeklyovertimehoursworked;
    DAILYTIMERECORD dailytimerecord[MAXWORKDAYS];

} WEEKLYTIMERECORD;


typedef struct _EMPLOYEERECORD
{
    char code[BUFSIZ];
    char name[BUFSIZ];
    size_t level;
    double rate;
    WEEKLYTIMERECORD weeklytimerecord;

} EMPLOYEERECORD;

/****************************************/


/* Employee Records Container. Can hold maximum of MAXREC records */
static EMPLOYEERECORD records[MAXREC] = { 0 };

static char * workdays[MAXWORKDAYS] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };

typedef enum _InputFilter { EMPCODEINPUT, EMPTIMEINPUT, EMPCOVDATEINPUT } InputFilter;
typedef enum _WorkDay { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY } WorkDay;
typedef enum _PrintInfo { EMPLOYEEINFO, EMPLOYEEHOURS } PrintInfo;


//*********************** Function Prototypes *************************//

int ReadEmployeeRecords( const char * );
int WriteEmployeeTimeRecords ( char *, size_t );
int FindEmployeeRecord ( const char * );
int FilterInput ( char *, InputFilter );
char * GetEmployeeCodeInput ( );
void GetEmployeeRegularHours ( size_t, size_t );
void GetEmployeeOvertimeHours ( size_t, size_t );
void GetHoliday ( size_t, size_t );
void GetCoverageDate ( size_t );
void ComputeWeeklySalary ( size_t );
void DisplayRecords ( PrintInfo, size_t, size_t );
int RunApp ( );
void ResetRecords ( size_t );

//*********************************************************************//



/* Main entry */
int main ( int argc, char ** argv )
{
    if ( RunApp () < 0 )
        exit ( EXIT_FAILURE );

    return 0;
}

/*
    Read records from the file pointed to by filein.
*/
int ReadEmployeeRecords( const char * filein )
{
    FILE * pfile;
    char * linebuffer;
    char * pch;
    const char * delim = ":";
    size_t index = 0;

    pfile = fopen ( filein, "r" );
    if ( pfile == NULL )
    {
        printf ( "Error opening file %s: %s\n", filein, strerror ( errno ) );
        return -1;
    }

    linebuffer = ( char * ) malloc ( sizeof ( char ) * BUFSIZ );
    if ( linebuffer == NULL )
    {
        fclose ( pfile );
        printf ( "Error allocating memory space.\n" );
        return -1;
    }

    while ( fgets ( linebuffer, BUFSIZ, pfile ) )
    {
        if ( index == MAXREC )
        {
            /* printf ( "Maximum number of %d records allowed in records container has been reached.\n", MAXREC ); */
            free ( linebuffer );
            fclose ( pfile );
            return 0;
        }

        if ( ferror ( pfile ) != 0 )
        {
            printf ( "Error reading from input file %s: %s\n", 
                filein, strerror ( errno ) );
            free ( linebuffer );
            fclose ( pfile );
            return -1;
        }

        if ( linebuffer[0] == '#' || linebuffer[0] == '\n' )
            continue;

        linebuffer[strlen ( linebuffer ) - 1] = '\0';

        pch = strtok ( linebuffer, delim );
        memcpy (records[index].code, pch, strlen ( pch ) );
        records[index].code[strlen ( pch ) ] = '\0';

        pch = strtok ( NULL, delim );
        memcpy (records[index].name, pch, strlen ( pch ) );
        records[index].name[strlen ( pch ) ] = '\0';

        pch = strtok ( NULL, delim );
        sscanf ( pch, "%d", &records[index].level );

        if ( records[index].level == 1 )
            records[index].rate = SALARYLEVEL1;
        else if ( records[index].level == 2 )
            records[index].rate = SALARYLEVEL2;
        else if ( records[index].level == 3 )
            records[index].rate = SALARYLEVEL3;

        ++index;
    }

    free ( linebuffer );

    return 0;
}

/*
    Write records to dtr.txt.
*/
int WriteEmployeeTimeRecords ( char * fileout, size_t index )
{
    FILE * pfile;
    int ret = -1;

    struct tm * tminfo;
    char buffer[BUFSIZ];
    size_t i;

    pfile = fopen ( fileout, "a" );
    if ( pfile == NULL )
    {
        printf ( "Error opening file %s: %s\n", fileout, strerror ( errno ) );
        return ret;
    }


    fprintf ( pfile, "%s|", records[index].code );

    for ( i = MONDAY; i <= FRIDAY; ++i )
    {
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].regulartimein );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );
        if ( fprintf ( pfile, "%s|", buffer ) < 0 )
            break;

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].regulartimeout );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );
        if ( fprintf ( pfile, "%s|", buffer ) < 0 )
            break;

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].overtimein );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );
        if ( fprintf ( pfile, "%s|", buffer ) < 0 )
            break;

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].overtimeout );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );

        if ( i == FRIDAY )
        {
            if ( fprintf ( pfile, "%s\n", buffer ) < 0 )
                break;
        }
        else
        {
            if ( fprintf ( pfile, "%s|", buffer ) < 0 )
                break;
        }

        ret = 0;
    }

    fclose ( pfile );

    return ret; 
}

/*
    Attempt to locate a matching string defined by pointer to parameter rec.
*/
int FindEmployeeRecord ( const char * rec )
{
    char * pch;
    int i, found = -1;

    if ( rec == NULL )
        return -1;

    for ( i = 0; i < MAXREC; ++i )
    {
        pch = strstr ( records[i].code, rec );
        if ( pch != NULL )
        {
            found = i;
            break;
        }
    }

    return found;
}

/*
    Check the format of the string input.
*/
int FilterInput ( char * input, InputFilter filter )
{
    const int EMPCODEMAXLEN     = 8;
    const int EMPTIMEINPUTLEN   = 5;
    const int EMPCOVDATELEN     = 15;
    int ret = -1;


    if ( input[0] == '\n' )
    {
        ret = 0;
        return ret;
    }

    input[ strlen ( input ) - 1 ] = '\0';


    switch ( filter )
    {
        case EMPCODEINPUT       :   if ( strlen ( input ) != EMPCODEMAXLEN )
                                        ret = -1;
                                    else if ( ! ( ( input[0] == 'A' && input[3] == '-' )        &&
                                                  ( input[1] >= '0' && input[1] <= '9' )     &&
                                                  ( input[2] >= '0' && input[2] <= '9' )     &&
                                                  ( input[4] >= '0' && input[4] <= '9' )     &&
                                                  ( input[5] >= '0' && input[5] <= '9' )     &&
                                                  ( input[6] >= '0' && input[6] <= '9' )     &&
                                                  ( input[7] >= '0' && input[7] <= '9' ) ) )

                                                    ret = -1;
                                    else
                                                    ret = 0;
                                    break;

        case EMPTIMEINPUT       :   if ( strlen ( input ) != EMPTIMEINPUTLEN )
                                        ret = -1;
                                    else if ( ! ( ( input[0] >= '0' && input[0] <= '2' )     &&
                                                  ( input[1] >= '0' && input[1] <= '9' )     &&
                                                  ( input[2] == ':' )                           &&
                                                  ( input[3] >= '0' && input[3] <= '5' )     &&
                                                  ( input[4] >= '0' && input[3] <= '9' ) ) )

                                                ret = -1;
                                    else
                                                ret = 0;
                                    break;

        case EMPCOVDATEINPUT    :   if ( strlen ( input ) != EMPCOVDATELEN )
                                        ret = -1;
                                    else if ( ! ( ( input[0] >= 'A' && input[0] <= 'Z' )     &&
                                                  ( input[1] >= 'a' && input[1] <= 'z' )     &&
                                                  ( input[2] >= 'a' && input[2] <= 'z' )     &&
                                                  ( isspace ( input[3] ) )                      &&
                                                  ( input[4] >= '0' && input[4] <= '2' )     &&
                                                  ( input[5] >= '0' && input[5] <= '9' )     &&
                                                  ( input[6] == '-' )                           &&
                                                  ( input[7] >= '0' && input[7] <= '3' )     &&
                                                  ( input[8] >= '0' && input[8] <= '9' )     &&
                                                  ( input[9] == ',' )                           &&
                                                  ( isspace ( input[10] ) )                     &&
                                                  ( input[11] == '2' )                          &&
                                                  ( input[12] == '0'    )                       &&
                                                  ( input[13] >= '0' && input[13] <= '1' )       &&
                                                  ( input[14] >= '0' && input[14] <= '9' ) ) )

                                                ret = -1;
                                    else
                                                ret = 0;
                                    break;

        default                 :   printf ( "Invalid filter code.\n");
                                    break;

    }

    return ret;
}

/*
    Retrieve employee code from input stream.
*/
char * GetEmployeeCodeInput ( )
{
    char buffer[BUFSIZ];

    while ( TRUE )
    {
        printf ( "Enter Employee Code (AXX-XXXX): " );

        fgets ( buffer, BUFSIZ, stdin );

        buffer[0] = toupper ( buffer[0] );

        if ( FilterInput ( buffer, EMPCODEINPUT ) < 0 )
        {
            printf ( "Invalid input.\n" );
            continue;
        }

        return buffer;
    }
}


/*
    Get employee regular hours.
*/
void GetEmployeeRegularHours ( size_t index, size_t day )
{
    char tmpbuf[BUFSIZ];
    struct tm * tminfo;
    double diff = 0.0;

    while ( TRUE )
    {
        printf ( "Enter Time-in for %s (00:00): ", workdays[day] );

        fgets ( tmpbuf, BUFSIZ, stdin );

        if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
        {
            printf ( "Invalid Time-in input format for %s.\n", workdays[day] );
            continue;
        }

        /* Valid input format for time-in */
        time ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimein );
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimein );

        /* We only need to invalidate the hour/min/sec */
        tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

        /* If string other than newline was entered... */ 
        if ( tmpbuf[0] != '\n' )
        {
            tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
            tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
        }
        else /* ...else, make a dummy regular time in/out with zero hour/min/sec */
        {
            records[index].weeklytimerecord.dailytimerecord[day].regulartimein  = mktime ( tminfo );
            records[index].weeklytimerecord.dailytimerecord[day].regulartimeout = mktime ( tminfo );
            return;
        }

        /* Valid regular time-in must be between 07:00 and 17:00 */
        if ( tminfo->tm_hour < 7 || tminfo->tm_hour > 16 )
        {
            printf ( "Invalid Time-in for %s, hours must be between 07:00 - 16:00.\n", workdays[day] );
            continue;
        }

        /* Latest start work hour must not exceed 16:00 */
        if ( tminfo->tm_hour == 16 && tminfo->tm_min > 0 )
        {
            printf ( "Invalid Time-in for %s, latest work hour must be 16:00.\n", workdays[day] );
            continue;
        }

        /*  
            Check if the employee came in late for work.
            If so, find out how many hours late then record it.
        */
        if ( tminfo->tm_hour > 8 )
        {
            records[index].weeklytimerecord.dailytimerecord[day].latehours = tminfo->tm_hour - 8;
        }

        /* If we arrived here then we have a valid regular time-in input */
        records[index].weeklytimerecord.dailytimerecord[day].regulartimein = mktime ( tminfo );

        /* Get regular time-out input */
        while ( TRUE )
        {
            printf ( "Enter Time-out for %s (00:00): ", workdays[day] );

            fgets ( tmpbuf, BUFSIZ, stdin );

            if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
            {
                printf ( "Invalid Time-out input format for %s.\n", workdays[day] );
                continue;
            }

            /* Valid input format for regular time-out */
            time ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimeout );
            tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimeout );

            tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

            if ( tmpbuf[0] != '\n' )
            {
                tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
                tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
            }
            else
                continue;

            if ( tminfo->tm_hour > 17 )
            {
                printf ( "Time-out hour cannot be greater than 15:00.\n" );
                continue;
            }

            /* If we arrived here then we have a valid regular time-out input */
            records[index].weeklytimerecord.dailytimerecord[day].regulartimeout = mktime ( tminfo );

            break;
        }

        /* Find the difference between time-out and time-in hours for this day */
        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].regulartimeout,
                            records[index].weeklytimerecord.dailytimerecord[day].regulartimein );

        /*
            If this employee worked from 08:00 - 17:00, we need to subtract lunch hour so
            he/she will have a full 8 hours of work time.
        */
        if ( diff > 28800 )
        {
            diff -= 3600;
        }

        /* Time-out hour cannot be less than Time-in */
        if ( diff <= 0 )
        {
            printf ( "Time-out hour cannot be less than or equal to Time-in hour.\n" );
            continue;
        }

        /* Difference between time-in and time-out must be at least one hour */
        if ( diff - 3600 < 3600 )
        {
            printf ( "Difference between Time-in and Time-out must be greater than one hour.\n" );
            continue;
        }

        /* The hours input is valid, get the total regular hours worked for this day */
        records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked = diff / 3600;


        /* Check for late hours */
        tminfo->tm_hour = 8; tminfo->tm_min = 0; tminfo->tm_sec = 0;

        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].regulartimein, mktime ( tminfo ) );

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimein );

        if ( tminfo->tm_hour <= 0 )
            records[index].weeklytimerecord.dailytimerecord[day].latehours = 0;
        else
            records[index].weeklytimerecord.dailytimerecord[day].latehours = tminfo->tm_hour - 8;


        /* Check for undertime hours */
        tminfo->tm_hour = 17; tminfo->tm_min = 0; tminfo->tm_sec = 0;

        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].regulartimeout, mktime ( tminfo ) );

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimeout );

        if ( tminfo->tm_hour >= 17 )
            records[index].weeklytimerecord.dailytimerecord[day].undertimehours = 0;
        else
            records[index].weeklytimerecord.dailytimerecord[day].undertimehours = 17 - tminfo->tm_hour;


        /* Is this day a holiday */
        GetHoliday ( index, day );


        /*
            If it is a holiday, make necessary adjustments by switching regular hours worked
            and overtime hours worked. Note that this day will still show up as regular hours
            in dtr.txt.
        */
        if ( records[index].weeklytimerecord.dailytimerecord[day].holiday == 1 )
        {
            records[index].weeklytimerecord.dailytimerecord[day].overtimehoursworked
                = records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked;

            records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked = 0;
        }

        break;
    }
}


/*
    Get employee regular hours.
*/
void GetEmployeeOvertimeHours ( size_t index, size_t day )
{
    char tmpbuf[BUFSIZ];
    struct tm * tminfo;
    double diff = 0.0;

    /* If this day is a holiday just return since it is already overtime pay */
    if ( records[index].weeklytimerecord.dailytimerecord[day].holiday == 1 )
    {
        time ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );
        tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;
        records[index].weeklytimerecord.dailytimerecord[day].overtimein     = mktime ( tminfo );
        records[index].weeklytimerecord.dailytimerecord[day].overtimeout    = mktime ( tminfo );

        return;
    }

    /* Make sure the employee worked regular hours today before we process his/her overtime */
    if ( records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked == 0 )
        return;


    while ( TRUE )
    {
        printf ( "Enter Overtime-in for %s (00:00): ", workdays[day] );

        fgets ( tmpbuf, BUFSIZ, stdin );

        if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
        {
            printf ( "Invalid Overtime-in input format for %s.\n", workdays[day] );
            continue;
        }

        /* Valid input format for overtime-in */
        time ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );

        /* We only need to invalidate the hour/min/sec */
        tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

        /* If string other than newline was entered... */ 
        if ( tmpbuf[0] != '\n' )
        {
            tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
            tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
        }
        else /* ...else, make a dummy regular time in/out with zero hour/min/sec */
        {
            records[index].weeklytimerecord.dailytimerecord[day].overtimein     = mktime ( tminfo );
            records[index].weeklytimerecord.dailytimerecord[day].overtimeout    = mktime ( tminfo );
            return;
        }

        /* Valid overtime-in must begin at 17:30 */
        if ( ! ( tminfo->tm_hour == 17 && tminfo->tm_min == 30 ) )
        {
            printf ( "Overtime-in must begin at 17:30.\n" );
            continue;
        }

        /* If we arrived here then we have a valid overtime-in input */
        records[index].weeklytimerecord.dailytimerecord[day].overtimein = mktime ( tminfo );

        /* Get overtime-out input */
        while ( TRUE )
        {
            printf ( "Enter Overtime-out for %s (00:00): ", workdays[day] );

            fgets ( tmpbuf, BUFSIZ, stdin );

            if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
            {
                printf ( "Invalid Overtime-out input format for %s.\n", workdays[day] );
                continue;
            }

            /* Valid input for overtime-out*/
            time ( &records[index].weeklytimerecord.dailytimerecord[day].overtimeout );
            tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].overtimeout);

            tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

            if ( tmpbuf[0] != '\n' )
            {
                tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
                tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
            }

            if ( ! ( tminfo->tm_hour >= 18 && tminfo->tm_hour <= 20 ) )
            {
                printf ( "Overtime-out must be between 18:00 and 20:30.\n" );
                continue;
            }

            if ( tminfo->tm_hour == 18 && tminfo->tm_min < 30 )
            {
                printf ( "Overtime-out must be between 18:30 and 20:30.\n" );
                continue;
            }

            /* If we arrived here then we have a valid overtime-out input */
            records[index].weeklytimerecord.dailytimerecord[day].overtimeout = mktime ( tminfo );

            break;
        }

        /* Find the difference between overtime-out and overtime-in hours for this day */
        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].overtimeout,
                            records[index].weeklytimerecord.dailytimerecord[day].overtimein );

        /* The hours input is valid, get the total overtime hours worked for this day */
        records[index].weeklytimerecord.dailytimerecord[day].overtimehoursworked = diff / 3600;

        break;
    }
}


/*
    Check if this day is a holiday.
*/
void GetHoliday ( size_t index, size_t day )
{
    char buffer[BUFSIZ];

    while ( TRUE )
    {
        printf ( "Is %s a holiday (y/n)?: ", workdays[day] );

        fgets ( buffer, BUFSIZ, stdin );

        buffer[0] = tolower ( buffer[0] );

        if ( buffer[0] == 'y' )
            records[index].weeklytimerecord.dailytimerecord[day].holiday = 1;
        else if ( buffer[0] == 'n' )
            records[index].weeklytimerecord.dailytimerecord[day].holiday = 0;
        else
            continue;

        break;
    }
}


/*
    Get coverage date for this work week.
*/
void GetCoverageDate ( size_t index )
{
    char buffer[BUFSIZ];
    size_t i;

    while ( TRUE )
    {
        printf ( "Coverage Date (Ex: Mar 05-09, 2012) : " );

        memset ( buffer, 0, sizeof ( buffer ) );

        fgets ( buffer, BUFSIZ, stdin );

        buffer[0] = toupper ( buffer[0] );

        if ( FilterInput ( buffer, EMPCOVDATEINPUT ) < 0 )
        {
            printf ( "Invalid coverage date format.\n" );
            continue;
        }

        if ( buffer[7] == 3 && buffer[8] > 1 )
        {
            printf ( "Day cannot exceed 31.\n" );
            continue;
        }

        for ( i = MONDAY; i <= FRIDAY; ++i )
            strncpy ( records[index].weeklytimerecord.coveragedate, buffer, strlen ( buffer ) );

        break;
    }
}


/*
    Display employee work and hours information.
*/
void DisplayRecords ( PrintInfo pi, size_t index, size_t code )
{
        printf ( "\n******************************************************************************" );
        printf ("\nEmployee Name: %s\nEmployee Code: %s\nSalary Level: %d\nSalary Rate: Php %.2f/day\n",
            records[index].name, records[index].code, records[index].level, records[index].rate ); 
        printf ( "******************************************************************************\n" );

        if ( pi != EMPLOYEEINFO && code != -1 )
        {
            printf ( "Date Covered: %s\nTotal Number of Work Hours: %d Hrs.\nOvertime Hours: %d Hrs.\nRegular Income: Php %.2f\nOvertime Income: Php %.2f\nGross Income: Php %.2f\n",
                records[index].weeklytimerecord.coveragedate, ( int ) records[index].weeklytimerecord.totalweeklyregularhoursworked,
                ( int ) records[index].weeklytimerecord.totalweeklyovertimehoursworked,
                records[index].weeklytimerecord.regularincome, records[index].weeklytimerecord.overtimeincome,
                records[index].weeklytimerecord.grossincome );

            printf ( "Deductions:\n* Tax: Php %.2f\n* SSS: Php %.2f\nNet Income: %.2f\n",
                records[index].weeklytimerecord.taxdeductions, records[index].weeklytimerecord.sssdeductions, records[index].weeklytimerecord.netincome );

            printf ( "******************************************************************************\n\n" );
        }
}


/*
    Calculate weekly salary for this employee.
*/
void ComputeWeeklySalary ( size_t index )
{
    double hourlyrate = records[index].rate / 8;
    size_t i;

    for ( i = MONDAY; i <= FRIDAY; ++i )
    {
        /* 
            If the regular hours worked for this day is less than 8, we need to offset it.
            If we don't and there are late hours, those late hours are subtracted against
            regular hours worked twice.
        */
        if ( records[index].weeklytimerecord.dailytimerecord[i].regularhoursworked < 8 )
            records[index].weeklytimerecord.dailytimerecord[i].regularhoursworked = 8;

        /* Add all regular hours worked for this week */
        records[index].weeklytimerecord.totalweeklyregularhoursworked 
            += records[index].weeklytimerecord.dailytimerecord[i].regularhoursworked
            - ( records[index].weeklytimerecord.dailytimerecord[i].latehours
            + records[index].weeklytimerecord.dailytimerecord[i].undertimehours );

        /* Add all overtime hours worked for this week */
        records[index].weeklytimerecord.totalweeklyovertimehoursworked 
            += records[index].weeklytimerecord.dailytimerecord[i].overtimehoursworked;
    }

    /* Regular and Overtime income */
    records[index].weeklytimerecord.regularincome 
        = hourlyrate 
        * ( int ) records[index].weeklytimerecord.totalweeklyregularhoursworked;



/*
    NC4 COC2 (Procedural) - Reviewer.

    For educational purposes only! Do not sell this code!

    Disclaimer:
    This source code is based on my interpretations of the specifications described in:
    COMPUTER PROGRAMMING NC IV (COC 2 DEVELOP APPLICATIONS USING PROCEDURAL – PROGRAMMING LANGUAGE).
    However, I do not guarantee the correctness of this code.

    Your can freely distribute this as long as proper credit is given to the author.

    ezroot - 6/19/2012
*/

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

/* Needs gcc or MSVC */
#if defined ( __GNUC__ )  || ( _MSC_VER )
#   if defined ( _MSC_VER ) && ( _MSC_VER >= 1020 )
#       pragma warning ( disable : 4996 )
#       pragma warning ( disable : 4172 )
#   endif

#ifndef BUFSIZ
#define BUFSIZ      512
#endif

#ifndef NULL
#define NULL        0
#endif

#ifndef FALSE
#define FALSE       0
#endif

#ifndef TRUE
#define TRUE        1
#endif

#define MAXREC      10
#define MAXWORKDAYS 5

const float SALARYLEVEL1    =   380.00;
const float SALARYLEVEL2    =   450.00;
const float SALARYLEVEL3    =   550.00;

const float WEEKLYALLOWANCE =   500.00;

/* Nested structs to hold employee data */

typedef struct _DAILYTIMERECORD
{
    double regularhoursworked;
    time_t regulartimein;
    time_t regulartimeout;
    double overtimehoursworked;
    time_t overtimein;
    time_t overtimeout;
    double latehours;
    double undertimehours;
    size_t holiday;

} DAILYTIMERECORD;


typedef struct _WEEKLYTIMERECORD
{
    char coveragedate[BUFSIZ];
    double regularincome;
    double overtimeincome;
    double grossincome;
    double netincome;
    double taxdeductions;
    double sssdeductions;
    double totalweeklyregularhoursworked;
    double totalweeklyovertimehoursworked;
    DAILYTIMERECORD dailytimerecord[MAXWORKDAYS];

} WEEKLYTIMERECORD;


typedef struct _EMPLOYEERECORD
{
    char code[BUFSIZ];
    char name[BUFSIZ];
    size_t level;
    double rate;
    WEEKLYTIMERECORD weeklytimerecord;

} EMPLOYEERECORD;

/****************************************/


/* Employee Records Container. Can hold maximum of MAXREC records */
static EMPLOYEERECORD records[MAXREC] = { 0 };

static char * workdays[MAXWORKDAYS] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };

typedef enum _InputFilter { EMPCODEINPUT, EMPTIMEINPUT, EMPCOVDATEINPUT } InputFilter;
typedef enum _WorkDay { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY } WorkDay;
typedef enum _PrintInfo { EMPLOYEEINFO, EMPLOYEEHOURS } PrintInfo;


//*********************** Function Prototypes *************************//

int ReadEmployeeRecords( const char * );
int WriteEmployeeTimeRecords ( char *, size_t );
int FindEmployeeRecord ( const char * );
int FilterInput ( char *, InputFilter );
char * GetEmployeeCodeInput ( );
void GetEmployeeRegularHours ( size_t, size_t );
void GetEmployeeOvertimeHours ( size_t, size_t );
void GetHoliday ( size_t, size_t );
void GetCoverageDate ( size_t );
void ComputeWeeklySalary ( size_t );
void DisplayRecords ( PrintInfo, size_t, size_t );
int RunApp ( );
void ResetRecords ( size_t );

//*********************************************************************//



/* Main entry */
int main ( int argc, char ** argv )
{
    if ( RunApp () < 0 )
        exit ( EXIT_FAILURE );

    return 0;
}

/*
    Read records from the file pointed to by filein.
*/
int ReadEmployeeRecords( const char * filein )
{
    FILE * pfile;
    char * linebuffer;
    char * pch;
    const char * delim = ":";
    size_t index = 0;

    pfile = fopen ( filein, "r" );
    if ( pfile == NULL )
    {
        printf ( "Error opening file %s: %s\n", filein, strerror ( errno ) );
        return -1;
    }

    linebuffer = ( char * ) malloc ( sizeof ( char ) * BUFSIZ );
    if ( linebuffer == NULL )
    {
        fclose ( pfile );
        printf ( "Error allocating memory space.\n" );
        return -1;
    }

    while ( fgets ( linebuffer, BUFSIZ, pfile ) )
    {
        if ( index == MAXREC )
        {
            /* printf ( "Maximum number of %d records allowed in records container has been reached.\n", MAXREC ); */
            free ( linebuffer );
            fclose ( pfile );
            return 0;
        }

        if ( ferror ( pfile ) != 0 )
        {
            printf ( "Error reading from input file %s: %s\n", 
                filein, strerror ( errno ) );
            free ( linebuffer );
            fclose ( pfile );
            return -1;
        }

        if ( linebuffer[0] == '#' || linebuffer[0] == '\n' )
            continue;

        linebuffer[strlen ( linebuffer ) - 1] = '\0';

        pch = strtok ( linebuffer, delim );
        memcpy (records[index].code, pch, strlen ( pch ) );
        records[index].code[strlen ( pch ) ] = '\0';

        pch = strtok ( NULL, delim );
        memcpy (records[index].name, pch, strlen ( pch ) );
        records[index].name[strlen ( pch ) ] = '\0';

        pch = strtok ( NULL, delim );
        sscanf ( pch, "%d", &records[index].level );

        if ( records[index].level == 1 )
            records[index].rate = SALARYLEVEL1;
        else if ( records[index].level == 2 )
            records[index].rate = SALARYLEVEL2;
        else if ( records[index].level == 3 )
            records[index].rate = SALARYLEVEL3;

        ++index;
    }

    free ( linebuffer );

    return 0;
}

/*
    Write records to dtr.txt.
*/
int WriteEmployeeTimeRecords ( char * fileout, size_t index )
{
    FILE * pfile;
    int ret = -1;

    struct tm * tminfo;
    char buffer[BUFSIZ];
    size_t i;

    pfile = fopen ( fileout, "a" );
    if ( pfile == NULL )
    {
        printf ( "Error opening file %s: %s\n", fileout, strerror ( errno ) );
        return ret;
    }


    fprintf ( pfile, "%s|", records[index].code );

    for ( i = MONDAY; i <= FRIDAY; ++i )
    {
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].regulartimein );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );
        if ( fprintf ( pfile, "%s|", buffer ) < 0 )
            break;

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].regulartimeout );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );
        if ( fprintf ( pfile, "%s|", buffer ) < 0 )
            break;

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].overtimein );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );
        if ( fprintf ( pfile, "%s|", buffer ) < 0 )
            break;

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[i].overtimeout );
        strftime ( buffer, BUFSIZ, "%H:%M", tminfo );

        if ( i == FRIDAY )
        {
            if ( fprintf ( pfile, "%s\n", buffer ) < 0 )
                break;
        }
        else
        {
            if ( fprintf ( pfile, "%s|", buffer ) < 0 )
                break;
        }

        ret = 0;
    }

    fclose ( pfile );

    return ret; 
}

/*
    Attempt to locate a matching string defined by pointer to parameter rec.
*/
int FindEmployeeRecord ( const char * rec )
{
    char * pch;
    int i, found = -1;

    if ( rec == NULL )
        return -1;

    for ( i = 0; i < MAXREC; ++i )
    {
        pch = strstr ( records[i].code, rec );
        if ( pch != NULL )
        {
            found = i;
            break;
        }
    }

    return found;
}

/*
    Check the format of the string input.
*/
int FilterInput ( char * input, InputFilter filter )
{
    const int EMPCODEMAXLEN     = 8;
    const int EMPTIMEINPUTLEN   = 5;
    const int EMPCOVDATELEN     = 15;
    int ret = -1;


    if ( input[0] == '\n' )
    {
        ret = 0;
        return ret;
    }

    input[ strlen ( input ) - 1 ] = '\0';


    switch ( filter )
    {
        case EMPCODEINPUT       :   if ( strlen ( input ) != EMPCODEMAXLEN )
                                        ret = -1;
                                    else if ( ! ( ( input[0] == 'A' && input[3] == '-' )        &&
                                                  ( input[1] >= '0' && input[1] <= '9' )     &&
                                                  ( input[2] >= '0' && input[2] <= '9' )     &&
                                                  ( input[4] >= '0' && input[4] <= '9' )     &&
                                                  ( input[5] >= '0' && input[5] <= '9' )     &&
                                                  ( input[6] >= '0' && input[6] <= '9' )     &&
                                                  ( input[7] >= '0' && input[7] <= '9' ) ) )

                                                    ret = -1;
                                    else
                                                    ret = 0;
                                    break;

        case EMPTIMEINPUT       :   if ( strlen ( input ) != EMPTIMEINPUTLEN )
                                        ret = -1;
                                    else if ( ! ( ( input[0] >= '0' && input[0] <= '2' )     &&
                                                  ( input[1] >= '0' && input[1] <= '9' )     &&
                                                  ( input[2] == ':' )                           &&
                                                  ( input[3] >= '0' && input[3] <= '5' )     &&
                                                  ( input[4] >= '0' && input[3] <= '9' ) ) )

                                                ret = -1;
                                    else
                                                ret = 0;
                                    break;

        case EMPCOVDATEINPUT    :   if ( strlen ( input ) != EMPCOVDATELEN )
                                        ret = -1;
                                    else if ( ! ( ( input[0] >= 'A' && input[0] <= 'Z' )     &&
                                                  ( input[1] >= 'a' && input[1] <= 'z' )     &&
                                                  ( input[2] >= 'a' && input[2] <= 'z' )     &&
                                                  ( isspace ( input[3] ) )                      &&
                                                  ( input[4] >= '0' && input[4] <= '2' )     &&
                                                  ( input[5] >= '0' && input[5] <= '9' )     &&
                                                  ( input[6] == '-' )                           &&
                                                  ( input[7] >= '0' && input[7] <= '3' )     &&
                                                  ( input[8] >= '0' && input[8] <= '9' )     &&
                                                  ( input[9] == ',' )                           &&
                                                  ( isspace ( input[10] ) )                     &&
                                                  ( input[11] == '2' )                          &&
                                                  ( input[12] == '0'    )                       &&
                                                  ( input[13] >= '0' && input[13] <= '1' )       &&
                                                  ( input[14] >= '0' && input[14] <= '9' ) ) )

                                                ret = -1;
                                    else
                                                ret = 0;
                                    break;

        default                 :   printf ( "Invalid filter code.\n");
                                    break;

    }

    return ret;
}

/*
    Retrieve employee code from input stream.
*/
char * GetEmployeeCodeInput ( )
{
    char buffer[BUFSIZ];

    while ( TRUE )
    {
        printf ( "Enter Employee Code (AXX-XXXX): " );

        fgets ( buffer, BUFSIZ, stdin );

        buffer[0] = toupper ( buffer[0] );

        if ( FilterInput ( buffer, EMPCODEINPUT ) < 0 )
        {
            printf ( "Invalid input.\n" );
            continue;
        }

        return buffer;
    }
}


/*
    Get employee regular hours.
*/
void GetEmployeeRegularHours ( size_t index, size_t day )
{
    char tmpbuf[BUFSIZ];
    struct tm * tminfo;
    double diff = 0.0;

    while ( TRUE )
    {
        printf ( "Enter Time-in for %s (00:00): ", workdays[day] );

        fgets ( tmpbuf, BUFSIZ, stdin );

        if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
        {
            printf ( "Invalid Time-in input format for %s.\n", workdays[day] );
            continue;
        }

        /* Valid input format for time-in */
        time ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimein );
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimein );

        /* We only need to invalidate the hour/min/sec */
        tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

        /* If string other than newline was entered... */ 
        if ( tmpbuf[0] != '\n' )
        {
            tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
            tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
        }
        else /* ...else, make a dummy regular time in/out with zero hour/min/sec */
        {
            records[index].weeklytimerecord.dailytimerecord[day].regulartimein  = mktime ( tminfo );
            records[index].weeklytimerecord.dailytimerecord[day].regulartimeout = mktime ( tminfo );
            return;
        }

        /* Valid regular time-in must be between 07:00 and 17:00 */
        if ( tminfo->tm_hour < 7 || tminfo->tm_hour > 16 )
        {
            printf ( "Invalid Time-in for %s, hours must be between 07:00 - 16:00.\n", workdays[day] );
            continue;
        }

        /* Latest start work hour must not exceed 16:00 */
        if ( tminfo->tm_hour == 16 && tminfo->tm_min > 0 )
        {
            printf ( "Invalid Time-in for %s, latest work hour must be 16:00.\n", workdays[day] );
            continue;
        }

        /*  
            Check if the employee came in late for work.
            If so, find out how many hours late then record it.
        */
        if ( tminfo->tm_hour > 8 )
        {
            records[index].weeklytimerecord.dailytimerecord[day].latehours = tminfo->tm_hour - 8;
        }

        /* If we arrived here then we have a valid regular time-in input */
        records[index].weeklytimerecord.dailytimerecord[day].regulartimein = mktime ( tminfo );

        /* Get regular time-out input */
        while ( TRUE )
        {
            printf ( "Enter Time-out for %s (00:00): ", workdays[day] );

            fgets ( tmpbuf, BUFSIZ, stdin );

            if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
            {
                printf ( "Invalid Time-out input format for %s.\n", workdays[day] );
                continue;
            }

            /* Valid input format for regular time-out */
            time ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimeout );
            tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimeout );

            tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

            if ( tmpbuf[0] != '\n' )
            {
                tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
                tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
            }
            else
                continue;

            if ( tminfo->tm_hour > 17 )
            {
                printf ( "Time-out hour cannot be greater than 15:00.\n" );
                continue;
            }

            /* If we arrived here then we have a valid regular time-out input */
            records[index].weeklytimerecord.dailytimerecord[day].regulartimeout = mktime ( tminfo );

            break;
        }

        /* Find the difference between time-out and time-in hours for this day */
        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].regulartimeout,
                            records[index].weeklytimerecord.dailytimerecord[day].regulartimein );

        /*
            If this employee worked from 08:00 - 17:00, we need to subtract lunch hour so
            he/she will have a full 8 hours of work time.
        */
        if ( diff > 28800 )
        {
            diff -= 3600;
        }

        /* Time-out hour cannot be less than Time-in */
        if ( diff <= 0 )
        {
            printf ( "Time-out hour cannot be less than or equal to Time-in hour.\n" );
            continue;
        }

        /* Difference between time-in and time-out must be at least one hour */
        if ( diff - 3600 < 3600 )
        {
            printf ( "Difference between Time-in and Time-out must be greater than one hour.\n" );
            continue;
        }

        /* The hours input is valid, get the total regular hours worked for this day */
        records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked = diff / 3600;


        /* Check for late hours */
        tminfo->tm_hour = 8; tminfo->tm_min = 0; tminfo->tm_sec = 0;

        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].regulartimein, mktime ( tminfo ) );

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimein );

        if ( tminfo->tm_hour <= 0 )
            records[index].weeklytimerecord.dailytimerecord[day].latehours = 0;
        else
            records[index].weeklytimerecord.dailytimerecord[day].latehours = tminfo->tm_hour - 8;


        /* Check for undertime hours */
        tminfo->tm_hour = 17; tminfo->tm_min = 0; tminfo->tm_sec = 0;

        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].regulartimeout, mktime ( tminfo ) );

        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].regulartimeout );

        if ( tminfo->tm_hour >= 17 )
            records[index].weeklytimerecord.dailytimerecord[day].undertimehours = 0;
        else
            records[index].weeklytimerecord.dailytimerecord[day].undertimehours = 17 - tminfo->tm_hour;


        /* Is this day a holiday */
        GetHoliday ( index, day );


        /*
            If it is a holiday, make necessary adjustments by switching regular hours worked
            and overtime hours worked. Note that this day will still show up as regular hours
            in dtr.txt.
        */
        if ( records[index].weeklytimerecord.dailytimerecord[day].holiday == 1 )
        {
            records[index].weeklytimerecord.dailytimerecord[day].overtimehoursworked
                = records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked;

            records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked = 0;
        }

        break;
    }
}


/*
    Get employee regular hours.
*/
void GetEmployeeOvertimeHours ( size_t index, size_t day )
{
    char tmpbuf[BUFSIZ];
    struct tm * tminfo;
    double diff = 0.0;

    /* If this day is a holiday just return since it is already overtime pay */
    if ( records[index].weeklytimerecord.dailytimerecord[day].holiday == 1 )
    {
        time ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );
        tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;
        records[index].weeklytimerecord.dailytimerecord[day].overtimein     = mktime ( tminfo );
        records[index].weeklytimerecord.dailytimerecord[day].overtimeout    = mktime ( tminfo );

        return;
    }

    /* Make sure the employee worked regular hours today before we process his/her overtime */
    if ( records[index].weeklytimerecord.dailytimerecord[day].regularhoursworked == 0 )
        return;


    while ( TRUE )
    {
        printf ( "Enter Overtime-in for %s (00:00): ", workdays[day] );

        fgets ( tmpbuf, BUFSIZ, stdin );

        if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
        {
            printf ( "Invalid Overtime-in input format for %s.\n", workdays[day] );
            continue;
        }

        /* Valid input format for overtime-in */
        time ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );
        tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].overtimein );

        /* We only need to invalidate the hour/min/sec */
        tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

        /* If string other than newline was entered... */ 
        if ( tmpbuf[0] != '\n' )
        {
            tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
            tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
        }
        else /* ...else, make a dummy regular time in/out with zero hour/min/sec */
        {
            records[index].weeklytimerecord.dailytimerecord[day].overtimein     = mktime ( tminfo );
            records[index].weeklytimerecord.dailytimerecord[day].overtimeout    = mktime ( tminfo );
            return;
        }

        /* Valid overtime-in must begin at 17:30 */
        if ( ! ( tminfo->tm_hour == 17 && tminfo->tm_min == 30 ) )
        {
            printf ( "Overtime-in must begin at 17:30.\n" );
            continue;
        }

        /* If we arrived here then we have a valid overtime-in input */
        records[index].weeklytimerecord.dailytimerecord[day].overtimein = mktime ( tminfo );

        /* Get overtime-out input */
        while ( TRUE )
        {
            printf ( "Enter Overtime-out for %s (00:00): ", workdays[day] );

            fgets ( tmpbuf, BUFSIZ, stdin );

            if ( FilterInput ( tmpbuf, EMPTIMEINPUT ) < 0 )
            {
                printf ( "Invalid Overtime-out input format for %s.\n", workdays[day] );
                continue;
            }

            /* Valid input for overtime-out*/
            time ( &records[index].weeklytimerecord.dailytimerecord[day].overtimeout );
            tminfo = localtime ( &records[index].weeklytimerecord.dailytimerecord[day].overtimeout);

            tminfo->tm_hour = tminfo->tm_min = tminfo->tm_sec = 0;

            if ( tmpbuf[0] != '\n' )
            {
                tminfo->tm_hour = atoi ( strtok ( tmpbuf, ":" ) );
                tminfo->tm_min  = atoi ( strtok ( NULL, ":" ) );
            }

            if ( ! ( tminfo->tm_hour >= 18 && tminfo->tm_hour <= 20 ) )
            {
                printf ( "Overtime-out must be between 18:00 and 20:30.\n" );
                continue;
            }

            if ( tminfo->tm_hour == 18 && tminfo->tm_min < 30 )
            {
                printf ( "Overtime-out must be between 18:30 and 20:30.\n" );
                continue;
            }

            /* If we arrived here then we have a valid overtime-out input */
            records[index].weeklytimerecord.dailytimerecord[day].overtimeout = mktime ( tminfo );

            break;
        }

        /* Find the difference between overtime-out and overtime-in hours for this day */
        diff = difftime ( records[index].weeklytimerecord.dailytimerecord[day].overtimeout,
                            records[index].weeklytimerecord.dailytimerecord[day].overtimein );

        /* The hours input is valid, get the total overtime hours worked for this day */
        records[index].weeklytimerecord.dailytimerecord[day].overtimehoursworked = diff / 3600;

        break;
    }
}


/*
    Check if this day is a holiday.
*/
void GetHoliday ( size_t index, size_t day )
{
    char buffer[BUFSIZ];

    while ( TRUE )
    {
        printf ( "Is %s a holiday (y/n)?: ", workdays[day] );

        fgets ( buffer, BUFSIZ, stdin );

        buffer[0] = tolower ( buffer[0] );

        if ( buffer[0] == 'y' )
            records[index].weeklytimerecord.dailytimerecord[day].holiday = 1;
        else if ( buffer[0] == 'n' )
            records[index].weeklytimerecord.dailytimerecord[day].holiday = 0;
        else
            continue;

        break;
    }
}


/*
    Get coverage date for this work week.
*/
void GetCoverageDate ( size_t index )
{
    char buffer[BUFSIZ];
    size_t i;

    while ( TRUE )
    {
        printf ( "Coverage Date (Ex: Mar 05-09, 2012) : " );

        memset ( buffer, 0, sizeof ( buffer ) );

        fgets ( buffer, BUFSIZ, stdin );

        buffer[0] = toupper ( buffer[0] );

        if ( FilterInput ( buffer, EMPCOVDATEINPUT ) < 0 )
        {
            printf ( "Invalid coverage date format.\n" );
            continue;
        }

        if ( buffer[7] == 3 && buffer[8] > 1 )
        {
            printf ( "Day cannot exceed 31.\n" );
            continue;
        }

        for ( i = MONDAY; i <= FRIDAY; ++i )
            strncpy ( records[index].weeklytimerecord.coveragedate, buffer, strlen ( buffer ) );

        break;
    }
}


/*
    Display employee work and hours information.
*/
void DisplayRecords ( PrintInfo pi, size_t index, size_t code )
{
        printf ( "\n******************************************************************************" );
        printf ("\nEmployee Name: %s\nEmployee Code: %s\nSalary Level: %d\nSalary Rate: Php %.2f/day\n",
            records[index].name, records[index].code, records[index].level, records[index].rate ); 
        printf ( "******************************************************************************\n" );

        if ( pi != EMPLOYEEINFO && code != -1 )
        {
            printf ( "Date Covered: %s\nTotal Number of Work Hours: %d Hrs.\nOvertime Hours: %d Hrs.\nRegular Income: Php %.2f\nOvertime Income: Php %.2f\nGross Income: Php %.2f\n",
                records[index].weeklytimerecord.coveragedate, ( int ) records[index].weeklytimerecord.totalweeklyregularhoursworked,
                ( int ) records[index].weeklytimerecord.totalweeklyovertimehoursworked,
                records[index].weeklytimerecord.regularincome, records[index].weeklytimerecord.overtimeincome,
                records[index].weeklytimerecord.grossincome );

            printf ( "Deductions:\n* Tax: Php %.2f\n* SSS: Php %.2f\nNet Income: %.2f\n",
                records[index].weeklytimerecord.taxdeductions, records[index].weeklytimerecord.sssdeductions, records[index].weeklytimerecord.netincome );

            printf ( "******************************************************************************\n\n" );
        }
}


/*
    Calculate weekly salary for this employee.
*/
void ComputeWeeklySalary ( size_t index )
{
    double hourlyrate = records[index].rate / 8;
    size_t i;

    for ( i = MONDAY; i <= FRIDAY; ++i )
    {
        /* 
            If the regular hours worked for this day is less than 8, we need to offset it.
            If we don't and there are late hours, those late hours are subtracted against
            regular hours worked twice.
        */
        if ( records[index].weeklytimerecord.dailytimerecord[i].regularhoursworked < 8 )
            records[index].weeklytimerecord.dailytimerecord[i].regularhoursworked = 8;

        /* Add all regular hours worked for this week */
        records[index].weeklytimerecord.totalweeklyregularhoursworked 
            += records[index].weeklytimerecord.dailytimerecord[i].regularhoursworked
            - ( records[index].weeklytimerecord.dailytimerecord[i].latehours
            + records[index].weeklytimerecord.dailytimerecord[i].undertimehours );

        /* Add all overtime hours worked for this week */
        records[index].weeklytimerecord.totalweeklyovertimehoursworked 
            += records[index].weeklytimerecord.dailytimerecord[i].overtimehoursworked;
    }

    /* Regular and Overtime income */
    records[index].weeklytimerecord.regularincome 
        = hourlyrate 
        * ( int ) records[index].weeklytimerecord.totalweeklyregularhoursworked;

    records[index].weeklytimerecord.overtimeincome 
        = hourlyrate 
        * 1.1 
        * ( int ) records[index].weeklytimerecord.totalweeklyovertimehoursworked;

    /* Gross income */
    records[index].weeklytimerecord.grossincome 
        = records[index].weeklytimerecord.regularincome 
        + records[index].weeklytimerecord.overtimeincome;

    /* Tax */
    records[index].weeklytimerecord.taxdeductions 
        = records[index].weeklytimerecord.grossincome 
        * 0.1;

    /* SSS/GSIS */
    if ( records[index].level == 1 )
        records[index].weeklytimerecord.sssdeductions 
        = records[index].rate 
        * 0.010;
    else if ( records[index].level == 2 )
        records[index].weeklytimerecord.sssdeductions 
        = records[index].rate 
        * 0.015;
    else if ( records[index].level == 3 )
        records[index].weeklytimerecord.sssdeductions 
        = records[index].rate 
        * 0.020;

    /* Net income */
    records[index].weeklytimerecord.netincome 
        = ( records[index].weeklytimerecord.grossincome
        - ( records[index].weeklytimerecord.taxdeductions
        + records[index].weeklytimerecord.sssdeductions ) )
        + WEEKLYALLOWANCE;
}

/*
    Program runner.
*/
int RunApp ( )
{
    char * filein   = "employee.txt";
    char * fileout  = "dtr.txt";
    char * tmpbuf;
    char buffer[BUFSIZ];
    size_t day;
    int index;

    printf ( "Tesda NC IV Reviewer\n\n");

    if ( ReadEmployeeRecords ( filein ) < 0 )
        exit ( EXIT_FAILURE );

    while ( TRUE )
    {
        tmpbuf      = GetEmployeeCodeInput ( );
        index       = FindEmployeeRecord ( tmpbuf );

        if ( index < 0 )
        {
            printf ( "Employee code not found.\n" );
            continue;
        }

        DisplayRecords ( EMPLOYEEINFO, index, -1 );

        for ( day = MONDAY; day < MAXWORKDAYS; ++day )
        {
            GetEmployeeRegularHours ( index, day );
            GetEmployeeOvertimeHours ( index, day );
        }

        GetCoverageDate ( index );
        ComputeWeeklySalary ( index );
        DisplayRecords ( EMPLOYEEHOURS, index, 0 );

        if ( WriteEmployeeTimeRecords ( fileout, index ) < 0 )
            exit ( EXIT_FAILURE );

        printf ( "Continue (y/n)?: " );
        fgets ( buffer, BUFSIZ, stdin );

        if ( toupper ( buffer[0] ) == 'Y' )
        {
            ResetRecords ( index );
            continue;
        }

        break;
    }

    return 0;

}

/* Reset Time Records */
void ResetRecords ( size_t index )
{
    size_t i;

    strncpy ( records[index].weeklytimerecord.coveragedate, "", 0 );

    records[index].weeklytimerecord.regularincome                   =
    records[index].weeklytimerecord.overtimeincome                  = 
    records[index].weeklytimerecord.grossincome                     =
    records[index].weeklytimerecord.netincome                       =
    records[index].weeklytimerecord.taxdeductions                   =
    records[index].weeklytimerecord.sssdeductions                   =
    records[index].weeklytimerecord.totalweeklyregularhoursworked   =
    records[index].weeklytimerecord.totalweeklyovertimehoursworked  = 0;

    for ( i = MONDAY; i <= FRIDAY; ++i )
    {
        records[index].weeklytimerecord.dailytimerecord[i].regularhoursworked   =
        records[index].weeklytimerecord.dailytimerecord[i].overtimehoursworked  =
        records[index].weeklytimerecord.dailytimerecord[i].latehours            =
        records[index].weeklytimerecord.dailytimerecord[i].undertimehours       = 0;

        records[index].weeklytimerecord.dailytimerecord[i].regulartimein        =
        records[index].weeklytimerecord.dailytimerecord[i].regulartimeout       =
        records[index].weeklytimerecord.dailytimerecord[i].overtimein           =
        records[index].weeklytimerecord.dailytimerecord[i].overtimeout          = 0;
    }

    records[index].weeklytimerecord.dailytimerecord[i].holiday = 0;
}

#else
#error "You need MSVC or GCC compiler!"
#endif

thank you.. hope you can help me.

Edited 3 Years Ago by nnayram: delete something

I would define the functionality of the C-program, and then try to completely rewrite it in C#.
As a second option: C# can also compile C-code, to some extent. includes become using etc.,most IO and file manipulations would be different... Read C# documentation about that, try to translate as much as you can in that way, compile and solve the other errors.
As a third option: google and try to find some c to C# translators.
Success.

Edited 3 Years Ago by ddanbe

Most of this should actually copy/paste over to be honest.

Personally, I'd copy it over in parts, like x amount of lines at a time, then compile it. If you see an error, track it down, and fix it. A lot of C and C# code is similar, well at least for basics. Arrays, Read In, Write Out, ext have differences.

I have been getting ready to do this personally, and am just copying it one piece of code at a time, and tweaking it (of course the C code needs to be cleaned up so a simple conversion won't do)

Also, if a piece of code is stumping you, google it, see what it does, then find the C# correspondent

I would not recommend simple copy/paste/compile as suggested by others. There are many features in C# that are a lot easier to do then they are in C/C++ due mostly to .NET framework api functions. And there are many other things that are done entirely differently. You and your program will be better off taking ddanbe's original suggestion to just rewrite the program entirely in C#, and while you are at it you can easily make it a GUI Windows program instead of command-line program. GUI windows are pretty simple in C# compared to terribly complicated win32 gui c programs.

Edited 3 Years Ago by Ancient Dragon

Well Ancient Dragon, the reason I said copy/paste it in parts, was because then he could tweak it as he goes.

Heck the copy/paste practically is rewriting it I guess (I should have left out the compile as you copy and paste in ... that isn't as great), but there are still basics in C and C#.

This article has been dead for over six months. Start a new discussion instead.