/*
   $Id: date.c 8 2007-07-12 15:45:14Z vol $
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "date.h"
#include "rfc2822.h"

static const char *days[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", NULL };
static const char *months[] = {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
   "Sep", "Oct", "Nov", "Dec", NULL
};

/*
   Parse an RFC2822 or obsolete date and convert to
   tm structure. Does not take DST into account

   Wed, 11 Jul 2007 11:51:28 -0500
   Wed, 11 Jul 2007 11:51:28 EST
   5 Jul 2006 14:29:32 -0000
*/

int date_parse(struct tm *tm, char *str)
{
   int i = 0;
   char *h = NULL, *t = NULL, c = 0, utc[3] = { 0 };

   if ((str == NULL) || (!(*str)))
	  return 0;

   while(rfc2822_is_wsp(*str))
	  str++;

   h = str;
   t = rfc2822_next_token(str, ',', "\t ");
   if (t == NULL)
	  return 0;

   /*
	  Day of the week is optional
   */

   if (*t == ',') {
	  *t++ = '\0';

	  for (i = 0; days[i]; i++) {
		 if (!(strcasecmp(days[i], h)))
			break;
	  }

	  if (days[i] == NULL)
		 return 0;

	  tm->tm_wday = (i + 1);
//	  printf("Day of the week: %d\n", tm->tm_wday);

	  while(rfc2822_is_wsp(*t))
		 t++;

	  h = t;
   }

   /*
	  Day of the month
   */

   t = rfc2822_next_token(t, ' ', "\t");
   if (t == NULL)
	  return 0;

   *t++ = '\0';

   i = atoi(h);
   if (i == 0)
	  return 0;

   tm->tm_mday = i;

//   printf("Day of the month: %d\n", tm->tm_mday);

   while(rfc2822_is_wsp(*t))
	  t++;

   h = t;

   /*
	  Month
   */

   t = rfc2822_next_token(t, ' ', "\t");
   if (t == NULL)
	  return 0;

   *t++ = '\0';

   for (i = 0; months[i]; i++) {
	  if (!(strcasecmp(months[i], h)))
		 break;
   }

   if (months[i] == NULL)
	  return 0;

   tm->tm_mon = i;
//   printf("Month: %d [%s]\n", i, months[i]);

   while(rfc2822_is_wsp(*t))
	  t++;

   h = t;

   /*
	  Year
   */

   t = rfc2822_next_token(t, ' ', "\t");
   if (t == NULL)
	  return 0;

   *t++ = '\0';

   i = atoi(h);
   if ((i == 0) || (i < 1900))
	  return 0;

   tm->tm_year = (i - 1900);

//   printf("Year: %d\n", tm->tm_year+1900);

   while(rfc2822_is_wsp(*t))
	  t++;

   h = t;

   /*
	  Hours
   */

   t = rfc2822_next_token(t, ':', NULL);
   if (t == NULL)
	  return 0;

   *t++ = '\0';

   i = atoi(h);
   if ((i < 0) || (i > 23))
	  return 0;
   
   tm->tm_hour = i;	  

//   printf("Hour: %d\n", tm->tm_hour);

   while(rfc2822_is_wsp(*t))
	  t++;

   h = t;

   /*
	  Minutes
   */

   t = rfc2822_next_token(t, ':', " \t");
   if (t == NULL)
	  return 0;

   c = *t;
   *t++ = '\0';

   i = atoi(h);
   if ((i < 0) || (i > 59))
	  return 0;
   
   tm->tm_min = i;	  

//   printf("Minute: %d\n", tm->tm_min);

   /*
	  Seconds (optional)
   */

   if (c == ':') {
	  while(rfc2822_is_wsp(*t))
		 t++;

	  h = t;

	  t = rfc2822_next_token(t, ' ', "\t");
	  if (t == NULL)
		 return 0;

	  *t++ = '\0';

	  i = atoi(h);
	  if ((i < 0) || (i > 60))
		 return 0;
   
	  tm->tm_sec = i;

//	  printf("Second: %d\n", tm->tm_sec);
   }

   while(rfc2822_is_wsp(*t))
	  t++;

   h = t;

   /*
	  UTC offset or TZ string
   */

   while((*t) && (!(rfc2822_is_wsp(*t))))
	  t++;

   if (rfc2822_is_wsp(*t))
	  *t = '\0';

   c = *h++;

   /*
	  Timezone specification we don't care about
   */

   if ((c != '+') && (c != '-')) 
	  return 1;

   utc[0] = *h++;
   utc[1] = *h++;
   utc[2] = '\0';

   i = atoi(utc);

   tm->tm_gmtoff = ((i * 60) * 60);

   utc[0] = *h++;
   utc[1] = *h++;

   i = atoi(utc);

   tm->tm_gmtoff += (i * 60);

   if (c == '-')
	  tm->tm_gmtoff = -(tm->tm_gmtoff);

//   printf("Offset: %ld\n", tm->tm_gmtoff);

   return 1;
}
