/* A class to do time manipulations. */!!

inherit(Long, #Time, nil, 1, nil)!!

now(class(Time))!!

/* Return current time. */
Def current(self | ds)
{ ds := new(Struct, 18);
  putMSB(ds, 0x2c, 4);
  call(ds);
  ^time(new(self),
    atMSB(ds, 8), /* Hour */
    atLSB(ds, 8), /* Minute */
    atMSB(ds, 10) /* Second */);
}!!

/* Create a new Time object and initialize. */
Def new(self)
{ ^init(new(self:Behavior));
}!!

now(Time)!!

/* Return self as a long number for arithmetic purposes. */
Def asLong(self | temp)
{ ^setClass(temp := copy(self), Long);
}!!

/* Convert Time object to a String. */
Def asString(self | ta)
{ ta := asTimeArray(self);
  ^asString(ta[0]) + ":" +
    asPaddedString(ta[1], 2) + ":" +
    asPaddedString(ta[2], 2);
}!!

/* Converts self to a time object. */
Def asTime(self)
{
}!!

/* Return an array with 4 elements - hour, minute, second,
  overflow. Overflow indicates a time past a 24 hour clock.
  Overflowed times should be normalized. */
Def asTimeArray(self | hour, min, sec, over, time)
{ if (time := (asLong(self) mod 86400)) < self /* more than 24 Hour */
  then over := asLong(self) / 86400;
  endif;
  hour := time / 3600;
  min := time - (hour * 3600);
  sec := min mod 60;
  min := min / 60;
  ^tuple(asInt(hour), asInt(min), asInt(sec), over);
}!!

/* Initialize time to 0:00:00. */
Def init(self)
{ set(self, 0L);
}!!

/* Normalize the time by setting the time to be
  within a single 24 hour period. */
Def normalize(self)
{ set(self, asLong(self) mod 86400);
}!!

/* Put a date onto the specified Stream. */
Def printOn(self, aStrm)
{ printOn(asString(self), aStrm);
}!!

/* Private method which sets the (indexed) value of self with
  the passed value. */
Def set(self, value | temp)
{ temp := new(Struct, 4);
  putLong(temp, value, 0);
  setClass(temp, class(self));
  swapProperties(self, temp);
  swap(self, temp);
}!!

/* Put a date onto the specified Stream. */
Def sysPrintOn(self, aStrm)
{ printOn(asString(self), aStrm);
}!!

/* Set the time object from the passed parameters. */
Def time(self, hr, min, sec)
{ set(self, (hr*3600)+(min*60)+sec);
}!!
