-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- PupTimeServerHot.mesa,  HGM, 24-Sep-83 14:41:24

DIRECTORY
  Inline USING [LongDivMod, DIVMOD, LowHalf, HighHalf],
  System USING [
    GetGreenwichMeanTime, GetLocalTimeParameters, LocalTimeParameters],
  Time USING [AppendCurrent],

  Buffer USING [ReturnBuffer],
  PupDefs USING [PupBuffer, MoveStringBodyToPupBuffer, ReturnPup],
  PupTypes USING [allHosts, dateTextIs, dateTextRequest, fillInPupAddress, PupAddress],
  PupWireFormat USING [MesaToBcplLongNumber],
  Stats USING [StatCounterIndex, StatIncr, StatGetCounter],
  PupTimeServerFormat USING [
    PupTimeFormat, TimeStatsEntry, timeStatsRequest, timeStatsReply, version,
    resetTimeRequest, resetTimeReply, lockTimeRequest, lockTimeReply],
  PupTimeServerOps USING [statText, statTenex, statAlto];

PupTimeServerHot: PROGRAM
  IMPORTS
    Inline, System, Time,
    Buffer, PupTimeServerOps, PupWireFormat, Stats, PupDefs
  EXPORTS PupTimeServerOps =
  BEGIN OPEN Stats, PupDefs, PupTimeServerOps;

  locked, parmsOk: PUBLIC BOOLEAN ← FALSE;
  correction: PUBLIC INTEGER ← 0;
  resetAddress: PUBLIC PupTypes.PupAddress ← PupTypes.fillInPupAddress;

  PupTimeServer: PUBLIC PROCEDURE [b: PupBuffer] =
    BEGIN
    IF b.pup.dest.host = PupTypes.allHosts
      AND (locked OR ~parmsOk)
      AND (b.pup.pupType = PupTypes.dateTextRequest OR b.pup.pupType = dateTenexRequest
        OR b.pup.pupType = dateAltoRequest) THEN
      BEGIN Buffer.ReturnBuffer[b]; RETURN; END;
    SELECT b.pup.pupType FROM
      PupTypes.dateTextRequest =>
        BEGIN
        s: STRING = [30];
        Time.AppendCurrent[s, TRUE];
        MoveStringBodyToPupBuffer[b, s];
        ReturnPup[b, PupTypes.dateTextIs, s.length];
        StatIncr[statText];
        END;
      dateTenexRequest =>
        BEGIN OPEN Inline;
        now: LONG CARDINAL ← System.GetGreenwichMeanTime[];
        days, seconds: LONG CARDINAL;
        q1, q2, r1, r2: CARDINAL;
        -- Q1, R1 ← AltoTime/43200, Q1 = halfDays, R1 = seconds
        -- Q2, R2 ← Q1/2, Q2 = days, R2 = halfDays (0 or 1)
        -- Days ← Q2 + 15385
        -- Seconds ← R1 + R2*43200
        [q1, r1] ← LongDivMod[now, 43200];
        [q2, r2] ← DIVMOD[q1, 2];
        days ← LOOPHOLE[LONG[q2] + LONG[15385]];
        seconds ← LOOPHOLE[LONG[r1] + LONG[r2*43200]];
        -- Yetch, I think this is what MAXC wants
        b.pup.pupWords[0] ← HighHalf[days]*256 + LowHalf[days]/256;
        b.pup.pupWords[1] ← LowHalf[days]*256 + HighHalf[seconds];
        b.pup.pupWords[2] ← LowHalf[seconds];
        ReturnPup[b, dateTenexIs, 6];
        StatIncr[statTenex];
        END;
      dateAltoRequest =>
        BEGIN
        parms: System.LocalTimeParameters ← System.GetLocalTimeParameters[];
	ptf: LONG POINTER TO PupTimeServerFormat.PupTimeFormat = LOOPHOLE[@b.pup.pupWords];
        ptf↑ ← [
          time: PupWireFormat.MesaToBcplLongNumber[System.GetGreenwichMeanTime[]],
          zoneS: IF parms.direction = west THEN west ELSE east, zoneH: parms.zone,
          zoneM: parms.zoneMinutes, beginDST: parms.beginDST,
          endDST: parms.endDST];
        ReturnPup[b, dateAltoIs, 2*SIZE[PupTimeServerFormat.PupTimeFormat]];
        StatIncr[statAlto];
        END;
      PupTimeServerFormat.timeStatsRequest =>
        BEGIN
        tse: LONG POINTER TO PupTimeServerFormat.TimeStatsEntry ← LOOPHOLE[@b.pup.pupWords];
        tse↑ ← [
          version: PupTimeServerFormat.version,
          tenexRequests: PupWireFormat.MesaToBcplLongNumber[
          StatGetCounter[statTenex]],
          stringRequests: PupWireFormat.MesaToBcplLongNumber[
          StatGetCounter[statText]],
          altoRequests: PupWireFormat.MesaToBcplLongNumber[
          StatGetCounter[statAlto]], correction: correction,
          resetAddress: resetAddress];
        ReturnPup[b, PupTimeServerFormat.timeStatsReply, 2*SIZE[PupTimeServerFormat.TimeStatsEntry]];
        END;
      PupTimeServerFormat.lockTimeRequest =>
        BEGIN locked ← TRUE; ReturnPup[b, PupTimeServerFormat.lockTimeReply, 0]; END;
      PupTimeServerFormat.resetTimeRequest =>
        BEGIN
        locked ← FALSE;
        ReturnPup[b, PupTimeServerFormat.resetTimeReply, 0];
        END;
      ENDCASE => BEGIN Buffer.ReturnBuffer[b]; END;
    END;

  END.