/*	time.c	- 
**
**
** Copyright (c) 1997  Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** The software may be modified for your own purposes, but modified versions
** may not be distributed.
**
** This software is provided "as is" without any expressed or implied warranty.
**
*/


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


#include <common/debug.h>
#include <common/site.h>
#include <common/portability.h>

#include "errmsg.h"

#define REG     register
extern	char    errMsg[];

#ifndef HAVE_STRPTIME
void strptime();
#endif


static int days_in_month[2][13] = {
        {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
        {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};

#define leap_year(yr) (!((yr) % 4) && ((yr) % 100)) || (!((yr) % 400))


/* date value is  (year << 9) + (month << 5) + day */
#define	year_mask	0x007FFE00
#define	month_mask	0x000001E0
#define day_mask	0x0000001F

char *msqlUnixTimeToDate(clock)
	time_t clock;
{
	static char	buf[20];
	struct	tm *locTime;

	locTime = localtime(&clock);
	strftime(buf,sizeof(buf),"%d-%b-%Y",locTime);
	return(buf);
}


time_t msqlDateToUnixTime(date)
	char	*date;
{
	struct	tm locTime;
	time_t	res;

	bzero(&locTime, sizeof(struct tm));
	strptime(date,"%d-%b-%Y", &locTime);
	locTime.tm_sec = 0;
	locTime.tm_min = 0;
	locTime.tm_hour = 0;
	res = mktime(&locTime);
	return(res);
}



char *msqlUnixTimeToTime(clock)
	time_t clock;
{
	static char	buf[20];
	struct	tm *locTime;

	locTime = localtime(&clock);
	strftime(buf,sizeof(buf),"%H:%M:%S",locTime);
	return(buf);
}


time_t msqlTimeToUnixTime(date)
	char	*date;
{
	struct	tm locTime;
	time_t	res;

	bzero(&locTime, sizeof(struct tm));
	strptime(date,"%H:%M:%S", &locTime);
	locTime.tm_year = 70;
	locTime.tm_mon = 0;
	locTime.tm_mday = 1;
	res = mktime(&locTime);
	return(res);
}




void __msqlPrintDate(buf,len,val)
	char	*buf;
	int	len,
		val;
{
	int 	year, mon, day,
		recalc = 0;

	if (val == 0)
	{
		*buf = 0;
		return;
	}
	year = (val >> 9);
	mon = (val - (year << 9)) >> 5;
	day = val - (year << 9) - (mon << 5) ;
	if (day == 0)
	{
		val -= 1;
		recalc = 1;
	}
	if (mon == 0)
	{
		val -= 1 << 5;
		recalc = 1;
	}
	if (recalc)
	{
		year = (val >> 9);
		mon = (val - (year << 9)) >> 5;
		day = val - (year << 9) - (mon << 5) ;
	}
	year -= 4096;
	switch(mon)
	{
		case 1: snprintf(buf,len,"%02d-Jan-%04d",day,year);
			break;
		case 2: snprintf(buf,len,"%02d-Feb-%04d",day,year);
			break;
		case 3: snprintf(buf,len,"%02d-Mar-%04d",day,year);
			break;
		case 4: snprintf(buf,len,"%02d-Apr-%04d",day,year);
			break;
		case 5: snprintf(buf,len,"%02d-May-%04d",day,year);
			break;
		case 6: snprintf(buf,len,"%02d-Jun-%04d",day,year);
			break;
		case 7: snprintf(buf,len,"%02d-Jul-%04d",day,year);
			break;
		case 8: snprintf(buf,len,"%02d-Aug-%04d",day,year);
			break;
		case 9: snprintf(buf,len,"%02d-Sep-%04d",day,year);
			break;
		case 10: snprintf(buf,len,"%02d-Oct-%04d",day,year);
			break;
		case 11: snprintf(buf,len,"%02d-Nov-%04d",day,year);
			break;
		case 12: snprintf(buf,len,"%02d-Dec-%04d",day,year);
			break;
	}
}


int __msqlScanDate(val)
	char	*val;
{
	char	*cp,
		*cp2;
	int	day,
		month,
		year;
	time_t	timeVal;

	/*
	** Scan the day value
	*/
	if (val == NULL || *val == 0)
	{
		return(0);
	}
	cp = (char *)index(val,'-');
	if (!cp)
		return(-1);
	day = atoi(val);
	if (day == 0)
		return(-1);

	/*
	** Scan the month value
	*/
	cp2 = (char *)index(cp+1,'-');
	if (!cp2)
		return(-1);
	*(cp+1) = toupper(*(cp+1));
	if (strncmp(cp+1,"Jan-",4) == 0)
		month = 1;
	else if (strncmp(cp+1,"Feb-",4) == 0)
		month = 2;
	else if (strncmp(cp+1,"Mar-",4) == 0)
		month = 3;
	else if (strncmp(cp+1,"Apr-",4) == 0)
		month = 4;
	else if (strncmp(cp+1,"May-",4) == 0)
		month = 5;
	else if (strncmp(cp+1,"Jun-",4) == 0)
		month = 6;
	else if (strncmp(cp+1,"Jul-",4) == 0)
		month = 7;
	else if (strncmp(cp+1,"Aug-",4) == 0)
		month = 8;
	else if (strncmp(cp+1,"Sep-",4) == 0)
		month = 9;
	else if (strncmp(cp+1,"Oct-",4) == 0)
		month = 10;
	else if (strncmp(cp+1,"Nov-",4) == 0)
		month = 11;
	else if (strncmp(cp+1,"Dec-",4) == 0)
		month = 12;
	else
		return(-1);

	/*
	** Scan the year value
	*/
	year = atoi(cp2+1);
	if (year == 0)
		return(-1);
	if (year < 100 && strlen(cp2+1) == 2)
	{
		char	yearBuf[10];
		struct	tm *locTime;
		time_t	clock;

		clock = time(NULL);
		locTime = localtime(&clock);
		strftime(yearBuf,10,"%Y",locTime);
		yearBuf[2] = 0;
		year = (atoi(yearBuf) * 100) + year;
	}
	year += 4096;

	timeVal = (year << 9) + (month << 5) + day;
	return((int)timeVal);
}



void __msqlPrintTime(buf,len,val)
	char	*buf;
	int	len,
		val;
{
	int	hour,
		min,
		sec;

	hour = val >> 12;
	min = (val - (hour << 12)) >> 6;
	sec = val - (hour << 12) - (min << 6) ;
	while(sec > 59)
	{
		sec -= 60;
		min++;
	}
	while(min > 59)
	{
		min -= 60;
		hour++;
	}
	snprintf(buf,len,"%02d:%02d:%02d",hour,min,sec);
}


int __msqlScanTime(val)
	char	*val;
{
	char	*cp,
		*cp2;
	int	hour,
		min,
		sec;
	time_t	timeVal;

	/*
	** Scan the hour value
	*/
	cp = (char *)index(val,':');
	if (!cp)
		return(-1);
	hour = atoi(val);

	/*
	** Scan the min value
	*/
	cp2 = (char *)index(cp+1,':');
	if (!cp2)
		return(-1);
	min = atoi(cp+1);
	if (min > 60)
		return(-1);

	/*
	** Scan the year value
	*/
	sec = atoi(cp2+1);
	if (sec > 60)
		return(-1);

	timeVal = (hour << 12) + (min << 6) + sec;
	return((int)timeVal);
}



char *msqlSumTimes(t1, t2)
	char	*t1, *t2;
{
	int	h1, m1, s1,
		h2, m2, s2,
		hr, mr, sr;
	static  char buf[80];
	char	*cp;

	h1 = atoi(t1);
	cp = (char *)index(t1,':');
	if (!cp)
		return(NULL);
	m1 = atoi(cp + 1);
	cp = (char *)index(cp + 1,':');
	if (!cp)
		return(NULL);
	s1 = atoi(cp + 1);

	h2 = atoi(t2);
	cp = (char *)index(t2,':');
	if (!cp)
		return(NULL);
	m2 = atoi(cp + 1);
	cp = (char *)index(cp + 1,':');
	if (!cp)
		return(NULL);
	s2 = atoi(cp + 1);

	hr = h1 + h2;
	mr = m1 + m2;
	sr = s1 + s2;

	while (sr > 59)
	{
		mr++;
		sr -= 60;
	}
	while (mr > 59)
	{
		hr++;
		mr -= 60;
	}
	
	sprintf(buf,"%d:%02d:%02d",hr,mr,sr);
	return(buf);
}


char *msqlDateOffset(date, dOff, mOff, yOff)
	char	*date;
	int	dOff, mOff, yOff;
{
	int	val, res,
		year, month, day,
		maxDays, addMaxDays,
		leap;
	static	char buf[80];

	if (dOff == 0 && mOff == 0 && yOff == 0)
	{
		strcpy(buf,date);
		return(buf);
	}
	
	val = __msqlScanDate(date);
	year = ((val & year_mask) >> 9) - 4096 + yOff;
	month = (val & month_mask) >> 5 + mOff;
	day = (val & day_mask) + dOff;

	addMaxDays = 0;

	while (1)
	{
		while(month > 12)
		{
			month -= 12;
			year++;
		}
		while(month < 1)
		{
			month += 12;
			year--;
		}
		leap = leap_year(year);
		if (leap)
			maxDays = days_in_month[1][month];	
		else
			maxDays = days_in_month[0][month];
		if (addMaxDays)
		{
			day += maxDays;
			addMaxDays = 0;
		}
		if (day > maxDays)
		{
			day -= maxDays;
			month++;
			continue;
		}
		if (day < 1)
		{
			month--;
			addMaxDays = 1;
			continue;
		}
		break;
	}
	year += 4096;
	res = (year << 9) + (month << 5) + day;
	__msqlPrintDate(buf,80,res);
	return(buf);
}


#define	hour_mask	0x0001F000
#define	min_mask	0x00000FC0
#define	sec_mask	0x0000003F	

char *msqlDiffTimes(t1, t2)
	char	*t1, *t2;
{
	int	v1, v2,
		h1, m1, s1,
		h2, m2, s2,
		hr, mr, sr;
	static  char buf[80];

	v1 = __msqlScanTime(t1);
	v2 = __msqlScanTime(t2);
	if (v1 == -1 || v2 == -1)
		return(NULL);
	
	h1 = (v1 & hour_mask) >> 12;
	m1 = (v1 & min_mask) >> 6;
	s1 = (v1 & sec_mask) ;

	h2 = (v2 & hour_mask) >> 12;
	m2 = (v2 & min_mask) >> 6;
	s2 = (v2 & sec_mask) ;

	hr = h2 - h1;
	mr = m2 - m1;
	sr = s2 - s1;

	while(sr < 0)
	{
		sr+=60;
		mr--;
	}
	while(mr < 0)
	{
		mr+=60;
		hr--;
	}
	snprintf(buf,sizeof(buf),"%02d:%02d:%02d",hr,mr,sr);
	return(buf);
}


int msqlDiffDates(date1, date2)
	char	*date1, *date2;
{
	int	v1, v2,
		y1, m1, d1,
		y2, m2, d2,
		res,
		leap;

	v1 = __msqlScanDate(date1);
	v2 = __msqlScanDate(date2);
	if (v1 == -1 || v2 == -1)
		return(-1);
	if (v1 > v2)
		return(-1);

	y1 = ((v1 & year_mask) >> 9) - 4096;
	m1 = (v1 & month_mask) >> 5;
	d1 = (v1 & day_mask);

	y2 = ((v2 & year_mask) >> 9) - 4096;
	m2 = (v2 & month_mask) >> 5;
	d2 = (v2 & day_mask);

	/* Simple case */
	if ((m1 == m2) && (y1 == y2))
		return(d2 - d1);

	/* Not so simple.  Work our way forward */
	res = 0;
	while((m1 != m2) || (y1 != y2))
	{
		leap = leap_year(y1);
		res += days_in_month[leap][m1] - d1 + 1;
		m1++;
		if (m1 > 12)
		{
			m1 = 1;
			y1++;
		}
		d1 = 1;
	}
	res += d2 - d1;
	return(res);
}


