/* File apptcal. The ApptCalendar ADT implemented using an array.*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include "bool.h"
#include "apptcal.h"
#include "appt.h"
#include "time.h"

/* DayStrings will be used to print out days and to convert strings
   into our enum type */
char *DayStrings[5] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};



/* ApptCalInit()
 *----------------------------------------------------------------
 * Initialize the appointment calendar
 */
void
ApptCalInit(Calendar *C)
{
    int i, j;
    for(i =  Monday; i <=  Friday; i++) 
        for(j = 0; j < MAX_APPTS; j++)
            ApptInit(&(C->WorkWeek[i][j]));
    C->currentDay = Monday;
    strncpy(C->fileName, "apptcal.dat", sizeof("apptcal.dat") +1);
}

/* DisplayDay
 *----------------------------------------------------------------
 */
void
DisplayDay(Workday day)
{
    printf("%s", DayStrings[day]);
}

/* MakeDayFromString
 *----------------------------------------------------------------
 */
Workday
MakeDayFromString(char *dayStr)
{
    Workday i;
    
    for(i = Monday; i <=Friday; i++)
	if(strncmp(DayStrings[i], dayStr, sizeof(dayStr)) == 0)
	    return i;
    /* Did not find a valid day */
    return -1;
}

/* ConvertTimeToIndex
 *----------------------------------------------------------------
 * Return the index into DayAppts that corresponds to time.
 */
int
ConvertTimeToIndex (ClockTime time)
{
    int hour = GetHour(time);
    int minute = GetMinute(time);

    assert( hour >= 9 && hour - 9 <= MAX_APPTS/2);
    assert( 0 <= minute && minute <= 59);
    
    return ((hour - 9) * 60 + minute) / 30; /*note: integer division*/
}


/* ConvertIndexToTime
 *----------------------------------------------------------------
 * Return the time corresponding to index.
 */
ClockTime
ConvertIndexToTime(int index)
{
    ClockTime t;
    int hour = 9 + index / 2;
    int minute = 30 * (index % 2);
    
    assert( hour >= 9 && hour - 9 <= MAX_APPTS/2);
    assert( 0 <= minute && minute <= 59);

    t = MakeTime(hour, minute);
    return t;
}


/* ValidBooking
 *----------------------------------------------------------------
 * Return true iff the appointment slot on day between startTime
 * and endTime is not used by other appointments.
 */
boolean
ValidBooking(Calendar *C, Workday day, ClockTime startTime, ClockTime endTime)
{
    int i;
    int startIndex = ConvertTimeToIndex(startTime);
    
    /* Special case to deal with appointments that end in the hour or
     * half hour, subtract 1 minute before finding the index*/
    int endIndex = ConvertTimeToIndex(TimeDifference(MakeTime(0, 1), endTime));
    
    if(startIndex < 0 || endIndex >= MAX_APPTS) {
	printf("Appointment is outside the bookable hours.\n");
	return FALSE;
    }
    
    for(i = startIndex; i <= endIndex; i++)
	if(!Empty(C->WorkWeek[day][i]))
	    return FALSE;

    return TRUE;
}




/* CalendarBook
 *----------------------------------------------------------------
 */
boolean
CalendarBook(Calendar *C, Workday day, ClockTime startTime, ClockTime endTime,
     char *message, boolean fixed)
{
    int i;
    int startIndex, endIndex;
    if(!ValidBooking(C, day, startTime, endTime))
	return FALSE;
    else { /* It will fit.*/
	
	startIndex = ConvertTimeToIndex(startTime);
	
	/* Special case to deal with appointments that end in the hour or
	   half hour, subtract 1 minute before finding the index. */
	endIndex = ConvertTimeToIndex(TimeDifference(MakeTime(0,1),
						     endTime));
	
	/* Store appointment in the locations in the calendar*/
	for(i = startIndex; i <= endIndex; i++) {
	    SetAppt(&(C->WorkWeek[day][i]), startTime, endTime,
		    message, fixed);
	}
	return TRUE;
    }
}


/* CalendarFit
 *----------------------------------------------------------------
 */
boolean
CalendarFit(Calendar *C, Workday day, ClockTime totalTime, char *message,
    boolean fixed, ClockTime *startTime, ClockTime *endTime)
{
        /*  <<< YOU COMPLETE THIS SUBPROGRAM >>>  */
}


/* CalendarFind
 *----------------------------------------------------------------
 */
boolean
CalendarFind(Calendar *C, char *message, Workday *day,
     ClockTime *startTime, ClockTime *endTime)
{
    Workday i;
    int j;
    for(i = Monday; i <= Friday; i++) {
	for(j = 0; j < MAX_APPTS; j++) {
	    if(!Empty(C->WorkWeek[i][j])) {
		if(strncmp(message, GetMessage(&(C->WorkWeek[i][j])),
		   MAX_MESSAGE_LEN) == 0) {
		    *day = i;
		    *startTime = GetStartTime(C->WorkWeek[i][j]);
		    *endTime = GetEndTime(C->WorkWeek[i][j]);
		    return TRUE;
		}
	    }
	}
    }
    return FALSE;
}


/* CalendarCancel
 *----------------------------------------------------------------
 */
void 
CalendarCancel(Calendar *C, char *message)
{
    int i;
    Workday day;
    ClockTime startTime, endTime;
    int startIndex, endIndex;
    boolean success;
    
    success = CalendarFind(C, message, &day, &startTime, &endTime);
    if(success) {
	startIndex = ConvertTimeToIndex(startTime);
	/* Special case to deal with appointments that end in the hour or
	   half hour, subtract 1 minute before finding the index. */
	endIndex = ConvertTimeToIndex(TimeDifference(MakeTime(0,1), endTime));

	for(i = startIndex; i <= endIndex; i++)
	    ClearAppt(&(C->WorkWeek[day][i]));
    }
}
 
/* CalendarClearDay
 *----------------------------------------------------------------
 */
void
CalendarClearDay(Calendar *C, Workday day)
{
    int j;
    for(j = 0; j < MAX_APPTS; j++)
	ClearAppt(&(C->WorkWeek[day][j]));
}


/* CalendarClearWeek
 *-----------------------------------------------------------------
 */
void
CalendarClearWeek(Calendar *C)
{
    Workday day;

    for(day = Monday; day <= Friday; day++) {
	CalendarClearDay(C, day);
    }
}


/* CalendarViewDay
 *----------------------------------------------------------------
 */
void
CalendarViewDay(Calendar *C, Workday day)
{
        /*  <<< YOU COMPLETE THIS SUBPROGRAM >>>  */
}

/* CalendarViewToday
 *----------------------------------------------------------------
 */
void
CalendarViewToday(Calendar *C)
{
    CalendarViewDay(C, C->currentDay);
}


/* CalendarNextDay
 *----------------------------------------------------------------
 */
void
CalendarNextDay(Calendar *C)
{
        /*  <<< YOU COMPLETE THIS SUBPROGRAM >>>  */
}


/* CalendarViewWeek
 *----------------------------------------------------------------
 */
void
CalendarViewWeek(Calendar *C)
{
        /*  <<< YOU COMPLETE THIS SUBPROGRAM >>>  */
}


/* CalendarSave
 *----------------------------------------------------------------
 */
void
CalendarSave(Calendar *C)
{
    int i;
    Workday day;

    FILE *savefile = fopen(C->fileName, "wt");
    assert(savefile != NULL);


    fprintf(savefile, "%s\n", DayStrings[C->currentDay]);

    /* For each day, print the whether the appointments are used;*/
    /* if they are, print the appointment information.*/

    for(day = Monday; day <= Friday; day++) {
	for(i = 0; i < MAX_APPTS; i++) {
	    if(!Empty(C->WorkWeek[day][i]) &&
	       i == ConvertTimeToIndex(GetStartTime(C->WorkWeek[day][i]))) {
		fprintf(savefile, "%s\n", DayStrings[day]);
		SaveAppt(C->WorkWeek[day][i], savefile);
	    }
	}
    }
    fclose(savefile);
}


/* CalendarLoad
 *----------------------------------------------------------------
 */
void
CalendarLoad(Calendar *C)
{
    FILE *savefile = fopen(C->fileName, "rt");
    Workday day;
    Appointment app;
    char curDayStr[DAY_LEN];
    int res;
    
    assert(savefile != NULL);
    
    if((res = ReadString(curDayStr, sizeof(curDayStr), savefile)) == EOF) {
	printf("Trying to load invalid Calendar file, exiting.\n");
	exit(-1);
    }
	

    C->currentDay = MakeDayFromString(curDayStr);
    
    if((res = ReadString(curDayStr, sizeof(curDayStr), savefile)) != EOF)
	res = LoadAppt(&app, savefile);

    day = MakeDayFromString(curDayStr);

    while(res != EOF) {
	CalendarBook(C, day, app.startTime, app.endTime,
		     app.message, app.fixed);

	/* read in the next appointment*/
	if((res = ReadString(curDayStr, sizeof(curDayStr), savefile)) != EOF){
	    res = LoadAppt(&app, savefile);
	    day  = MakeDayFromString(curDayStr);
	}
	
    }
    fclose(savefile);
}

