/* File: mycal6.c

   Step 6 in writing my version of the
   calendar program.  Printing an 
   entire year.
*/

#include <stdio.h>
#include "genlib.h"
#include "simpio.h"

#define Sunday     0
#define Monday     1
#define Tuesday    2
#define Wednesday  3
#define Thursday   4
#define Friday     5
#define Saturday   6

void PrintOneMonth(int start, int days) ;
int AddDay(int weekday, int inc) ;
int YearDays(int year) ; 
int MonthDays(int month, int year) ;
bool IsLeapYear(int year) ;
string MonthName(int month);

main() {
  int year, month, i ;
  int start, this_month_days ;

  /* get year from user */
  printf("year =? ") ;
  year = GetInteger() ;
  printf("\n") ;

  /* January 1900, starts on Monday */
  start = 1 ;
  for (i = 1900; i < year ; i++) {
     start = AddDay(start, YearDays(i)) ;
  }

  /* Print a calendar for year month. */
  for (month = 1 ; month <= 12 ; month++) {
      printf("%s %d\n", MonthName(month), year) ;
      printf("  S  M Tu  W Th  F  S\n") ;
      this_month_days = MonthDays(month, year) ;
      PrintOneMonth(start, this_month_days) ;
      printf("\n") ;
      start = AddDay(start, this_month_days) ;
  }
}


/*
 * Function: AddDay
 * Usage: new_week_day = AddDay(old_week_day, n) ;
 * ----------------------------------------------
 * AddDay returns the weekday of the day n days after
 * old_week_day.
 */

int AddDay(int weekday, int inc) {
   return( (weekday % 7 + inc % 7) % 7 ) ;
}

/*
 * Function: PrintOneMonth
 * Usage: PrintOneMonth(weekday, n) ;
 * -----------------------------------
 * PrintOneMonth prints the body of a one-month
 * calendar with n days starting on the given
 * weekday.  No headings are printed.
 */

void PrintOneMonth(int start, int days) {
   int i ;

   /* Indent the first line */
   for (i = 0 ; i < start ; i++) {
      printf("   ") ;
   }

   for (i = 1 ; i <= days ; i++) {
      printf("%3d", i) ;
      /* print newline at end of week */
      if ( (i + start) % 7 == 0 ) {
	 printf("\n") ;
      }
   }

   /* Print newline at end of month
     only if necessary */
   if( (i + start) % 7 != 1)  {
      printf("\n") ;
   }
}

/* 
 * Function: YearDays
 * Usage: ndays = YearDays(year) ;
 * ------------------------------
 * YearDays returns the number of days in the given year.
 */

int YearDays(int year) {
   if (IsLeapYear(year)) {
      return(366) ;
   } else {
      return(365) ;
   }
}


/*
 * Function: MonthDays
 * Usage: ndays = MonthDays(month, year);
 * --------------------------------------
 * MonthDays returns the number of days in the indicated
 * month and year.  The year is required to handle leap years.
 */
 
int MonthDays(int month, int year) {
    switch (month) {
      case 2:
        if (IsLeapYear(year)) return (29);
        return (28);
      case 4: case 6: case 9: case 11:
        return (30);
      default:
        return (31);
    }
}

/*
 * Function: MonthName
 * Usage: name = MonthName(month);
 * -------------------------------
 * MonthName converts a numeric month in the range 1-12
 * into the string name for that month.
 */

string MonthName(int month)
{
    switch (month) {
      case  1: return ("January");
      case  2: return ("February");
      case  3: return ("March");
      case  4: return ("April");
      case  5: return ("May");
      case  6: return ("June");
      case  7: return ("July");
      case  8: return ("August");
      case  9: return ("September");
      case 10: return ("October");
      case 11: return ("November");
      case 12: return ("December");
      default: return ("Illegal month");
    }
}

/*
 * Function: IsLeapYear
 * Usage: if (IsLeapYear(year)) . . .
 * ----------------------------------
 * This function returns TRUE if year is a leap year.
 */

bool IsLeapYear(int year) {
    return ( ((year % 4 == 0) && (year % 100 != 0))
             || (year % 400 == 0) );
}
