/*
  ISO 8601 - Week Number Magic
  Copyright (C) 1998 by Daniel Stenberg, All Rights Reserved

  Version 1.2 Nov 18, 1998
  - Magnus Tjernstrom <d92-mtm@ludd.luth.se> brought my attention to a weird
    treatment of the last days of a year, treated as week 53 before when they
    really should be week 1. I believe I've corrected that now.
  */

#include <time.h>
#include <stdio.h>

#ifdef DOS
long timezone = -1*60*60;
#endif

/* returns non-zero if it failed, zero if OK */
int Week(int year, int month, int day, int *week, int *weekday)
{
  struct tm timeCheck;
  time_t timeNowInSeconds;
  struct tm *timeNow;
  int yearNow;
  int  WeekDay_I;
  int   WeekNo_I;
  int   FirstWeek_I;
  int   YearDay_I;

  memset(&timeCheck, 0, sizeof(struct tm));

  timeCheck.tm_year=year;
  timeCheck.tm_mon=month;
  timeCheck.tm_mday=day;
    
  timeNowInSeconds = mktime(&timeCheck);

  timeNow = localtime(&timeNowInSeconds);

  if(timeNow->tm_mon != month) {
    return 1; /* this is no longer the same month! */
  }

  yearNow = timeNow->tm_year;
  /* struct tm stores yday 0 based, we need it 1 based */
  YearDay_I = timeNow->tm_yday + 1;
        
  /* silly americans begin the week on sundays. ISO doesn't */
  WeekDay_I = timeNow->tm_wday;
  if ( 0 == WeekDay_I )               /* if it's sunday, */
    WeekDay_I = 7;                  /* make it sunday! */

  WeekNo_I    = YearDay_I / 7;
  FirstWeek_I = YearDay_I % 7;
  
  FirstWeek_I -= WeekDay_I;
  if ( ( FirstWeek_I <= 0 ) && ( WeekNo_I > 0 ) ) {
    /* break up one week and add the days to FirstWeek_I */
    WeekNo_I--;
    FirstWeek_I += 7;
  }

  if ( FirstWeek_I > (-4) )
    WeekNo_I += 1;
    
  if ( FirstWeek_I > 3 )
    WeekNo_I += 1;
    
  if(0 == WeekNo_I) {
    /* same as previous year's last day: */
    int fool;

    Week(year-1, 11 /* December is 11 */, 31, &WeekNo_I, &fool);
  }
  else if(WeekNo_I > 52) {
    /* the last days of the year */
    if(WeekDay_I < 4 &&
       day > 28) {
      /* Three or less days of this year in 53 makes it week 1 instead! */
      WeekNo_I = 1;
    }
  }

  *week = WeekNo_I;
  *weekday = WeekDay_I;

  return 0;
}

int WeekNo( int year, int week,
            int *ret_month, int *ret_day)
{
  /*
   * Mission: we have year and week number. What date does that week
   * start with? (i.e what's the date monday that week)
   */
  int month;
  int day=15;

  int getweek;
  int getday;

  while(week>53) {
    week-=53;
  }

  month = 11 * week/53; /* assume 53 weeks a year */

  do {
    if(Week(year, month, day, &getweek, &getday)) {
      month++;
      day=1;
      continue;
    }
#if 0
    printf("Year %d Month %d Day %d Week %d WDay %d\n",
           year, month+1, day, getweek, getday);
#endif

    if((getweek>week-3) && (getweek<week+3)) {
      if((getweek == week) && (getday == 1)) {
        break;
      }
      else if(getweek<week) {
        if(week-getweek>1)
          day+=7;
        else
          day+=(8-getday);
      }
      else {
        if(getweek-week>1)
          day-=7;
        else if(getweek==week) {
          day-=getday-1;
        }
        else
          day-=getday+6;
        if(day<=0) {
          day=28;
          month--;
        }
      }
    }
    else {
      if(++month>11) {
        day=0;
        month=0;
        break;
      }
    }
  } while(1);

  *ret_day=day;
  *ret_month=month+1;
  return 0;
}

int main(int argc, char **argv)
{
  int WeekNo_I, WeekDay_I;

  if(argc<4) {
    puts("Enter [YYYY] [MM] [DD]");
    return -1;
  }
  if(!strcasecmp(argv[1], "week")) {
    WeekNo( atoi(argv[2])-1900, atoi(argv[3]),
            &WeekNo_I, &WeekDay_I);
    if(WeekDay_I>0) {
      printf("Month %02d Day %02d\n", WeekNo_I, WeekDay_I);
    }
    else {
      printf("No monday in such a week that year!\n");
    }
  }
  else {
    if(!Week(atoi(argv[1])-1900, atoi(argv[2])-1, atoi(argv[3]),
             &WeekNo_I, &WeekDay_I)) {
      printf("Week %d Weekday %d\n", WeekNo_I, WeekDay_I);
    }
    else
      printf("Illegal date!\n");
  }
  return 0;
}




