/*
------------------------------------------------------------------------
Compile Switches
------------------------------------------------------------------------
*/
/*
------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <error.h>

extern int errno;

/*
------------------------------------------------------------------------
Defines
------------------------------------------------------------------------
*/
#define VERSION_STR "pdate 0.9"
#define TIME_LEN 64


/*
------------------------------------------------------------------------
DEBUGGING MACROS
------------------------------------------------------------------------
*/
#define WRITEMSG \
   printf ("File %s line %d: ", __FILE__, __LINE__); \
   printf ("errmsg <%s>\n", strerror(errno)); fflush(stdout); 
#define WRITEVAR(VAL,FMT) \
   printf ("File %s line %d: ", __FILE__, __LINE__); \
   printf ("%s=",#VAL); printf (#FMT, VAL); printf ("\n"); \
   fflush(stdout); 


/*
------------------------------------------------------------------------
Macros
------------------------------------------------------------------------
*/
/*
------------------------------------------------------------------------
Typedefs
------------------------------------------------------------------------
*/
/*
------------------------------------------------------------------------
Global Variables
------------------------------------------------------------------------
*/
extern int daylight;

/*
------------------------------------------------------------------------
Module Wide Variables
------------------------------------------------------------------------
*/
/*
------------------------------------------------------------------------
Local Function Prototypes
------------------------------------------------------------------------
*/
void Usage(void);
long tosec (char *timestr);



/*
------------------------------------------------------------------------
Main
------------------------------------------------------------------------
*/
int main (int argc, char *argv[]) {
	char optchar;
	int  nopt=0;
	int  nscan=0;
	char *date_format    = "%Y-%m-%d-%H:%M";
	char *time_increment = NULL;
	char *rounding_time  = NULL;
	char *initial_time   = NULL;
	time_t current_time  = 0;
	time_t standard_time = 0;
	time_t time_diff     = 0;
	int    isdst = 0;
	struct tm *ts = NULL;
	char timestr[TIME_LEN];

	while (-1 != (optchar=getopt(argc,argv,"d:f:hi:r:t:v"))) {
		nopt++;
		switch (optchar) {
			case '?':
				return 1;
			/*  Use daylight savings time  */
			case 'd':
				isdst = atoi(optarg);
				break;
			case 'h':
				Usage();
				return 0;
			case 'v':
				printf ("%s (compiled %s)\n", VERSION_STR, __DATE__);
				return 0;
			case 'f':
				date_format = strdup(optarg);
				break;
			case 't':
				initial_time = strdup(optarg);
				break;
			case 'i':
				time_increment = strdup(optarg);
				break;
			case 'r':
				rounding_time  = strdup(optarg);
				break;
			default:
				return 1;
		}
	}


	/*  Read input time  */
	if (initial_time) {
		ts = (struct tm *) calloc (1, sizeof(struct tm));
		nscan = sscanf (initial_time, "%d-%d-%d-%d:%d", 
			&ts->tm_year,
			&ts->tm_mon,
			&ts->tm_mday,
			&ts->tm_hour,
			&ts->tm_min
		);
		if (nscan==5) {
		} else {
			if (nscan<5)  
				nscan = sscanf (initial_time, "%d-%d-%d",
				&ts->tm_year,
				&ts->tm_mon,
				&ts->tm_mday
				);
				ts->tm_hour = 0;
				ts->tm_min  = 0;
		}
		if (nscan<3) {
			perror ("Initial time is in unrecognized format\n");
			exit (1);
		}
		/*  Internal representation for year is measured from 1900  */
		ts->tm_year -= 1900;
		/*  Internal representation for month ranges from 0 to 11   */
		ts->tm_mon  -= 1;
		/*  Should we respect daylight savings time ?  */
		/*  
      For example, if isdst = -1 then for end of DST interval (2:00am Oct 29, 2000)
         `pdate -t 2000-10-29-01:30 -i30m`
      yields
          2000-10-29-01:00
      which is 30min *before* rather than *after* (-i30m should give 30minutes after)
      Setting isdst=0 gives 'expected' value, 200-10-29-02:00
		*/
		ts->tm_isdst = isdst;
		current_time = mktime(ts);
	} else {
		current_time = time(NULL);	
	}

	/*  Round time  */
	if (rounding_time) {
		current_time -= current_time % tosec(rounding_time);
	}


	/*  Increment time  */
	if (time_increment) {
		current_time += tosec(time_increment);
	}

	/*  Print time  */
	ts = localtime(&current_time);
	strftime (timestr, TIME_LEN, date_format, ts);
	printf ("%s\n", timestr);

	/*  All done  */
	return 0;
}

/*
------------------------------------------------------------------------
Functions
------------------------------------------------------------------------
*/

/* 
Convert strings of form 10s, 21m, 102h, 7d to seconds
where letters smhd denote seconds, minutes, hours, days
*/
long tosec (char *timestr) {
	int length = strlen(timestr);
	int unitchar   = tolower (timestr[length-1]);
	long unit;
	long time;

	switch (unitchar) {
		case 'd':
			unit = 60*60*24;
			break;
		case 'h':
			unit = 60*60;
			break;
		case 'm':
			unit = 60;
			break;
		case 's':
			unit = 1;
			break;
		default:
			perror ("Invalid time unit\n");
			exit(1);
	}
	return unit * atol(timestr);
}


void Usage (void) {
	printf("\n");
   printf(" pdate [-hfitv]\n");
	printf("\n");
   printf("    Prints date and time.  Without arguments prints\n");
   printf("    current time in format YYYY-mm-dd-HH:MM such as\n");
   printf("       2000-08-14-01:43\n");
   printf("\n");
   printf("   -d  <n>          daylight savings time - default 0\n");
	printf("                      (see 'man ctime' for info on tm_isdst field)\n");
   printf("   -h               Print help.\n");
   printf("   -f  <string>     Format string for time.\n");
   printf("   -i  <increment>  Adds (negative) increment to time.\n");
   printf("                    Append letter s,m,h,d for to use units of\n");
   printf("                    seconds, minutes, hours or days.\n");
   printf("   -r  <interval>   Round time to previous interval using same\n");
   printf("                    units as above.  This is done before\n");
   printf("                    increment is added.  For example, if\n");
   printf("                    time is 12:41, the '-r 30min' option would\n");
   printf("                    round the time to 12:30\n");
   printf("   -t  <date/time>  Use specified date/time instead of current\n");
   printf("                    time, must be in format YYYY-mm-dd-HH:MM.\n");
	printf("   -v               Print version.\n");
	printf("\n");
	exit(0);
}
