/*
  parse_time_range(char *str, int *start_time, int *end_time);

  Input: pointer to parsed string beginning with "[Time_Range]".
	 pointer to integers to be set to range boundaries
  Return: 0 if successful, -1 if invalid

  start_time and end_time are set to 24-hr values.
  Periods (like "afternoon") are defined in a table.
  If an exact time is specified start_time and end_time are set to the same
  value.
  If only one end of a range is specified, the other is set to 0.
  Thus, "after four am" sets start_time= 400  end_time= 0.

  If an approximate time is specified (like "around four") the range is
  increased by 60 minutes at each end (start-60, end +60).
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dm.h"

#define APRX_TOL 60


//int find_period();
int find_period(char *s);
//char *get_word();
char *get_word(char *s, char *to, int max);


static char *hrs[] = {
	"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX",
	"SEVEN", "EIGHT", "NINE", "TEN", "ELEVEN", "TWELVE",
	"THIRTEEN", "FOURTEEN", "FIFTEEN", "SIXTEEN", "SEVENTEEN",
	"EIGHTEEN", "NINETEEN", "TWENTY", "TWENTY ONE",
	"TWENTY TWO", "TWENTY THREE", "TWENTY FOUR"
};

static char *ten[] = {
	"ZERO", "TEN", "TWENTY", "THIRTY", "FORTY", "FIFTY"
};

static char *mns[] = {
	"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX",
	"SEVEN", "EIGHT", "NINE", "TEN", "ELEVEN", "TWELVE",	
	"THIRTEEN", "FOURTEEN", "FIFTEEN", "SIXTEEN", "SEVENTEEN",
	"EIGHTEEN", "NINETEEN"
};

typedef struct day_interval{
	char *str;
	int	start;
	int	end;
} DayInterval;

static DayInterval periods[] = {
  {"am", 0, 1159},
  {"pm", 1201, 2359},
  {"noon", 1200, 1200},
  {"midnight", 2400, 2400},
  {"morning", 0, 1159},
  {"afternoon", 1201, 1759},
  {"evening", 1800, 2059},
  {"night", 2100, 2359},
  {"breakfast", 700, 859},
  {"lunch", 1200, 1300},
  {"dinner", 1800, 2000},
  {"early morning", 0, 759},
  {"early am", 0, 759},
  {"early afternoon", 1201, 1459},
  {"early pm", 1201, 1459},
  {"early evening", 1800, 1959},
  {"early night", 2100, 2159},
  {"late morning", 1000, 1159},
  {"late afternoon", 1600, 1759},
  {"late evening", 2000, 2059},
  {"late night", 2200, 2359},
  {"mid morning", 800, 1000},
  {"mid afternoon", 1400, 1700},
  {"mid evening", 1900, 2059},
  {"mid night", 2400, 2400},
  {0, 0, 0}
  };

typedef struct hr_min {
	int	hour;
	int	min;
	char	period_mod[50];
	char	period_base[50];
} HrMin;

int parse_time_range(char *tree, int *start, int *end) {
  char *p;
  char *t = NULL;
  char *c;
    HrMin	*hm,
		at_hm,
		start_hm,
		end_hm;
    int		relative_min= 0,
		before_after=0,
		hr_tol, min_tol,
		tmp,
		aprx= 0;
    char	period[100];
    char	word[100];
    int	i;

    at_hm.hour= at_hm.min= 0;
    at_hm.period_mod[0]= at_hm.period_base[0]= 0;
    start_hm.hour= start_hm.min= 0;
    start_hm.period_mod[0]= start_hm.period_base[0]= 0;
    end_hm.hour= end_hm.min= 0;
    end_hm.period_mod[0]= end_hm.period_base[0]= 0;
    hm= &at_hm;

    for(p= tree ; *p;  ) {
        /* scan for next token '[' or '.' */
	while( *p && (*p != '[') && (*p != '.') ) p++;
	if( !*p ) break;
	if( *p == '.' ) p++;
	if( *p == '[' ) p++;
	if( *p == '_' ) p++;

	if( !scmp("Hour", p) ) {
	    while( *p && (*p != '.') ) p++;
	    if( *p == '.' )  p++;
	    for( i=1; i < 14; i++) {
		if(!strncmp(p, hrs[i], strlen(hrs[i])) ) break;
	    }
	    if( i < 14 ) hm->hour= i;
	    if( relative_min ) {
		if( before_after == -1 ) {
		    hm->min -= relative_min;
		    if ( hm->min < 0 ) {
			hm->min += 60;
			hm->hour -= 1;
		    }
		}
	 	else {
	 	    hm->min += relative_min;
	 	}
	    }
	}

	else if( !scmp("Minute", p) ) {
	    while( *p && (*p != '.') ) p++;
	    if( *p == '.' )  p++;
	    while( (c= get_word(p, word, 100) )) {
		if( word[0] == '[' ) break;
		for( i=2; i < 6; i++) { if( !scmp(ten[i], word) ) break; }
		if( i < 6 )  { hm->min += 10 * i; }
		else {
		    for( i=0; i < 20; i++) { if( !scmp(mns[i], word) ) break; }
		    if( i < 20 ) hm->min += i;
		}
		p= c;
	    }
	}

	else if( !scmp("Minute_Rel", p) ) {
	    while( *p && (*p != '.') ) p++;
	    if( *p ) p++;
	    /* scan past [Minutes] token */
	    while( *p && (*p != '.') ) p++;
	    if( *p ) p++;

	    for( i=2; i < 6; i++) { if( !scmp(ten[i], p) ) break; }
	    if( i < 6 )  { relative_min += 10 * i; }
	    else {
		for( i=0; i < 20; i++) { if( !scmp(mns[i], p) ) break; }
		if( i < 20 ) relative_min += i;
	    }
	}

	else if( !scmp("quarter", p) ) { p++; relative_min= 15; }

	else if( !scmp("half", p) ) { p++; relative_min= 30; }

	else if( !scmp("Start_Time", p) ) { p++; hm= &start_hm; }

	else if( !scmp("End_Time", p) ) { p++; hm= &end_hm; }

	else if( !scmp("noon", p) ) { p++; hm->hour= 12; }

	else if( !scmp("midnight", p) ) { p++; hm->hour= 24; }

	else if( !scmp("aprx_time", p) ) { p++; aprx= 1; }

	else if( !scmp("before", p) ) { p++; before_after= -1; }

	else if( !scmp("after", p) ) { p++; before_after= 1; }

	else if( !scmp("Period_Mod", p) ) {
	    for( p++; *p && (*p != ']'); p++ ) ;
	    if( !*p ) return(-1);
	    p++;

	    if( *p == '[' ) {
	         p++;
	        if( *p == '_' ) p++;
	        for(t=hm->period_mod;*p && (*p != ']');) *t++= *p++;
	    }
	    else  if( *p == '.' ) {
		p++;
		for(t=hm->period_mod;*p && (*p != ' ') && (*p != '\n');) {
			*t++= *p++;
		}
	    }
	    *t= 0;
	}

	else if( !scmp("Period_Of_Day", p) ) {
	    for( p++; *p && (*p != '.'); p++ ) ;
	    if( !*p ) return(-1);
	    p++;
	    if( (c= get_word(p, word, 100) )) {
		strcpy(hm->period_base, word);
		p= c;
	    }

	}


	if( *p == '[' ) p++;
    }

    if( at_hm.hour || at_hm. min ) {
	*start= *end= 100*at_hm.hour + at_hm.min;
    }
    if( at_hm.period_base[0] ) {
        period[0]= 0;
	if( at_hm.period_mod[0] ) {
	    strcpy(period, at_hm.period_mod);
	    strcat(period, " ");
	}
        strcat(period, at_hm.period_base);
	i= find_period(period);
	if( i < 0 ) return(-1);
	if( !at_hm.hour && !at_hm.min ) {
	    *start= periods[i].start;
	    *end= periods[i].end;
	}
	else {
	    /* if pm period */
	    if( (periods[i].start > 1200) ) {
		if( *start && (*start < 1200) ) *start += 1200;
		if( *end && (*end < 1200) ) *end += 1200;
	    }
	}
    }

    if( start_hm.hour || start_hm. min ) {
	*start= 100*start_hm.hour + start_hm.min;
    }
    if( start_hm.period_base[0] ) {
        period[0]= 0;
	if( start_hm.period_mod[0] ) {
	    strcpy(period, start_hm.period_mod);
	    strcat(period, " ");
	}
        strcat(period, start_hm.period_base);
	i= find_period(period);
	if( i < 0 ) return(-1);
	if( !start_hm.hour && !start_hm.min ) {
	    *start= periods[i].end;
	}
	else {
	    /* if pm period */
	    if( (periods[i].start > 1200) ) {
		if( *start && (*start < 1200) ) *start += 1200;
	    }
	}
    }

    if( end_hm.hour || end_hm. min ) {
	*end= 100*end_hm.hour + end_hm.min;
    }
    if( end_hm.period_base[0] ) {
        period[0]= 0;
	if( end_hm.period_mod[0] ) {
	    strcpy(period, end_hm.period_mod);
	    strcat(period, " ");
	}
        strcat(period, end_hm.period_base);
	i= find_period(period);
	if( i < 0 ) return(-1);
	if( !end_hm.hour && !end_hm.min ) {
	    *end= periods[i].start;
	}
	else {
	    /* if pm period */
	    if( (periods[i].start > 1200) ) {
		if( *end && (*end < 1200) ) *end += 1200;
		/* if start am/pm not specified */
    		if( !start_hm.period_base[0] ) {
		    /* make start same period as end as long as start < end */
#ifdef whw
		    if( *start && (*start < 1200) ) *start += 1200;
		    if( *start > *end ) *start -= 1200;
#endif
		}
	    }
	}
    }


    /* add/subtract tolerance if approximate */
    if( aprx ) {
	hr_tol= APRX_TOL/60;
	min_tol= (APRX_TOL % 60);
	if( *start ) {
	    if( (*start % 100) >= APRX_TOL ) *start -= APRX_TOL;
	    else  {
		tmp= *start - (100*hr_tol);
	    	if( (tmp % 100) >= min_tol ) tmp -= min_tol;
		else tmp -= (40+min_tol);
		*start= tmp;
	    }
	    if( *start < 0 ) *start= 0;
	}

	if( *end ) {
	    if( (*end % 100) < (60-APRX_TOL) ) *end += APRX_TOL;
	    else {
		tmp= *end + (100*hr_tol);
		if( (tmp % 100) < (60-min_tol) ) tmp += min_tol;
		else tmp += min_tol + 40;
	    	*end= tmp;
	    }
	    if( *end > 2400 ) *end= 2400;
	}
    }

    return(0);
}


int find_period(char *s)
{
    int	i;


    for(i=0; 1; i++) {
	if( !periods[i].str ) break;
	if( !strcmp(s, periods[i].str) ) break;
    }
    if( periods[i].str ) return(i);
    else return(-1);
}
