--  CreateLookupImpl.mesa
--  ryu 27-Jun-84 19:48:39

DIRECTORY
  CESDictDataDefs USING [DictBytesPerEntry, Entry],
  JLispLookupFile USING [MaxKanaPerEntry, MaxKanjiPerEntry, LEntry, DictPtr],
  CharDefs USING [Char, Code],
  PhonicDefs USING [Phonics],
  CreateLookupDictDefs,
  
  Heap USING [Create, Delete],
  Put USING [Text, Line, Decimal],
  Stream USING [Block, CompletionCode, Handle, PutByte, PutWord, GetBlock, SetPosition],
  Space USING [PageCount],
  Window USING [Handle];
  
CreateLookupImpl: PROGRAM IMPORTS Stream, Heap, Put
			  EXPORTS CreateLookupDictDefs =
BEGIN

-- Constants

Onesbyte: CARDINAL = 377B;
nullPhonic: CharDefs.Code = PhonicDefs.Phonics[nullPhonic].ORD;
MaxEntries : CARDINAL = 134;

-- Variables

mEntry: CESDictDataDefs.Entry;
nullPtr: JLispLookupFile.DictPtr ← [0, , 0];
pMEntry: LONG POINTER TO CESDictDataDefs.Entry ← @mEntry;
inBlock: Stream.Block ← [LOOPHOLE [LONG[@mEntry]], 0, CESDictDataDefs.DictBytesPerEntry];
nBytes: CARDINAL ← 0;
kana0, kana1: CharDefs.Code ← nullPhonic;
currentDictPtr, oldDictPtr: JLispLookupFile.DictPtr;
kanjiArray: ARRAY [0..JLispLookupFile.MaxKanjiPerEntry) OF CharDefs.Char;
nKanjis: CARDINAL ← 0;
recsize : CARDINAL ← 0;
nKanaCodes : CARDINAL ← 0;
KanaCode : PACKED ARRAY [0..JLispLookupFile.MaxKanaPerEntry) OF CharDefs.Code;
nOldKana: CARDINAL ← 0;
oldKana: PACKED ARRAY [0..JLispLookupFile.MaxKanaPerEntry) OF CharDefs.Code;
nLEntries : CARDINAL ← 0;
pLEntry : ARRAY [0 .. MaxEntries] OF LONG POINTER TO JLispLookupFile.LEntry;
myZone: UNCOUNTED ZONE;
zoneSize: Space.PageCount = 200;
firstTime: BOOLEAN;

why: Stream.CompletionCode;

-- Create is the Main Line of this module
  
CreateLookupDict:  PUBLIC PROCEDURE [masterStrH: Stream.Handle,
                                     lookupStrH: Stream.Handle,
				     indexStrH:  Stream.Handle,
                                     msgSW, logSW: Window.Handle]
                   RETURNS [nEntry, ctSkipped: LONG CARDINAL] =
BEGIN
  
  

-- Initialize initializes the index table (first part) of the lookup dictionary

Initialize: PROCEDURE[] =
BEGIN
  myZone ← Heap.Create[initial: zoneSize, increment: 10, threshold: 16, checking: TRUE]; 
  KanaCode ← ALL [nullPhonic];
--  KanaCode[0] ← PhonicDefs.Phonics[hirSmallA].ORD;
  kana0 ← nullPhonic;
  kana1 ← nullPhonic;
  nLEntries ← 0;
  pLEntry ← ALL [NIL];
  recsize ← 0;
  currentDictPtr.dictPageNo ← 0;
  currentDictPtr.relAddr ← 1;
  oldDictPtr ← currentDictPtr;
  InitIndex[];
  Stream.SetPosition[indexStrH, LONG[0] ];
  Stream.PutWord[lookupStrH, 0];
  firstTime ← TRUE;
END;

-- InitIndex

InitIndex: PROCEDURE[] =
BEGIN
  i, j: LONG CARDINAL;
  
  Stream.SetPosition[indexStrH, LONG[0]];
  FOR i IN [PhonicDefs.Phonics[hirSmallA].ORD .. PhonicDefs.Phonics[hirN].ORD] DO
    FOR j IN [nullPhonic .. PhonicDefs.Phonics[hirN].ORD] DO
      OutputDictPtr[indexStrH, nullPtr];
    ENDLOOP;
  ENDLOOP;
END;    

-- AddEntry 

AddEntry: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = 
BEGIN
  ConvertNullPhonic[pMEntry];
  IF EqKana[KanaCode, pMEntry.kana]
    THEN SameRecord[pMEntry]
    ELSE DifferentRecord[pMEntry];
END;

-- ConvertNullPhonic

ConvertNullPhonic: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = 
BEGIN
  i: CARDINAL;
  
  FOR i IN [0..JLispLookupFile.MaxKanaPerEntry) DO
    IF pMEntry.kana[i] = Onesbyte THEN pMEntry.kana[i] ← nullPhonic;
  ENDLOOP;
END;

-- EqKana

EqKana: PROCEDURE[kana1, kana2: PACKED ARRAY [0..JLispLookupFile.MaxKanaPerEntry) OF CharDefs.Code]
	  RETURNS[BOOLEAN] =
BEGIN
  i: CARDINAL;
  
  FOR i IN [0..JLispLookupFile.MaxKanaPerEntry) DO
    IF kana1[i] # kana2[i] THEN RETURN[FALSE];
    IF kana1[i] = nullPhonic THEN RETURN[TRUE];
  ENDLOOP;
  RETURN[TRUE]
END;

-- SameRecord

SameRecord: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] =
BEGIN
  nWords, i: CARDINAL;
  
  IF nLEntries >= MaxEntries
    THEN { Put.Text[logSW, "Entry table overflow: "L];
    	   FOR i IN [0 .. nKanaCodes-1) DO
	     Put.Decimal[logSW, KanaCode[i]];
	     Put.Text[logSW, ", "]
	   ENDLOOP;
	   Put.Decimal[logSW, KanaCode[nKanaCodes-1]];
	   Put.Line[logSW, " "L] }
    ELSE { [nWords, pLEntry[nLEntries]] ← ConvertEntry[pMEntry];
           nLEntries ← nLEntries + 1;
           recsize ← recsize + nWords;
	   nEntry ← nEntry + 1 };
END;

-- ConvertEntry

ConvertEntry: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] 
		RETURNS [nWords: CARDINAL, pLEntry: LONG POINTER TO JLispLookupFile.LEntry] =
BEGIN
  i: CARDINAL;
  
  nKanjis ← 0;
  FOR i IN [0..JLispLookupFile.MaxKanjiPerEntry) DO
    kanjiArray[i] ← pMEntry.kanji[i];
    IF kanjiArray[i].code # Onesbyte THEN nKanjis ← i + 1;
  ENDLOOP;
  pLEntry ← myZone.NEW[JLispLookupFile.LEntry[nKanjis]];
  pLEntry↑.nKanjis ← nKanjis;
  pLEntry↑.pos ← pMEntry↑.pos;
  pLEntry↑.pre ← 1;
  pLEntry↑.freq ← pMEntry↑.freq;
  FOR i IN [0..nKanjis) DO
    pLEntry↑.kanji[i] ← pMEntry.kanji[i]
  ENDLOOP;
  nWords ← nKanjis + 3;
  RETURN [nWords, pLEntry];
END;

-- DifferentRecord

DifferentRecord: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] =
BEGIN
  nWords: CARDINAL;
  
  IF firstTime THEN firstTime ← FALSE
	       ELSE OutputPrevRecord[];
  SetupKanaCodes[pMEntry];
  ClearAllLEntries[];
  nLEntries ← 1;
  [nWords, pLEntry[0]] ← ConvertEntry[pMEntry];
  recsize ← nWords + CeilQuotient[nKanaCodes, 2] + 3;
  			-- for recsize(1), nKanaCodes(1), and nLEntries(1)
  nEntry ← nEntry + 1;
END;

-- OutputPrevRecord

OutputPrevRecord: PROCEDURE =
BEGIN
  i: CARDINAL;
  
  Stream.PutWord[lookupStrH, recsize];
  Stream.PutWord[lookupStrH, nKanaCodes];
  FOR i IN [0..nKanaCodes) DO
    Stream.PutByte[lookupStrH, KanaCode[i]]
  ENDLOOP;
  IF nKanaCodes MOD 2 # 0 THEN Stream.PutByte[lookupStrH, nullPhonic];
  Stream.PutWord[lookupStrH, nLEntries];
  FOR i IN [0..nLEntries) DO
    OutputEntry[ pLEntry[i] ];
  ENDLOOP;
  -- OutputDictPtr[lookupStrH, nullPtr];
  AdvancePtr[recsize];
END;

-- OutputEntry

OutputEntry: PROCEDURE[pLEntry: LONG POINTER TO JLispLookupFile.LEntry] =
BEGIN
  i: CARDINAL;
  
  Stream.PutWord[lookupStrH, pLEntry.nKanjis];
  FOR i IN [0..pLEntry.nKanjis) DO
    Stream.PutByte[lookupStrH, pLEntry.kanji[i].chset];
    Stream.PutByte[lookupStrH, pLEntry.kanji[i].code]
  ENDLOOP;
  Stream.PutByte[lookupStrH, pLEntry.pos];
  Stream.PutByte[lookupStrH, pLEntry.pre];
  Stream.PutByte[lookupStrH, pLEntry.freq];
  Stream.PutByte[lookupStrH, pLEntry.reserved];
END;

-- OutputDictPtr

OutputDictPtr: PROCEDURE [strH: Stream.Handle, aDictPtr: JLispLookupFile.DictPtr] =
BEGIN
  Stream.PutWord[strH, aDictPtr.dictPageNo];
  Stream.PutByte[strH, aDictPtr.padding];
  Stream.PutByte[strH, aDictPtr.relAddr];
END;

-- AdvancePtr

AdvancePtr: PROCEDURE[adv: CARDINAL] =
BEGIN
  temp: CARDINAL;
  
  temp ← CARDINAL[currentDictPtr.relAddr] + adv;
  currentDictPtr.dictPageNo ← currentDictPtr.dictPageNo + temp/256;
  currentDictPtr.relAddr ← temp MOD 256;
END;

-- ClearAllLEntries

ClearAllLEntries: PROCEDURE =
BEGIN
  i: CARDINAL;
  
  FOR i IN [0.. nLEntries) DO
    myZone.FREE[ @pLEntry[i] ];
  ENDLOOP;
END;

-- SetupKanaCodes

SetupKanaCodes: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] =
BEGIN
  i: CARDINAL;
 
  nOldKana ← nKanaCodes;
  FOR i IN [0..JLispLookupFile.MaxKanaPerEntry) DO
    oldKana[i] ← KanaCode[i]
  ENDLOOP;
  FOR i IN [0..JLispLookupFile.MaxKanaPerEntry) DO
    KanaCode[i] ← pMEntry.kana[i];
    IF KanaCode[i] # nullPhonic
      THEN nKanaCodes ← i + 1
  ENDLOOP;
  IF KanaCode[0] # kana0 OR KanaCode[1] # kana1
    THEN { NewIndex[KanaCode[0], KanaCode[1]];
    	   oldDictPtr ← currentDictPtr;
           kana0 ← KanaCode[0];
	   kana1 ← KanaCode[1]}
END;

-- NewIndex

NewIndex: PROCEDURE [kana0, kana1: CharDefs.Code] =
BEGIN
  position: LONG CARDINAL;
  
  IF kana0 = nullPhonic AND kana1 = nullPhonic THEN RETURN;
  position ← ((kana0-1)*(PhonicDefs.Phonics[hirN].ORD + 1) + kana1)*4;
    -- position ← ((kana0-1)*84 + kana1)*4;
  Stream.SetPosition[indexStrH, position];
  OutputDictPtr[indexStrH, currentDictPtr];
  
END;   

LastEntry: PROCEDURE [pMEntry: LONG POINTER TO CESDictDataDefs.Entry] = 
BEGIN
  OutputPrevRecord[];
 -- NewIndex[kana0, kana1];
  ClearAllLEntries[];
END;

-- CeilQuotient

CeilQuotient: PROCEDURE [x, y: CARDINAL] RETURNS[CARDINAL] =
BEGIN
  IF x MOD y = 0 THEN RETURN[x/y]
  		 ELSE RETURN[x/y+1]
		
END;

-- main line of Create

  Initialize[];
  nEntry ← 1;
  
  DO
    [nBytes, why] ← Stream.GetBlock[masterStrH, inBlock];
    IF why = endOfStream THEN { LastEntry[pMEntry]; EXIT };
    IF pMEntry.pos >= 1 AND pMEntry.pos <= 60B 
      AND (pMEntry.kanji[1].code.ORD = Onesbyte OR pMEntry.freq >= 4)
      THEN AddEntry[pMEntry];
  ENDLOOP;
  
  Heap.Delete[myZone,TRUE];
  RETURN[nEntry, 0];
  
END;  -- of Create
END.