/* $Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/moira/gen/moddiff.dc,v 1.6 1996/06/02 07:42:32 ghudson Exp $
 *
 *  (c) Copyright 1990 by the Massachusetts Institute of Technology.
 *  For copying and distribution information, please see the file
 *  <mit-copyright.h>.
 */

#include <mit-copyright.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <moira.h>
#include <moira_site.h>
EXEC SQL INCLUDE sqlca;

static char * MONTHNAMES[] = {"january", "february", "march", "april", "may", 
			      "june", "july", "august", "september",
			      "october", "november", "december"};

static int MONTHDAYS[] = {0,0,31,59,90,120,151,181,212,243,273,304,334};


/****************************************************************/
/**  Return the difference between the modtime & table modtime **/
/**  in flag variable.  Return 0 if success, else errno.       **/
/****************************************************************/

int ModDiff (flag, tbl, ModTime)
int *flag;
char *tbl;
time_t ModTime;
{
    time_t filetimeno;
    EXEC SQL BEGIN DECLARE SECTION;
    char filetime[48], *tbl_name;
    EXEC SQL END DECLARE SECTION;

    *flag = 0;
    tbl_name = tbl;
    EXEC SQL SELECT modtime INTO :filetime FROM tblstats 
      WHERE table_name = :tbl_name;
    if (sqlca.sqlcode != 0) {
	if (sqlca.sqlcode == -37000 ||
	    sqlca.sqlcode == 17700)
	  exit(MR_DEADLOCK);
	fprintf(stderr, "Moddiff Query failed: %d\n", sqlca.sqlcode);
	return(MR_DATE);
    }
#ifdef DEBUG
    printf("about to call Date2Sec, flag = 0x%x\n", flag);
#endif
    if (Date2Sec (filetime, &filetimeno)) {
	fprintf(stderr,"Unable to parse mod. date for file %s\n", tbl);
	return(MR_DATE);
    }
#ifdef DEBUG
    printf("got time, flag = 0x%x\n", flag);
#endif
    *flag = (int) (filetimeno - ModTime);
    return(0);
}


/***************************************************/
/**  convert Unix-time (# of seconds since 1970)  **/
/**  from a date-time string                      **/
/**  Return 1 if failure, 0 if success            **/
/***************************************************/

Date2Sec(DS, UTime)
char *DS;
time_t *UTime;
{
    static int defzone = -1;
    int Day, Month, Year, Hour, Minute, Sec, Err, TotalDays, Iter;
    struct timeval tv;
    struct timezone tz;

    if (defzone == -1) {
	if (gettimeofday(&tv, &tz))
	  defzone = 0;
	else
	  defzone = tz.tz_minuteswest;
    }

#ifdef DEBUG
    printf("Date2Sec(\"%s\", %d)\n", DS, *UTime);
#endif
    Err = ParseDateString (DS, &Day, &Month, &Year, &Hour, &Minute,&Sec);
#ifdef DEBUG
    printf("date=%d/%d/%d %d:%d:%d, err=%d\n", Day, Month, Year,
	   Hour, Minute, Sec, Err);
#endif
    if (Err) return (Err);

    if (Year < 1970) {
	for (TotalDays = 0, Iter = 1969; Iter > Year; Iter--) {
	    TotalDays += NumdaysY(Iter);}
#ifdef DEBUG
	printf("Days in years           : %d\n", TotalDays);
#endif
	TotalDays += (NumdaysY(Year) - NumdaysM(Month, Year) - Day);
#ifdef DEBUG
	printf("Days after months & days: %d\n", TotalDays);
#endif
	*UTime = -((((24 * TotalDays) + 24 - Hour) * 60 - Minute) * 60 -
			  Sec) + defzone;
	return (0);
    } else {
	for (TotalDays = 0, Iter = 1970; Iter < Year; Iter++) {
	    TotalDays += NumdaysY(Iter);}
#ifdef DEBUG
	printf("Days in years    : %d\n", TotalDays);
#endif
	TotalDays += NumdaysM(Month, Year);
#ifdef DEBUG
	printf("Days after months: %d\n", TotalDays);
#endif
	TotalDays += (Day - 1);
#ifdef DEBUG
	printf("Days after Days  : %d\n", TotalDays);
	printf("Calculating seconds...(UTime = 0x%x)\n", *UTime);
#endif
	*UTime = (((24 * TotalDays) + Hour) * 60 + Minute) * 60 +
			Sec + defzone;
#ifdef DEBUG
	printf("Calculated value of %d\n", *UTime);
#endif
	return (0);
    }
}


/*****************************************/
/**  Return the # of days in the Year   **/
/*****************************************/

static int NumdaysY(Year)
int Year;
{
    return (365 + Leapyear(Year));
}


/*****************************************/
/**  Return the # of days in the Month  **/
/*****************************************/

static int NumdaysM(Month, Year)
int Month, Year;
{
    if ((Month > 2) && (Leapyear (Year)))
      return (MONTHDAYS[Month] + 1);
    else
      return (MONTHDAYS[Month]);
}


/*****************************************/
/**  Return 1 if a leapyear, else 0     **/
/*****************************************/

static int Leapyear (Year)
int Year;
{
    if ((Year % 4) && (!(Year % 100) || (Year % 1000)))
      return (0);
    else
      return (1);
}


/************************************************/
/**  Compute numeric breakdown of date string  **/
/**  Return 0 if success, 1 if failure         **/
/************************************************/

static int ParseDateString (DS, Day, Month, Year, Hour, Minute, Sec)
char *DS;
int *Day, *Month, *Year, *Hour, *Minute, *Sec;
{
    int Gotten;
    char *M, *D, *Temp;
    int Y=0, H=0, Min=0, S=0, DayNum=0, MonthNum=0;

    M = (char *)malloc(strlen(DS) + 2);
    D = (char *)malloc(strlen(DS) + 2);
    if (!(M && D)) return (1);
    Gotten = sscanf (DS, "%[^-]-%[^-]-%d %d:%d:%d", D, M, &Y, &H, &Min, &S);
    if (Gotten < 3) 
      Gotten = sscanf (DS, "%[^/]/%[^/]/%d %d:%d:%d", D, M, &Y, &H, &Min, &S);
    if (Gotten < 3)
      Gotten = sscanf (DS, "%s %[^,], %d %d:%d:%d", M, D, &Y, &H, &Min, &S);
#ifdef DEBUG
    printf ("Month = %s\nDay = %s\nYear = %d\n", M, D, Y);
    printf ("Hour = %d\nMin= %d\nSec = %d\n", H, Min, S);
#endif
    if ((Gotten < 3) || !(D && M && Y)) {
	free(M);
	free(D);
	return (1);}               /* Couldn't scan in a date */
    if (atoi(M)) {               /* Month not text, so M/D/Y not D/M/Y */
	Temp = M;
	M = D;
	D = Temp;}
    DayNum = atoi(D);
    MonthNum = MonthNo(M);
    free(M);
    free(D);
#ifdef DEBUG
    printf ("Month = %d\nDay = %d\nYear = %d\n", MonthNum, DayNum, Y);
#endif
    if ((DayNum < 1) || (DayNum > 31)) 
      return (1);                /* Bad Day */
    if (!MonthNum) 
      return (1);                /* Bad Month */
    if ((Y < 1) || (Y > 10000)) 
      return (1);                /* Bad Year */
    if (Gotten == 4) 
      return(1);                 /* Bad Time (Hour only) */
    if ((Gotten > 4) && (H < 0) || (H > 24)) 
      return(1);                 /* Bad Hour */
    if ((Gotten > 4) && ((Min < 0) || (Min > 59))) 
      return(1);                 /* Bad Minute */
    if ((Gotten > 5) && ((S < 0) || (S > 59))) 
      return(1);                 /* Bad Second */
    *Day = DayNum; 
    *Month = MonthNum;
    if (Y < 100)                   /* For abreviations like 90 for 1990    */
      Y += 1900;                   /* (Yes, it will be wrong in 2000) */
    *Year = Y;
    if (Gotten > 4) {
	*Hour = H;
	*Minute = Min;
    }
    else {
	*Hour = 0;
	*Minute = 0;}
    if (Gotten > 5) 
      *Sec = S;
    else
      *Sec = 0;
    return(0);
}


/***********************************************************/
/**  Return the Month number of a Month number or string  **/
/***********************************************************/

static int MonthNo (M)
char *M;
{
    int Count;
    if (atoi(M)) {
	if ((atoi(M) > 0) && (atoi(M) < 13))
	  return (atoi(M));
	else
	  return (0);
    }  
    for (Count = 0; Count < 12; Count++) {
	if (!strcasecmp (M, MONTHNAMES[Count]) 
	    || !strncasecmp(M, MONTHNAMES[Count], 3)) 
	  return (Count + 1);
    }
    return (0);
}
