/* This file was generated by scm2java from source file "segs.scm" */
/*  "segs.scm" WB-tree File Based Associative String Data Base System. */
/*  Copyright (C) 1991, 1992, 1993, 2000, 2007, 2010 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/>. */

/*  routines in this file return success codes */



package wb;

import static wb.Ents.*;
import static wb.Blkio.*;
import static wb.Blink.*;
import static wb.Wbdefs.*;
import static wb.Handle.*;
import static wb.Wbsys.*;
import static wb.Blk.*;
import static wb.SchlepRT.*;
import static wb.Lck.*;
import static wb.Ent.*;
import static wb.Seg.*;
import static wb.Han.*;
public class Segs {


public static int segCntr = 4;

public static Seg segChain = null;

public static Lck segChainLck = makeLck( -3);

/*  Create segment-descriptor and splice into seg-chain. */

public static Seg newSeg(String filename,String caller)
{
  if (a2b(lckTab))
    {
      lck(segChainLck);
      {
	Seg sseg = segChain;
Lloop: while (true) {
	{
BmakeIt:while (true) {
	    if (!(a2b(sseg)))
	      break BmakeIt;
	    else if (a2b(seg_Str(sseg))
	        && filename.equals(seg_Str(sseg)))
	      {
		System.err.print(">>>>ERROR<<<< "+(caller)+": segment already open to \""+(filename)+"\"\n");
		unlck(segChainLck);
		return null;
	      }
	    else if ((segChain)==(seg_Nxt(sseg)))
	      break BmakeIt;
	    else {
	      sseg = seg_Nxt(sseg);
	      continue Lloop;
	    }
	  }
	  {
	    Seg seg = newSegd(segCntr);
	    seg_SetStr(seg, filename);
	    if (a2b(segChain))
	      {
		Seg prevSeg = seg_Prv(segChain);
		seg_SetNxt(prevSeg, seg);
		seg_SetPrv(seg, prevSeg);
		seg_SetNxt(seg, segChain);
		seg_SetPrv(segChain, seg);
	      }
	    else {
	      seg_SetNxt(seg, seg);
	      seg_SetPrv(seg, seg);
	    }
	    seg_SetFlc(seg, new int [flcLen]);
	    seg_SetFlcLen(seg, 0);
	    segCntr = 1+(segCntr);
	    segChain = seg;
	    unlck(segChainLck);
	    return seg;
	  }
	}
	}
      }
    }
  else {
    System.err.print(">>>>ERROR<<<< "+(caller)+": WB not initialized (need to call "+("initWb")+")\n");
    return null;
  }
}

/*  lock must already be held on seg-chain-lck */

public static void freeSeg(Seg seg)
{
  if (!(a2b(segChain)))
    {
      System.err.print(">>>>ERROR<<<< "+("freeSeg")+": "+("segChain")+" already empty!\n");
      return;
    }
  else if ((seg_Prv(seg))==(seg))
    {
      if ((seg)!=(segChain))
	System.err.print(">>>>ERROR<<<< "+("freeSeg")+": corrupted "+("segChain")+".\n");
      segChain = null;
      return;
    }
  else {
    Seg nextSeg = seg_Nxt(seg);
    Seg prevSeg = seg_Prv(seg);
    seg_SetNxt(prevSeg, nextSeg);
    seg_SetPrv(nextSeg, prevSeg);
    if ((seg)==(segChain))
      segChain = ((segChain)==(nextSeg)
	?null
	:nextSeg);
      return;
  }
}


public static boolean checkFile_P(String filename)
{
  java.io.RandomAccessFile file = blkio_OpenReadOnlyFile(filename, 0x80);
  byte []tblk = new byte[0x80];
  if (a2b(file))
    {
      boolean allok_P = blkio_Read(file, tblk, 0x80, 0)
      && 0==(str2long(tblk, 0))
      && 0==(str2long(tblk, 4))
      && 0==(str2long(tblk, 8))
      && 0x77==((tblk[0x17] & 0xFF))
      && 0x62==((tblk[0x18] & 0xFF));
      blkio_FileClose(file, 0x80, !((true)));
      return allok_P;
    }
  else return false;
}


public static Seg openSeg(String filename,boolean mutable_P)
{
  return openSegd(filename, mutable_P, !((true)));
}


public static Seg openSegd(String filename,boolean mutable_P,boolean evenIfDirty_P)
{
  int bsiz = 3*0x80;
  if ((bsiz)>(blkSize))
    {
      System.err.print(">>>>ERROR<<<< unsupported "+("bsiz")+" "+(bsiz)+" > "+(blkSize)+"\n");
      return null;
    }
  else if (!(checkFile_P(filename)))
    return null;
  else {
    Seg seg = newSeg(filename, "openSeg");
    String reason;
Berrout:while (true) {
      if (!(a2b(seg)))
	return seg;
      else {
	java.io.RandomAccessFile file = (mutable_P
	  ?blkio_OpenModifyFile(filename, bsiz)
	  :blkio_OpenReadOnlyFile(filename, bsiz));
Lloop: while (true) {
	if (blkio_PortOpen_P(file, mutable_P))
	  {
	    seg_SetPort(seg, file);
	    seg_SetBsiz(seg, bsiz);
	    seg_SetUsed(seg, 2);
	    seg_SetFlcLen(seg, (mutable_P
		? -1
		: -2));
	    {
	      Han han = seg_RtHan(seg);
	      byte []tmpStr = new byte[0x100];
	      if (err_P(btOpen(seg, 0, han, (wcbSap)+(wcbSar))))
		{
		  reason = "bt-open 0";
		  break Berrout;
		}
	      else if (2!=(btGet(han, bsizByts, 4, tmpStr)))
		{
		  reason = "BSIZ";
		  break Berrout;
		}
	      else if ((bsiz)!=(str2short(tmpStr, 0)))
		{
		  blkio_FileClose(file, bsiz, mutable_P);
		  bsiz = str2short(tmpStr, 0);
		  if ((bsiz)>(blkSize))
		    {
		      reason = "BSIZ too big.";
		      break Berrout;
		    }
		  else {
		    file = (mutable_P
		      ?blkio_OpenModifyFile(filename, bsiz)
		      :blkio_OpenReadOnlyFile(filename, bsiz));
		    continue Lloop;
		  }
		}
	      else {
		boolean dty_P = mutable_P
	        && err_P(btRem(han, clnByts, 3, tmpStr));
		if (dty_P
		    && !(evenIfDirty_P))
		  {
		    reason = "not cleanly saved; use wbcheck to repair.";
		    break Berrout;
		  }
		else {
		  if (dty_P)
		    System.err.print("WARNING: File \""+(filename)+"\" not cleanly saved.\n");
		  if (4!=(btGet(han, usedByts, 4, tmpStr)))
		    {
		      reason = "USED";
		      break Berrout;
		    }
		  else {
		    seg_SetUsed(seg, str2long(tmpStr, 0));
		    if (5!=(btGet(han, fldByts, 3, tmpStr)))
		      {
			reason = "FLD";
			break Berrout;
		      }
		    else if (err_P(btOpen(seg, str2long(tmpStr, 1), seg_FlHan(seg), wcbSar)))
		      {
			reason = "FLC";
			break Berrout;
		      }
		    else {
		      if ((han_Typ(seg_FlHan(seg)))!=(frlTyp))
			System.err.print("Older type freelist - still supported.\n");
		      han_SetWcb(seg_FlHan(seg), wcbSar);
		      return seg;
		    }
		  }
		}
	      }
	    }
	  }
	else {
	  if (blkio_PortOpen_P(file, mutable_P))
	    blkio_FileClose(file, bsiz, mutable_P);
	  System.err.print(">>>>ERROR<<<< could not open file "+(filename)+"\n");
	  freeSeg(seg);
	  return null;
	}
	}
      }
    }
    System.err.print(">>>>ERROR<<<< File \""+(filename)+"\" "+(reason)+"\n");
    if (a2b(seg))
      {
	blkio_FileClose(seg_Port(seg), bsiz, mutable_P);
	seg_SetPort(seg, null);
	seg_SetStr(seg, null);
	seg_SetUsed(seg, 0);
	freeSeg(seg);
      }
    return null;
  }
}


public static int closeSeg(Seg seg,boolean hammer_P)
{
  if ((!(a2b(seg))
      || !(a2b(seg_Port(seg)))
      || !(a2b(seg_Str(seg)))
      || 0==(seg_Used(seg))))
    return notpres;
  else {
    flushFlc(seg, 5);
    /*leave only enough blocks to fit in flc in superblock.*/
    if ((seg_FlcLen(seg))>=0)
      {
	byte []tmpStr = new byte[0x14];
	{
	  int i =  -1+(seg_FlcLen(seg));
	  while (!(0 > (i))) {
	    long2str(tmpStr, 4*(i), seg_Flc(seg)[i]);
	    {
	      i =  -1+(i);
	    }
	  }
	}
	btPut(seg_RtHan(seg), flcByts, 3, tmpStr, 4*(seg_FlcLen(seg)));
	seg_SetFlcLen(seg,  -1);
      }
    {
      boolean mutable_P = seg_Mutable_P(seg);
      int ans = doSegBuffers(seg, getMethod("wb.Ents", "flushBuffer", new Class[]{Ent.class}));
      if ((success_P(ans)
	  || hammer_P))
	{
	  if (!(success_P(ans)))
	    ans = notpres;
	  doSegBuffers(seg, getMethod("wb.Ents", "purgeBuffer", new Class[]{Ent.class}));
	  if (mutable_P)
	    {
	      blkio_FlushToFile(seg_Port(seg), !((true)));
	      if (err_P(btWrite(seg_RtHan(seg), clnByts, 3, noByts, 0)))
		System.err.print("WARNING: mutable file \""+(seg_Str(seg))+"\" already clean?\n");
	    }
	  btClose(seg_RtHan(seg));
	  btClose(seg_FlHan(seg));
	  blkio_FileClose(seg_Port(seg), seg_Bsiz(seg), mutable_P);
	  seg_SetPort(seg, null);
	  seg_SetStr(seg, null);
	  
	  seg_SetFlc(seg, null);
	  seg_SetFlcLen(seg, 0);
	  seg_SetUsed(seg, 0);
	  freeSeg(seg);
	}
      return ans;
    }
  }
}


public static byte []dbVersionStr = stringToBytes("wb-2b1");

public static byte []dbAuthorsStr = stringToBytes("A. Jaffer, J. Finger, R. Zito-Wolf");


public static Seg makeSeg(String filename,int bsiz)
{
  Seg seg = newSeg(filename, "makeSeg");
  if (!(a2b(seg)))
    return seg;
  else if ((bsiz)>(blkSize))
    {
      System.err.print(">>>>ERROR<<<< unsupported "+("bsiz")+" "+(bsiz)+" > "+(blkSize)+"\n");
      unlck(seg_Lck(seg));
      return null;
    }
  else {
    java.io.RandomAccessFile file = blkio_CreateFile(filename, bsiz);
    if (blkio_PortOpen_P(file, true))
      {
	seg_SetPort(seg, file);
	seg_SetBsiz(seg, bsiz);
	seg_SetUsed(seg, 3);
	seg_SetStr(seg, filename);
	seg_SetFlcLen(seg,  -1);
	{
	  Han rtHan = seg_RtHan(seg);
	  Han han = seg_FlHan(seg);
	  byte []tmpStr = new byte[5];
	  if (btOpenNew(seg, 0, rtHan, (wcbSap)+(wcbSar), dirTyp)
	      && btOpenNew(seg, 1, han, wcbSap, dirTyp)
	      && btOpenNew(seg, 2, han, wcbSar, frlTyp))
	    {
	      btPut(rtHan, noByts, 0, dbVersionStr, dbVersionStr.length);
	      long2str(tmpStr, 0, seg_Used(seg));
	      btPut(rtHan, usedByts, 4, tmpStr, 4);
	      short2str(tmpStr, 0, seg_Bsiz(seg));
	      btPut(rtHan, bsizByts, 4, tmpStr, 2);
	      tmpStr[0] = (byte) (0xff&4);
	      long2str(tmpStr, 1, 1);
	      btPut(rtHan, rootByts, 4, tmpStr, 5);
	      long2str(tmpStr, 1, 2);
	      btPut(rtHan, fldByts, 3, tmpStr, 5);
	      btPut(rtHan, flcByts, 3, noByts, 0);
	      if ((bsiz)>0x80)
		btPut(rtHan, authorsByts, 7, dbAuthorsStr, dbAuthorsStr.length);
	      return seg;
	    }
	  else {
	    System.err.print(">>>>ERROR<<<< couldn't allocate ents for file "+(filename)+"\n");
	    unlck(seg_Lck(seg));
	    closeSeg(seg, true);
	    return null;
	  }
	}
      }
    else {
      System.err.print(">>>>ERROR<<<< couldn't create new file "+(filename)+"\n");
      unlck(seg_Lck(seg));
      return null;
    }
  }
}


public static int btOpen(Seg seg,int blkNum,Han han,int wcb)
{
  if (a2b(seg)
      && a2b(seg_Str(seg)))
    {
      Ent ent = getEnt(seg, blkNum, accread);
      if (!(a2b(ent)))
	return argerr;
      else if (!(root_P(ent_Blk(ent))))
	{
	  releaseEnt(ent, accread);
	  System.err.print(">>>>ERROR<<<< "+("btOpen")+": not a root "+(seg_Id(seg))+":"+(blkNum)+"\n");
	  return argerr;
	}
      else {
	btOpenInitHan(han, ent, wcb);
	releaseEnt(ent, accread);
	return han_Typ(han);
      }
    }
  else return argerr;
}


public static void btOpenInitHan(Han han,Ent ent,int wcb)
{
  int typ = blk_Typ(ent_Blk(ent));
  Seg seg = ent_Seg(ent);
  int blkNum = ent_Id(ent);
  han_SetSeg(han, seg);
  han_SetNum(han, blkNum);
  han_SetLast(han, blkNum);
  han_SetTyp(han, typ);
  if ((typ)==(dirTyp))
    wcb = (wcb)|((wcbSap)+(wcbSar));
  han_SetWcb(han, wcb);
  return;
}

/*  Does calling GET-BUK-WAIT admit the possiblity of deadly embrace? */

public static boolean btOpenNew(Seg seg,int blkNum,Han han,int wcb,int typ)
{
  if (0 > (blkNum))
    {
      System.err.print(">>>>ERROR<<<< negative block number "+(blkNum)+"\n");
      return false;
    }
  else {
    Ent ent = tryGetFreeEnt(null,  -1);
    while (!(a2b(ent))) {
      {
	ent = tryGetFreeEnt(null,  -1);
      }
    }
    initLeafBlk(ent_Blk(ent), blkNum, typ);
    blk_SetTime(ent_Blk(ent), (int)(System.currentTimeMillis()/1000));
    ent_SetNext(ent, getBukWait(seg_Id(seg), blkNum));
    setBuk(seg_Id(seg), blkNum, ent);
    ent_SetAcc(ent, accwrite);
    ent_SetSeg(ent, seg);
    ent_SetId(ent, blkNum);
    ent_SetAge(ent,  -127);
    ent_SetDty(ent, true);
    ent_SetPus(ent, 0);
    ent_SetRef(ent, 1);
    relBuk(seg_Id(seg), blkNum);
    btOpenInitHan(han, ent, wcb);
    ents_EntWrite(ent);
    releaseEnt(ent, accwrite);
    return (true);
  }
}


public static int btCreate(Seg seg,int typ,Han han,int wcb)
{
  if (a2b(seg)
      && a2b(han))
    {
      Ent ent = createNewBlkEnt(seg);
      if (a2b(ent))
	{
	  int blkNum = ent_Id(ent);
	  initLeafBlk(ent_Blk(ent), blkNum, typ);
	  ent_SetPus(ent, 0);
	  btOpenInitHan(han, ent, wcb);
	  ents_EntWrite(ent);
	  releaseEnt(ent, accwrite);
	  return success;
	}
      else return noroom;
    }
  else return argerr;
}


public static int btClose(Han han)
{
  if (a2b(han))
    {
      han_SetSeg(han, null);
      han_SetNum(han, 0);
      han_SetTyp(han, 0);
      han_SetLast(han, 0);
      return success;
    }
  else return argerr;
}

}
