// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#include <timeclass.h>

#include <math.h>

int timeclass::days_in_month[12];

// constructor
timeclass::timeclass(const int y, const int d, const int h,
                     const int m, const double s)
{ _year = y;
  _day = d;
  _hour = h;
  _minute = m;
  _second = (float)s;
  _normalise();
  
// init what should be static
  int temp[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  for (int n = 0; n < 12; n++)
  days_in_month[n] = temp[n];
}

// normalise the contents of the object. This assumes all values are
// positive
void timeclass::_normalise(void)
{ _minute += ((int)_second) / 60;
  _second = fmod(_second, 60);
  
  _hour += _minute / 60;
  _minute = _minute % 60;
  
  _day += _hour / 24;
  _hour = _hour % 24;

  while (_day >= days_in_year())
  { _day -= days_in_year();
    _year++;
  }  
}

timeclass& timeclass::year(const int n)
{ _year = n;
  _normalise();
  return *this;
}

timeclass& timeclass::day(const int n)
{ _day = n;
  _normalise();
  return *this;
}

timeclass& timeclass::hour(const int n)
{ _hour = n;
  _normalise();
  return *this;
}

timeclass& timeclass::minute(const int n)
{ _minute = n;
  _normalise();
  return *this;
}

timeclass& timeclass::second(const double d)
{ _second = d;
  _normalise();
  return *this;
}




void timeclass::operator+=(const timeclass& t)
{ _second += t.second();
  while (_second >= 60)
  { _second -= 60;
    _minute++;
  }

  _minute += t.minute();
  while (_minute >= 60)
  { _minute -= 60;
    _hour++;
  }

  _hour += t.hour();
  while (_hour >= 24)
  { _hour -= 24;
    _day++;
  }

  _day += t.day();
  while (_day >= days_in_year())
  { _day -= days_in_year();
    _year++;
  }  

  _year += t.year();
}

timeclass timeclass::operator+(const timeclass& t2) const
{ timeclass rv = *this;
  rv += t2;
  return rv;
}

int timeclass::month(void) const
{ timeclass::days_in_month[1] = (leap_year() ? 29 : 28);
  int rv = 1, temp_day = doy();
  while (temp_day > 0)
  { temp_day -= days_in_month[rv - 1];
    if (temp_day > 0) then
      rv++;
  }
  return rv;
}

int timeclass::day_of_month(void) const
{ int rv = doy();
  for (int n = 1; n < month(); n++)
    rv -= days_in_month[n - 1];
  return rv;
}

boolean timeclass::operator<(const timeclass& t) const
{ if (year() < t.year()) then
    return true;
  if (year() > t.year()) then
    return false;
  if (doy() < t.doy()) then
    return true;
  if (doy() > t.doy()) then
    return false;
  if (hour() < t.hour()) then
    return true;
  if (hour() > t.hour()) then
    return false;
  if (minute() < t.minute()) then
    return true;
  if (minute() > t.minute()) then
    return false;
  if (second() < t.second()) then
    return true;
  return false;
}

boolean timeclass::operator>(const timeclass& t) const
{ if (year() > t.year()) then
    return true;
  if (year() < t.year()) then
    return false;
  if (doy() > t.doy()) then
    return true;
  if (doy() < t.doy()) then
    return false;
  if (hour() > t.hour()) then
    return true;
  if (hour() < t.hour()) then
    return false;
  if (minute() > t.minute()) then
    return true;
  if (minute() < t.minute()) then
    return false;
  if (second() > t.second()) then
    return true;
  return false;
}

// timeclass == timeclass
boolean timeclass::operator==(const timeclass& t) const
{ return ( (year() == t.year()) &&
           (doy() == t.doy()) &&
           (hour() == t.hour()) &&
           (minute() == t.minute()) &&
          (second() == t.second()));
}

// timeclass / int
timeclass timeclass::operator/(const int n) const
{ int tyear = _year * 365;
  tyear /= n;
  int ttyear = tyear / 365;
  int tday = ((tyear % 365) + _day) * 24;
  tday /= n;
  int ttday = tday / 24;
  int thour = ((tday % 24) + _hour) * 60;
  thour /= n;
  int tthour = thour / 60;
  int tminute = ((thour % 60) + _minute) * 60;
  tminute /= n;
  int ttminute = tminute / 60;
  int tsecond = (tminute % 60) + (int)_second;
  tsecond /= n;
  return timeclass(ttyear, ttday, tthour, ttminute, tsecond);
}

// output to a stream
ostream& operator<<(ostream& str, const timeclass& t)
{ str << t.year() << ":" << t.day() << ":" << t.hour() << ":" <<
	 t.minute() << ":" << t.second();
  return str;
}

// input from a stream
istream& operator>>(istream& str, timeclass& t)
{ str >> t._year >> t._day >> t._hour >> t._minute >> t._second;
  return str;
}

// timeclass = timeclass
void timeclass::operator=(const timeclass& t)
{ _year = t._year;
  _day = t._day;
  _hour = t._hour;
  _minute = t._minute;
  _second = t._second;
  for (int n = 0; n < 12; n++)
    days_in_month[n] = t.days_in_month[n];
}

// timeclass - timeclass
timeclass timeclass::operator-(const timeclass& t) const
{ timeclass rv, tmp1(*this), tmp2(t);
  int sign = 1;
  if (tmp2 > tmp1) then
  { sign = -1;
    timeclass tmp3(tmp2);
    tmp2 = tmp1;
    tmp1 = tmp3;
  }
  if (tmp1 == tmp2) then
    return rv;
  
// tmp1 is now definitely greater than tmp2

// seconds
  double seconds_to_add = tmp1._second - tmp2._second;
  if (seconds_to_add < 0) then
    seconds_to_add += 60;
  timeclass delta(0, 0, 0, 0, seconds_to_add);
  rv += delta;
  tmp2 += delta;
  
// minutes
  int minutes_to_add = tmp1._minute - tmp2._minute;
  if (minutes_to_add < 0) then
    minutes_to_add += 60;
  delta = timeclass(0, 0, 0, minutes_to_add);
  rv += delta;
  tmp2 += delta;
  
// hours
  int hours_to_add = tmp1._hour - tmp2._hour;
  if (hours_to_add < 0) then
    hours_to_add += 24;
  delta = timeclass(0, 0, hours_to_add);
  rv += delta;
  tmp2 += delta;
  
// days
  int days_to_add = tmp1._day - tmp2._day;
  if (days_to_add < 0) then
    days_to_add += tmp2.days_in_year();
  delta = timeclass(0, days_to_add);
  rv += delta;
  tmp2 += delta;
  
// years
  delta = timeclass(tmp1._year - tmp2._year);
  rv += delta;
  if (sign == -1) then
  { rv._year = -rv._year;
    rv._day = -rv._day;
    rv._hour = -rv._hour;
    rv._minute = -rv._minute;
    rv._second = -rv._second;
  }

  return rv;
}

// timeclass -= timeclass (have to be careful in case 2nd operand too big)
void timeclass::operator-=(const timeclass& t)
{ *this = *this - t; }

// write to a file
void timeclass::write(FILE* fp)
{ int val = year();
  fwrite((char*)&val, sizeof(val), 1, fp);
  val = day();
  fwrite((char*)&val, sizeof(val), 1, fp);
  val = hour();
  fwrite((char*)&val, sizeof(val), 1, fp);
  val = minute();
  fwrite((char*)&val, sizeof(val), 1, fp);
  double dval = second();
  fwrite((char*)&dval, sizeof(dval), 1, fp);
}

// read from a file
void timeclass::read(FILE* fp)
{ int y, d, h, m;
  double s;
  fread(&y, sizeof(y), 1, fp);
  fread(&d, sizeof(d), 1, fp);
  fread(&h, sizeof(h), 1, fp);
  fread(&m, sizeof(m), 1, fp);
  fread(&s, sizeof(s), 1, fp); 
  /* read_binary(fp, y);
  read_binary(fp, d);
  read_binary(fp, h);
  read_binary(fp, m);
  read_binary(fp, s); */
  
  
  _year = y;
  _day = d;
  _hour = h;
  _minute = m;
  _second = s;
}
