-- File: PupTimeServerHot.mesa - last edit:
-- AOF                  3-Feb-88 15:03:21
-- HGM                 24-Sep-83 14:41:24
-- Copyright (C) 1983, 1988 by Xerox Corporation. All rights reserved. 

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

  PupDefs USING [
    Body, PupBuffer, MoveStringBodyToPupBuffer, ReturnPup, ReturnBuffer],
  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, 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
    body: PupDefs.Body = b.pup;
    IF body.dest.host = PupTypes.allHosts
      AND (locked OR ~parmsOk)
      AND (body.pupType = PupTypes.dateTextRequest
        OR body.pupType = dateTenexRequest
        OR body.pupType = dateAltoRequest) THEN
      BEGIN PupDefs.ReturnBuffer[b]; RETURN; END;
    SELECT body.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
        body.pupWords[0] ← HighHalf[days]*256 + LowHalf[days]/256;
        body.pupWords[1] ← LowHalf[days]*256 + HighHalf[seconds];
        body.pupWords[2] ← LowHalf[seconds];
        ReturnPup[b, dateTenexIs, 6];
        StatIncr[statTenex];
        END;
      dateAltoRequest =>
        BEGIN
        parms: System.LocalTimeParameters ← System.GetLocalTimeParameters[];
	LOOPHOLE[@body.pupWords,
	  LONG POINTER TO PupTimeServerFormat.PupTimeFormat]↑ ← [
          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
	LOOPHOLE[@body.pupWords,
	  LONG POINTER TO PupTimeServerFormat.TimeStatsEntry]↑ ← [
          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 =>
        {locked ← TRUE; ReturnPup[b, PupTimeServerFormat.lockTimeReply, 0]};
      PupTimeServerFormat.resetTimeRequest =>
        BEGIN
        locked ← FALSE;
        ReturnPup[b, PupTimeServerFormat.resetTimeReply, 0];
        END;
      ENDCASE => BEGIN PupDefs.ReturnBuffer[b]; END;
    END;

  END.