/* This file was generated by scm2java from source file "prev.scm" */
/*  "prev.scm" WB-tree File Based Associative String Data Base System. */
/*  Copyright (C) 1991, 1992, 1993, 2000 Free Software Foundation, Inc. */
/*  */
/*  This program is free software: you can redistribute it and/or modify */
/*  it under the terms of the GNU Lesser General Public License as */
/*  published by the Free Software Foundation, either version 3 of the */
/*  License, or (at your option) any later version. */
/*  */
/*  This program is distributed in the hope that it will be useful, but */
/*  WITHOUT ANY WARRANTY; without even the implied warranty of */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/*  Lesser General Public License for more details. */
/*  */
/*  You should have received a copy of the GNU Lesser General Public */
/*  License along with this program.  If not, see */
/*  <http://www.gnu.org/licenses/>. */



package wb;

import static wb.Ents.*;
import static wb.Seg.*;
import static wb.Blink.*;
import static wb.Wbdefs.*;
import static wb.Wbsys.*;
import static wb.Blk.*;
import static wb.SchlepRT.*;
import static wb.Pkt.*;
import static wb.Ent.*;
public class Prev {


public static Ent chainPrevFind(Ent ent,int accmode,byte []keyStr,int kLen,int []pkt,Ent prevEnt,int prevPos)
{
LchainPrevFind:while (true) {
  {
    byte []blk = ent_Blk(ent);
    blk_FindPos(blk, keyStr, kLen, pkt);
    if ((pkt_MatchType(pkt))==(pastend)
        && !(endOfChain_P(blk)))
      {
	int nxtNum = blk_NxtId(blk);
	Seg seg = ent_Seg(ent);
	Ent nent = null;
	boolean emptyBlk_P = (pkt_MatchPos(pkt))==(blkDataStart);
	int ppos = (emptyBlk_P
	  ?prevPos
	  :pkt_PrevMatchPos(pkt));
	if (emptyBlk_P)
	  {
	    releaseEnt(ent, accmode);
	  }
	else {
	  if (a2b(prevEnt))
	    releaseEnt(prevEnt, accnone);
	  ents_EntUpdateAccess_P(ent, accmode, accnone);
	  prevEnt = ent;
	}
	nent = getEnt(seg, nxtNum, accmode);
	{
	  ent = nent;
	  prevPos = ppos;
	  continue LchainPrevFind;
	}
      }
    else if ((pkt_MatchPos(pkt))==(blkDataStart))
      if (a2b(prevEnt))
	{
	  releaseEnt(ent, accmode);
	  ents_EntUpdateAccess_P(prevEnt, accnone, accmode);
	  pkt_SetMatchType(pkt, match);
	  pkt_SetMatchPos(pkt, prevPos);
	  return prevEnt;
	}
      else {
	pkt_SetMatchType(pkt, pastend);
	pkt_SetMatchPos(pkt, 0);
	return ent;
      }
    else {
      if (a2b(prevEnt))
	releaseEnt(prevEnt, accnone);
      pkt_SetMatchType(pkt, match);
      pkt_SetMatchPos(pkt, pkt_PrevMatchPos(pkt));
      return ent;
    }
  }
}
}


public static boolean strGtr_P(byte []aStr,int aPos,int aLen,byte []bStr,int bPos,int bLen)
{
  {
    int i = 0;
    int ap = aPos;
    int bp = bPos;
Lloop: while (true) {
    if ((i)>=(aLen))
      return false;
    else if ((i)>=(bLen))
      return (true);
    else if (((aStr[ap] & 0xFF))<((bStr[bp] & 0xFF)))
      return false;
    else if (((bStr[bp] & 0xFF))<((aStr[ap] & 0xFF)))
      return (true);
    else {
      i = (i)+1;
      ap = (ap)+1;
      bp = (bp)+1;
      continue Lloop;
    }
    }
  }
}

/*  PREV-KEY-ENT [was PREV-KEY] assumes entry with ACCNONE accmode to BLK. */
/*  It either returns the  entry contining PREV(key) (with READ access) */
/*  (and pos(prev) in PKT, type=MATCH) or #f, if there is no such key. */
/*  call PREV-KEY-ENT with ROOT block... */

/*  NOTE: PREV:PREV-K-ENT still needs the PENT kluge to keep the block */
/*  unchanged while it works. */

public static Ent prev_PrevKEnt(Ent ent,byte []keyStr,int kLen,int level,int []pkt)
{
  if (a2b(ent))
    {
      Ent pent = getEnt(ent_Seg(ent), ent_Id(ent), accnone);
      ent = chainPrevFind(ent, accread, keyStr, kLen, pkt, null, 0);
      {
	Ent resEnt = ent;
	if ((pkt_MatchType(pkt))!=(match))
	  {
	    releaseEnt(ent, accread);
	    resEnt = prev_PrevKEnt(prevBlkEnt(pent, level), keyStr, kLen, level, pkt);
	  }
	releaseEnt(pent, accnone);
	return resEnt;
      }
    }
  else return null;
}


public static Ent prevKeyEnt(Ent ent,byte []keyStr,int kLen,int level,int []pkt)
{
  if (a2b(ent))
    return prev_PrevKEnt(prev_FindPrevEnt(ent, level,  -1, keyStr, kLen), keyStr, kLen, level, pkt);
  else return null;
}

/*  CHAIN-TO-PREV-ENT: subroutine for PREV-BLK-ENT */
/*  this routine chains fwd from FROM-ENT to imm predecessor of GOAL-BLK */
/*  called with FROM-ENT open with ACCREAD; assumes GOAL-BLOCK-NO Name-locked */
/*  returns an ENT open ACCREAD unless missed block, which returns #f */
/*  (routine also checks if its past key) */


public static Ent chainToPrevEnt(Ent fromEnt,int goalBlkNum,byte []goalKeyStr,int keyLen)
{
LchainToPrevEnt:while (true) {
  {
    byte []fromBlk = ent_Blk(fromEnt);
    if ((blk_NxtId(fromBlk))==(goalBlkNum))
      return fromEnt;
    else if (endOfChain_P(fromBlk))
      {
	System.err.print(">>>>ERROR<<<< "+("chainToPrevEnt")+": hit end of "+(ent_Id(fromEnt))+":"+(goalBlkNum)+" lev="+(blk_Level(fromBlk))
   +" "+(keyLen)+"\n");
	return null;
      }
    else {
      int bPos = blkDataStart;
      if (strGtr_P(fromBlk, (bPos)+2, fieldLen(fromBlk, (bPos)+1), goalKeyStr, 0, keyLen))
	{
	  System.err.print(">>>>ERROR<<<< "+("chainToPrevEnt")+": missed blk "+(ent_Id(fromEnt))+":"+(goalBlkNum)+" lev="+(blk_Level(fromBlk))
   +" "+(keyLen)+"\n");
	  return null;
	}
      else {
	fromEnt = switchEnt(fromEnt, accread, blk_NxtId(fromBlk), accread);
	continue LchainToPrevEnt;
      }
    }
  }
}
}

/*  there must be a more efficient way to check this !!! */

public static boolean atRootLevel_P(Seg seg,byte []blk)
{
  if (root_P(blk))
    return (true);
  else {
    Ent rent = getEnt(seg, blk_TopId(blk), accread);
    byte []rblk = ent_Blk(rent);
    int rlevel = blk_Level(rblk);
    boolean res_P = (blk_Level(blk))==(rlevel);
    releaseEnt(rent, accread);
    return res_P;
  }
}

/*  PREV-BLK-ENT [was PREV-BLK] is called with ENT (with ACCNONE accmode) */
/*  which IS PRESERVED. IT finds the block that precedes ENT, or #f. */
/*  It returns a (second) entry with READ access or #f. */
/*  TBD - shouldn't it release ENT if returning #f? */
/*  (no, not as things are now -- rjz) */

public static Ent prevBlkEnt(Ent ent,int level)
{
  ents_EntUpdateAccess_P(ent, accnone, accread);
  {
    byte []blk = ent_Blk(ent);
    ents_EntUpdateAccess_P(ent, accread, accnone);
    if (root_P(blk))
      return null;
    else {
      int skeyPos = splitKeyPos(blk);
      if (0 < (skeyPos))
	{
	  int topNum = blk_TopId(blk);
	  Seg seg = ent_Seg(ent);
	  int goalBlkNum = ent_Id(ent);
	  byte []newStr = new byte[0x100];
	  int kLen = reconThisKey(blk, skeyPos, newStr, 0, 0x100);
	  if (atRootLevel_P(seg, blk))
	    {
	      System.err.print(""+("prevBlkEnt")+" code which has never been run!!\n");
	      return chainToPrevEnt(getEnt(seg, topNum, accread), goalBlkNum, newStr, kLen);
	    }
	  else {
	    int []pkt = new int[pktSize];
	    ent = prevKeyEnt(getEnt(seg, topNum, accnone), newStr, kLen, (level)+1, pkt);
	    if ((ent)==null)
	      return null;
	    else {
	      int nxtPos = nextField(ent_Blk(ent), 1+(pkt_MatchPos(pkt)));
	      int num = 0;
	      if ((nxtPos)==(blk_End(ent_Blk(ent))))
		{
		  System.err.print(""+("prevBlkEnt")+": I'm confused: at split key of blk "+(seg_Id(ent_Seg(ent)))+":"+(ent_Id(ent))+"");
		  num = (pkt_MatchPos(pkt))-4;
		}
	      else num = 1+(nxtPos);
	      return chainToPrevEnt(switchEnt(ent, accread, str2long(ent_Blk(ent), num), accread), goalBlkNum, newStr, kLen);
	    }
	  }
	}
      else return null;
    }
  }
}

/*  FIND-PREV-ENT: called (like FIND-NEXT) with ACCNONE accmode on ENT. */
/*  Returns a new ENT with ACCREAD accmode. Will always return an ENT */
/*  unless some GET-ENT fails. */


public static Ent prev_FindPrevEnt(Ent ent,int desiredLevel,int lastLevel,byte []keyStr,int kLen)
{
Lprev_FindPrevEnt:while (true) {
  if (a2b(ent))
    if (ents_EntUpdateAccess_P(ent, accnone, accread))
      {
	byte []blk = ent_Blk(ent);
	if ((blk_Level(blk))==(desiredLevel))
	  return ent;
	else if ((blk_Level(blk))<(desiredLevel))
	  {
	    System.err.print(">>>>ERROR<<<< "+("findPrevEnt")+": bad blk level\n");
	    return null;
	  }
	else if ((lastLevel)>=0
	    && (blk_Level(blk))!=((lastLevel)-1))
	  {
	    System.err.print(">>>>ERROR<<<< "+("findPrevEnt")+": bad blk level "+(blk_Level(blk))+" last="+(lastLevel)+" in "+(seg_Id(ent_Seg(ent)))
   +":"+(ent_Id(ent))+"\n");
	    return null;
	  }
	else {
	  int []pkt = new int[pktSize];
	  ent = chainFind(ent, accread, keyStr, kLen, pkt);
	  if (a2b(ent))
	    {
	      int nxtPos = nextField(ent_Blk(ent), 1+(pkt_MatchPos(pkt)));
	      int ptrPos = ((nxtPos)==(blk_End(ent_Blk(ent)))
		?(pkt_MatchPos(pkt))-4
		:1+(nxtPos));
	      {
		Ent T_ent = switchEnt(ent, accread, str2long(ent_Blk(ent), ptrPos), accnone);
		lastLevel = blk_Level(ent_Blk(ent));
		ent = T_ent;
		continue Lprev_FindPrevEnt;
	      }
	    }
	  else return null;
	}
      }
    else return null;
  else return null;
}
}

}
