-- [Ivy]<Swinehart>Inscript>ClassInscript.mesa
-- Last Edited by Swinehart, April 14, 1982 10:11 am
-- Last Edited by Paul Rovner, June 10, 1983 9:01 am

DIRECTORY
  Intime USING [EventTime, MsTicks];

ClassInscript: DEFINITIONS =
  BEGIN

  -- An Inscript represents a sequence of recorded entries, organized
  --  in some sort of "page" units. At any time, there is a page
  --  number representing the latest page into which entries have
  --  been recorded, and another representing the earliest page which
  --  the Inscript still knows about (in some implementations old
  --  pages may be forgotten). The Inscript does not know the semantics
  --  of its entries. The client knows the semantics, and that entries
  --  are stored atomically on pages (they do not overlap boundaries),
  --  but not the size of pages or the exact means of storage. The
  --  Inscript provides operations for recording entries sequentially
  --  at the end of the sequence, for placing an "input" pointer at
  --  the beginning of a specified page, for retrieving entries
  --  sequentially from a page, and for determining the range of
  --  pages from which entries can be retrieved.

  NewStdInscript: PROCEDURE [
    KeyProc: KEyProc, ComProc: COmProc, initializeFile: BOOLEAN ← FALSE,
    lnFileSize: CARDINAL←4, lnGroupSize: CARDINAL←2]
    RETURNS [Inscript];

Inscript: TYPE = LONG POINTER TO InscriptObject;

  -- Client Interface for Inscripts


  -- No further operations will be supported using this Inscript; The
  --  client must know what  parameters to supply when making a new
  --  one to get the old information back.
Release: PROCEDURE [self: Inscript] RETURNS [nilInscript: Inscript];

GetPageLimits: PROCEDURE [self: Inscript]
    RETURNS [earliestPageNo: InscriptPageNumber, latestPageNo: InscriptPageNumber];

  -- Creates an invalid page descriptor, such that any operations applied
  --  to it will fail until  a SetPageDescriptor operation has been executed.

ResetPageDescriptor: PROCEDURE [self: Inscript, descriptor: InscriptPageDescriptor];

CopyPageDescriptor: PROCEDURE [self: Inscript, dest: InscriptPageDescriptor,
    source: InscriptPageDescriptor];

  -- The descriptor will now describe the indicated page number.
  --  The next read will obtain the first entry on the page.
  --  Returns FALSE if specified page does not exist at the time of call.

SetPage: PROCEDURE [self: Inscript, descriptor: InscriptPageDescriptor,
    pageNumber: InscriptPageNumber, init: BOOLEAN←FALSE] RETURNS [success: BOOLEAN];

  -- Advances descriptor to describe the next page in sequence.

AdvancePage: PROCEDURE [self: Inscript, descriptor: InscriptPageDescriptor]
    RETURNS [success: BOOLEAN];

  -- Adds a new output page to the script, so that additional entries
  --  can be made.

SetWritePage: PROCEDURE [self: Inscript] RETURNS [success: BOOLEAN];

-- If page is not exhausted, passes pointer to next entry to LengthProc
--  procedure. LengthProc procedure must determine the length of the entry, returning a
--  count of the number of words used. ReadEntry then copies the entry
--  to the destination.   ReadEntry returns FALSE
--  if the page was exhausted or the returned count would exceed
--  the page limits. It raises NoValidPage if the Inscript no
--  longer remembers the contents of the page.
-- False is returned so that the client may, if desired, take special
--  action at each page boundary.  Normally, client will then call
--  AdvancePage to move on to the next page.

ReadEntry: PROCEDURE [self: Inscript, descriptor: InscriptPageDescriptor,
	destination: LONG POINTER TO UNSPECIFIED, LengthProc: LengthProcType]
    RETURNS [success: BOOLEAN];

  -- Returns FALSE if the contents of the descriptor will not fit in
  --  the remainder of the current output page. Otherwise copies the
  --  entry into the page.  Client should call SetWritePage to move on, then
  --  perhaps take special action before continuing with normal writes.

WriteEntry: PROCEDURE [self: Inscript, entry: LONG DESCRIPTOR FOR ARRAY OF WORD]
    RETURNS [success: BOOLEAN];
    
    
waitALongTime: Intime.MsTicks=5000;
WaitForEntry: PROCEDURE [self: Inscript, waitMode: WaitMode, waitInterval: Intime.MsTicks ← waitALongTime,
    descriptor: InscriptPageDescriptor, waitStartTime: LONG POINTER TO Intime.EventTime ← NIL]
    RETURNS [moreEntries: BOOLEAN];

  InscriptPageNumber: TYPE = INTEGER;
  AccessMethod: TYPE = {read, readNext, writeNew};
  OrderKey: TYPE = RECORD [a, b, c: WORD];
  COmProc: TYPE = PROCEDURE [a, b: OrderKey] RETURNS [aLessB: BOOLEAN];
  KEyProc: TYPE = PROCEDURE [
    inscript: Inscript, descriptor: InscriptPageDescriptor] RETURNS [OrderKey];
  LengthProcType: TYPE = PROCEDURE [p: LONG POINTER TO UNSPECIFIED]
    RETURNS [wordsToAdvance: CARDINAL];
  WaitMode: TYPE = {forever, dontWait, timed};

  InscriptError: -- Abstraction --ERROR [code: InscriptErrorCode];
   InscriptErrorCode: TYPE = {
     entryOutOfBounds, -- trying to position out of bounds or old stuff has disappeared
     invalidInscriptSpecs, -- bad arguments to NewStd...
     invalidInscriptFile, -- while opening old inscript file
     descriptorUninitialized -- in AdvancePage--,
     invalidPageKey -- in KeyProc during intitialization --};

  -- Inscript interface implementation --
  InscriptObject: TYPE;

  InscriptPageDescriptor: TYPE = LONG POINTER TO InscriptPageDescBody;
  InscriptPageDescBody: TYPE[4]; -- <<Need SIZE, Should be a better way>>

  END.