Program SetClock;
{ Author: Willi Kusche
          P. O. Box 456
          Bellmawr, NJ  08099  }

{$I "include/DOS.i"}
{$I "include/ExecStdIO.i"}
{$I "include/Parameters.i"}
{$I "include/StringLib.i"}
{$I "include/Ports.i"}
{$I "include/TimerDevice.i"}

const SecondsInMinute=60;
      SecondsInHour=SecondsInMinute * 60;
      SecondsInDay=SecondsInHour * 24;
      SecondsInYear=SecondsInDay * 365;

type PackedDecimalDateRec=record
                            year,
                            month,
                            day,
                            hour,
                            minute,
                            second: integer
                          end;
     months=array[0..11] of integer;

var direction: string;
    ExtraDaysInFeb, TotalSeconds,
    year, month, day, hour, minute, second, temp: integer;
    date_stamp: DateStampRec;
    PDDate: PackedDecimalDateRec;
    result: integer;
    IOR: IOSTDReqPtr;

const DaysTable: months = (0, 31, 59, 90, 120, 151,
                           181, 212, 243, 273, 304, 334);

function PackedDecimal(i: integer): integer;
  begin
    PackedDecimal := (i div 10) * 16 + i mod 10
  end;

function ToInteger(i: integer): integer;
  begin
    ToInteger := (i shr 4) * 10 + i mod 16
  end;

procedure WriteSClock(date_stuff: PackedDecimalDateRec);
  external;

procedure ReadSClock(var date_stuff: PackedDecimalDateRec);
  external;

begin
  direction := AllocString(80);
  GetParam(1, direction);
  writeln;
  if strieq(direction, "save")
      then begin
        DateStamp(date_stamp);
        temp := date_stamp.dsDays - 2251;
        year := (4 * temp + 3) div 1461;
        temp := temp - ((1461 * year) div 4);
        month := (5 * temp + 2) div 153;
        day := temp - (153 * month + 2) div 5 + 1;
        month := month + 3;
        if month > 12
            then begin
              year := year + 1;
              month := month - 12
            end;
        PDDate.year := PackedDecimal(year + 84);
        PDDate.month := PackedDecimal(month);
        PDDate.day := PackedDecimal(day);
        temp := date_stamp.dsMinute;
        hour := temp div 60;
        PDDate.minute := PackedDecimal(temp - (hour * 60));
        PDDate.hour := PackedDecimal(hour);
        PDDate.second := PackedDecimal(date_stamp.dsTick div 50);
        writeln('Resetting Spirit hardware clock to zero.');
        writeln('Please wait...');
        WriteSClock(PDDate);
        writeln('Spirit hardware clock now matches AmigaDOS system clock!')
      end
    else if strieq(direction, "load")
             then begin
               ReadSClock(PDDate);
               year := ToInteger(PDDate.year);
               month := ToInteger(PDDate.month);
               day := ToInteger(PDDate.day);
               hour := ToInteger(PDDate.hour);
               minute := ToInteger(PDDate.minute);
               second := ToInteger(PDDate.second);
               if second = 99
                   then writeln("Couldn't find Spirit hardware clock!")
                 else begin
                   if year = 0
                       then temp := 694224000
                     else begin
                       if year > 77
                           then temp := (year - 78) * SecondsInYear
                         else temp := 694224000 + year * SecondsInYear
                     end;
                   ExtraDaysInFeb := year div 4;
                   if (year mod 4 = 0) and (month > 2)
                       then ExtraDaysInFeb := ExtraDaysInFeb - 1;
                   if year > 77
                       then ExtraDaysInFeb := ExtraDaysInFeb - 19;
                   TotalSeconds := temp
                                   + (ExtraDaysInFeb
                                      + DaysTable[month - 1]
                                      + day - 1) * SecondsInDay
                                   + hour * SecondsInHour
                                   + minute * SecondsInMinute
                                   + second;
                   new(IOR);
                   result := OpenDevice(TimerName, 0, IOR, 0);
                   if result <> 0
                       then begin
                         writeln("Couldn't open timer!");
                         exit(10)
                       end;
                   IOR^.ioReq.ioMessage.mnNode.lnType := NTMessage;
                   IOR^.ioReq.ioMessage.mnNode.lnName := "";
                   IOR^.ioReq.ioMessage.mnReplyPort := nil;
                   IOR^.ioReq.ioCommand := TR_SETSYSTIME;
                   IOR^.ioActual := TotalSeconds;
                   IOR^.ioLength := 0;
                   result := DoIO(IOR);
                   if result <> 0
                       then begin
                         writeln("Couldn't set timer!");
                         exit(10)
                       end;
                   dispose(IOR);
                   writeln("AmigaDOS system clock set from hardware clock")
                 end
             end
    else begin
      writeln("Use:");
      writeln("  'SetClock LOAD' to set system clock from hardware clock");
      writeln("  'SetClock SAVE' to set hardware clock from system clock")
    end;
  writeln
end.
