/* Copyright (C) 1993,1994 by the author(s).
 
 This software is published in the hope that it will be useful, but
 WITHOUT ANY WARRANTY for any part of this software to work correctly
 or as described in the manuals. See the ShapeTools Public License
 for details.

 Permission is granted to use, copy, modify, or distribute any part of
 this software but only under the conditions described in the ShapeTools 
 Public License. A copy of this license is supposed to have been given
 to you along with ShapeTools in a file named LICENSE. Among other
 things, this copyright notice and the Public License must be
 preserved on all copies.
 */
/*
 * mktime.c - convert various time formats to "seconds since 1970"
 *
 * Authors: Axel Mahler (Axel.Mahler@cs.tu-berlin.de)
 *          Andreas Lampen (Andreas.Lampen@cs.tu-berlin.de)
 *
 * $Header: mktime.c[4.1] Mon Jan 31 15:29:40 1994 andy@cs.tu-berlin.de frozen $
 */

#include <ctype.h>

#include "config.h"
#include "sttk.h"

/* all patterns are followed by an optional close 
   bracket ([]]*) to make atScanBindinhg happy !! */

/* Mon Nov 2[,] 92 */
#define RE1 "^[MTWFS][oherau][nudeit][ 	]*[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-9][,]*[ 	]*[7-9][0-9][]]*$"
/* Mon Nov 25[,] 92 */
#define RE2 "^[MTWFS][oherau][nudeit][ 	]*[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-3][0-9][,]*[ 	]*[7-9][0-9][]]*$"
/* Mon Nov 2[,] 1992 */
#define RE3 "^[MTWFS][oherau][nudeit][ 	]*[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-9][,]*[ 	]*19[7-9][0-9][]]*$"
/* Mon Nov 25[,] 1992 */
#define RE4 "^[MTWFS][oherau][nudeit][ 	]*[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-3][0-9][,]*[ 	]*19[7-9][0-9][]]*$"
/* Nov 2[,] 92 */
#define RE5 "^[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-9][,]*[ 	]*[7-9][0-9][]]*$"
/* Nov 25[,] 92 */
#define RE6 "^[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-3][0-9][,]*[ 	]*[7-9][0-9][]]*$"
/* Nov 2[,] 1992 */
#define RE7 "^[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-9][,]*[ 	]*19[7-9][0-9][]]*$"
/* Nov 25[,] 1992 */
#define RE8 "^[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-3][0-9][,]*[ 	]*19[7-9][0-9][]]*$"
/* Nov 2 */
#define RE9 "^[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-9][]]*$"
/* Nov 31 */
#define RE10 "^[JFMASOND][aepuco][nbrylgptvc]*[ 	]*[1-3][0-9][]]*$"
/* 1992/11/02 */
#define RE11 "^19[7-9][0-9]/[01][0-9]/[0-3][0-9][]]*$"
/* 92/01/31 */
#define RE12 "^[7-9][0-9]/[01][0-9]/[0-3][0-9][]]*$"
/* 1.5.92 */
#define RE13 "^[1-9][ 	]*\\.[ 	]*[1-9][ 	]*\\.[ 	]*[7-9][0-9][]]*$"
/* 10.5.92 */
#define RE14 "^[1-3][0-9][ 	]*\\.[ 	]*[1-9][ 	]*\\.[ 	]*[7-9][0-9][]]*$"
/* 1.10.92 */
#define RE15 "^[1-9][ 	]*\\.[ 	]*1[012][ 	]*\\.[ 	]*[7-9][0-9][]]*$"
/* 12.10.92 */
#define RE16 "^[1-3][0-9][ 	]*\\.[ 	]*1[012][ 	]*\\.[ 	]*[7-9][0-9][]]*$"
/* 1.5.1992 */
#define RE17 "^[1-9][ 	]*\\.[ 	]*[1-9][ 	]*\\.[ 	]*19[7-9][0-9][]]*$"
/* 10.5.1992 */
#define RE18 "^[1-3][0-9][ 	]*\\.[ 	]*[1-9][ 	]*\\.[ 	]*19[7-9][0-9][]]*$"
/* 1.10.1992 */
#define RE19 "^[1-9][ 	]*\\.[ 	]*1[012][ 	]*\\.[ 	]*19[7-9][0-9][]]*$"
/* 12.10.1992 */
#define RE20 "^[1-3][0-9][ 	]*\\.[ 	]*1[012][ 	]*\\.[ 	]*19[7-9][0-9][]]*$"
/* 1.5. */
#define RE21 "^[1-9][ 	]*\\.[ 	]*[1-9][ 	]*\\.[]]*$"
/* 10.5. */
#define RE22 "^[1-3][0-9][ 	]*\\.[ 	]*[1-9][ 	]*\\.[]]*$"
/* 1.10. */
#define RE23 "^[1-9][ 	]*\\.[ 	]*1[012][ 	]*\\.[]]*$"
/* 12.10. */
#define RE24 "^[1-3][0-9][ 	]*\\.[ 	]*1[012][ 	]*\\.[]]*$"

static struct df_map {
  char *pat, *fmt;
} date_fmts[] = {
  { RE1, ""},
  { RE2, ""},
  { RE3, ""},
  { RE4, ""},
  { RE5, ""},
  { RE6, ""},
  { RE7, ""},
  { RE8, ""},
  { RE9, ""},
  { RE10, ""},
  { RE11, ""},
  { RE12, ""},
  { RE13, ""},
  { RE14, ""},
  { RE15, ""},
  { RE16, ""},
  { RE17, ""},
  { RE18, ""},
  { RE19, ""},
  { RE20, ""},
  { RE21, ""},
  { RE22, ""},
  { RE23, ""},
  { RE24, ""},
  { (char *)0, (char *)0}
};

/*===================
 * month handling
 *===================*/

static char *mon_tab[] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
  "Sep", "Oct", "Nov", "Dec", (char *)0 
};

LOCAL int scanMonth(monthStr)
     char *monthStr;
{
  /* converts "Jan", "Feb" etc. to 0, 1 etc. */
  register int i; 

  for (i = 0; mon_tab[i]; i++) {
    if (!strncmp (mon_tab[i], monthStr, strlen (mon_tab[i])))
      return (i);
  }
  return (0);
}

/*===========================================
 * convert date string to normalized format
 *===========================================*/

LOCAL time_t str2tval (str, format, hour, min, sec)
     char *str;
     int format, hour, min, sec;
{
  char      *ptr;
  struct tm givenTime, *tmNow;
  time_t    now, givenSecs;

  givenTime.tm_sec = sec;
  givenTime.tm_min = min;
  givenTime.tm_hour = hour;
  givenTime.tm_mday = 1;
  givenTime.tm_mon = 0;
  givenTime.tm_year = 0;
  givenTime.tm_wday = -1;
  givenTime.tm_yday = -1;
  givenTime.tm_isdst = -1;

  switch (format) {
  case 1: /* Mon Nov[,] 2 92 */
  case 2: /* Mon Nov[,] 25 92 */
  case 3: /* Mon Nov[,] 2 1992 */
  case 4: /* Mon Nov[,] 25 1992 */
    str = strchr (str, ' ');
    if (!str) str = strchr (str, '\t');
    while (isspace (*str)) str++;
  case 5: /* Nov[,] 2 92 */
  case 6: /* Nov[,] 25 92 */
  case 7: /* Nov[,] 2 1992 */
  case 8: /* Nov[,] 25 1992 */
  case 9: /* Nov[,] 2 */
  case 10: /* Nov[,] 31 */
    givenTime.tm_mon = scanMonth (str);
    str = strchr (str, ' ');
    if (!str) str = strchr (str, '\t');
    while (isspace (*str)) str++;
    if ((ptr = strchr (str, ','))) *ptr = ' ';
    while (*str && !isdigit(*str)) str++;
    sscanf (str, "%d", &givenTime.tm_mday);
    while (*str && isdigit(*str)) str++;      /* Skip the day */
    while (*str && !isdigit(*str)) str++;     /* Skip non-numerics,
                                                 including timezone */
    sscanf (str, "%d", &givenTime.tm_year);
    break;
  case 11: /* 1992/11/02 */
  case 12: /* 92/01/31 */
    sscanf (str, "%d/%d/%d", &givenTime.tm_year, &givenTime.tm_mon, &givenTime.tm_mday);
    givenTime.tm_mon--;
    break;
  case 13: /* 1.5.92 */
  case 14: /* 10.5.92 */
  case 15: /* 1.10.92 */
  case 16: /* 12.10.92 */
  case 17: /* 1.5.1992 */
  case 18: /* 10.5.1992 */
  case 19: /* 1.10.1992 */
  case 20: /* 12.10.1992 */
  case 21: /* 12.10. */
  case 22: /* 12.10. */
  case 23: /* 12.10. */
  case 24: /* 12.10. */
    sscanf (str, "%d.%d.%d", &givenTime.tm_mday, &givenTime.tm_mon, &givenTime.tm_year);
    givenTime.tm_mon--;
    break;
  default:
    return (0);
    break;
  }

  now = time(NULL);
  tmNow = localtime (&now);
  if (givenTime.tm_year) {
    givenTime.tm_year = givenTime.tm_year%100;
    if (givenTime.tm_year < 70) /* these are years beyond 2000 */
      givenTime.tm_year += 100;
  }
  else
    givenTime.tm_year = tmNow->tm_year;

  if ((givenSecs = mktime (&givenTime)) == -1)
    return (0);
  return (givenSecs);
}


/*=======================
 * stMktime
 *=======================*/

EXPORT time_t stMktime (timeStr)
     char *timeStr;
{
  int  i=0, hours=12, mins=0, secs=0;
  char dateBuf[32], *colonPtr, *startPtr, *endPtr, *p;

  if (!timeStr || !(*timeStr))
    return (0);

  /* cut out time -- assume that time portion contains colon */
  if ((colonPtr = strchr (timeStr, ':'))) {
    if (colonPtr == timeStr) /* string starts with : */
      return (0);
    /* find beginning of time substring */
    startPtr = colonPtr-1;
    while ((startPtr >= timeStr) && isspace (*startPtr)) startPtr--;
    while ((startPtr >= timeStr) && isdigit (*startPtr)) startPtr--;
    hours = atoi (startPtr);

    /* find end of time substring */
    endPtr =  colonPtr+1;
    while (isspace (*endPtr)) endPtr++;
    mins = atoi (endPtr);
    while (isdigit (*endPtr)) endPtr++;
    if (*endPtr == ':') {
      endPtr++;
      while (isspace (*endPtr)) endPtr++;
      secs = atoi (endPtr);
      while (isdigit (*endPtr)) endPtr++;
    }
    i = 0;
    p = timeStr;
    while (p < startPtr) dateBuf[i++] = *p++;
    p = endPtr;
    while (*p) dateBuf[i++] = *p++;
    dateBuf[i] = '\0';
  }
  else
    strcpy (dateBuf, timeStr);

  i = 0;
  if (re_comp (date_fmts[0].pat)) {
    return (0);
  }
  while (date_fmts[i].pat) {
    if (re_exec (dateBuf)) {
      return (str2tval (dateBuf, i+1, hours, mins, secs));
    }
    i++;
    if (re_comp (date_fmts[i].pat)) {
      return (0);
    }
  }
  return (0);
}

/*=======================
 * stMktime
 *=======================*/

EXPORT char *stWriteTime (date)
     time_t date;
{
  static char timeBuf[64];

  strcpy (timeBuf, asctime (localtime (&date)));
  timeBuf[strlen(timeBuf)-1] = '\0';

  return (timeBuf);
}
