#include <time.h>
#include <signal.h>
#include "Date5b.h"
#include <iomanip>
using namespace std;

Date* Date::td = 0;

Date& Date::today() {
  if (!td) {
    time_t clk = time(0);
    struct tm t = *localtime(&clk);
    td = new Date(t.tm_mday, t.tm_mon+1, t.tm_year+1900);
  }
  return *td;
}  

Date::Date(int day, int month, int year) :
          d(day), m(month), y(year) {
  j = jday(d, m, y);
  delete td;
  td = 0;
}

ostream& operator<<(ostream& ostr, const Date& d) {
  return ostr << setw(2) << d.day() << '.' << d.monthname() << '.' << d.year();
}

// Algorithm from K & R, "The C Programming Language", 1st ed.
bool leapYear(int year) {
  return (year&3) == 0 && (year%100 != 0 || year % 400 == 0);
}

// Is a day (1-31) within a given month?
bool Date::dayWithinMonth(int day, int month, int year) const {
  if (day <= 0 || month<1 || month>12 ) return 0;
  int dh = daysInMonth[month-1];
  if (leapYear(year) && month == 2) dh++;
  return day <= dh;
}

/*
 * Convert Gregorian calendar date to the corresponding Julian day
 * number j.  Algorithm 199 from Communications of the ACM, Volume 6, No.
 * 8, (Aug. 1963), p. 444.  Gregorian calendar started on Sep. 14, 1752.
 * This function not valid before that.
 * Returns 0 if the date is invalid.
 */

unsigned long Date::jday(int day, int month, int year) const {
  if( !dayWithinMonth(day, month, year) ) return 0UL;

  if (month > 2) {
    month -= 3;  // wash out the leap day
  } else {
    month += 9;
    year--;
  } 
  unsigned long c  = year / 100;
  unsigned long ya = year - 100*c;
  unsigned long jd = ((146097*c)>>2) + ((1461*ya)>>2)
                                     + (153*month + 2)/5 + day + 1721119;
  return jd;
} 

/*
 * Convert a Julian day number to its corresponding Gregorian calendar
 * date.  Algorithm 199 from Communications of the ACM, Volume 6, No. 8,
 * (Aug. 1963), p. 444.  Gregorian calendar started on Sep. 14, 1752.
 * This function not valid before that.  
 */

void Date::dmy() {
  unsigned long jh = j - 1721119;
  y  = ((jh<<2) - 1) / 146097;
  jh = (jh<<2) - 1 - 146097*y;
  unsigned long dh = (jh>>2);
  jh = ((dh<<2) + 3) / 1461;
  dh = (dh<<2) + 3 - 1461*jh;
  dh = (dh + 4)>>2;
  m  = (5*dh - 3)/153;
  dh = 5*dh - 3 - 153*m;
  d  = (dh + 5)/5;
  y  = 100*y + jh;
  if (m < 10)
    m += 3;
  else {
    m -= 9;
    y++;
  } 
}