/**************************************************************************
 *
 * lstevent.c -- Routines to implement "events" using MTF lists.
 * Copyright (C) 1987  Alistair Moffat
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: lstevent.c 16583 2008-07-29 10:20:36Z davidb $
 *
 **************************************************************************/

#include "sysfuncs.h"

#include "arithcode.h"
#include "model.h"

/*
   $Log$
   Revision 1.1  2003/02/20 21:16:56  mdewsnip
   Addition of MG package for search and retrieval

   Revision 1.1  1999/08/10 21:17:26  sjboddie
   renamed mg-1.3d directory mg

   Revision 1.1  1998/11/17 09:33:37  rjmcnab
   *** empty log message ***

   * Revision 1.2  1994/09/20  04:41:40  tes
   * For version 1.1
   *
 */

static char *RCSID = "$Id: lstevent.c 16583 2008-07-29 10:20:36Z davidb $";

void
write_method ()
{
  fprintf (stderr, "C");
}


/*===========================================*/

/*
 * [Rodney Brown - Sep/95]
 * On IBM RS/6000 AIX version 3.2 the compiler defines NULL as (void *)0
 * when in ANSI mode. Hence the (event) and (point) casts
 */


#define GETNEWNODE(e,node)		\
do 					\
{	node = p32(numnodes) ;		\
	node->eventnum = (event)e ;	\
	node->count = increment ;	\
	node->foll.totalcnt = 0 ;	\
	node->foll.notfound = 0 ;	\
	node->foll.list = (point)NULL ;	\
	numnodes += 1 ;			\
	nfreenodes -= 1 ;		\
}					\
while (false)

/*===========================================*/

#define INSERTNODE(U,node)		\
do					\
{	node->next = U->list ;		\
	U->list = p16(node) ;		\
	U->totalcnt += increment;	\
}					\
while (false)

/*===========================================*/

int
halvelist (p)
     register eventnode *p;
{
  register int sum = 0;
  while (p != ENULL)
    {
      sum += p->count = (p->count + 1) / 2;
      p = p32 (p->next);
    }
  return (sum);
}

/*===========================================*/

void
halveallcounts (U)
     register eventset *U;
{
  U->notfound = (U->notfound + 1) / 2;
  U->totalcnt = U->notfound;
  U->totalcnt += halvelist (p32 (U->list));
}

/*===========================================*/

eventnode *
encode_event_noex (U, e, success)
     register eventset *U;
     event e;
     boolean *success;
{
  register eventnode *pnode, *node;
  register int lbnd, totl;

  if (U->list == (point)NULL)
    {
      *success = false;
      U->notfound += increment;
      U->totalcnt += increment;
      GETNEWNODE (e, node);
      INSERTNODE (U, node);
      return (node);
    }

  lbnd = 0;
  pnode = ENULL;
  node = p32 (U->list);
  while (node != ENULL)
    {
      if (e == node->eventnum)
	break;
      lbnd += node->count;
      pnode = node;
      node = p32 (node->next);
    }

  totl = U->totalcnt;

  if (node == ENULL)
    {				/* event not found in list */
      if ((totl > U->notfound))
	arithmetic_encode (totl - U->notfound, totl, totl);
      U->notfound += increment;
      U->totalcnt += increment;
      *success = false;
      GETNEWNODE (e, node);
      INSERTNODE (U, node);
    }
  else
    {				/* found in the list, so go ahead and code */
      arithmetic_encode (lbnd, lbnd + node->count, totl);
      node->count += increment;
      U->totalcnt += increment;
      *success = true;
      /* and move to front */
      if (pnode != ENULL)
	{
	  pnode->next = node->next;
	  node->next = U->list;
	  U->list = p16 (node);
	}
    }
  if (U->totalcnt > maxtotalcnt)
    halveallcounts (U);
  return (node);
}

/*===========================================*/

eventnode *
decode_event_noex (U, success, e)
     register eventset *U;
     boolean *success;
     event *e;
{
  register eventnode *node, *pnode;
  register int tget, lbnd, totl;

  if (U->list == (point)NULL)
    {
      *success = false;
      U->totalcnt += increment;
      U->notfound += increment;
      GETNEWNODE (NULL, node);
      INSERTNODE (U, node);
      return (node);
    }
  totl = U->totalcnt;
  tget = arithmetic_decode_target (totl);

  if (tget >= totl - U->notfound)
    {
      if (totl > U->notfound)
	arithmetic_decode (totl - U->notfound, totl, totl);
      U->totalcnt += increment;
      U->notfound += increment;
      *success = false;
      GETNEWNODE (NULL, node);
      INSERTNODE (U, node);
    }
  else
    {
      pnode = ENULL;
      node = p32 (U->list);
      lbnd = 0;
      for (;;)
	{
	  if (tget < (lbnd += node->count))
	    break;
	  pnode = node;
	  node = p32 (node->next);
	}

      arithmetic_decode (lbnd - node->count, lbnd, totl);
      node->count += increment;
      U->totalcnt += increment;
      *e = node->eventnum;
      *success = true;
      /* and move to front */
      if (pnode != ENULL)
	{
	  pnode->next = node->next;
	  node->next = U->list;
	  U->list = p16 (node);
	}
    }
  if (U->totalcnt > maxtotalcnt)
    halveallcounts (U);
  return (node);
}

/*===========================================*/

eventnode *
encode_event (U, e, success)
     register eventset *U;
     event e;
     boolean *success;
{
  register eventnode *pnode, *node, *p;
  register int lbnd, totl;

  if (U->list == (point)NULL)
    {
      *success = false;
      U->notfound += increment;
      U->totalcnt += increment;
      GETNEWNODE (e, node);
      INSERTNODE (U, node);
      return (node);
    }

  lbnd = 0;
  pnode = ENULL;
  node = p32 (U->list);
  while (node != ENULL)
    {
      if (!excluded[node->eventnum])
	{
	  if (e == node->eventnum)
	    break;
	  lbnd += node->count;
	}
      pnode = node;
      node = p32 (node->next);
    }

  if (node == ENULL)
    {				/* event not found in list, and whole list has been scanned */
      totl = lbnd + U->notfound;
      if ((totl > U->notfound))
	arithmetic_encode (totl - U->notfound, totl, totl);
      U->notfound += increment;
      U->totalcnt += increment;
      *success = false;
      GETNEWNODE (e, node);
      INSERTNODE (U, node);
    }
  else
    {				/* found in the list, so go ahead and code */
      /* first, total up rest of list */
      totl = lbnd + node->count;
      p = p32 (node->next);
      while (p != ENULL)
	{
	  if (!excluded[p->eventnum])
	    totl += p->count;
	  p = p32 (p->next);
	}
      totl += U->notfound;

      arithmetic_encode (lbnd, lbnd + node->count, totl);
      node->count += increment;
      U->totalcnt += increment;
      *success = true;
      /* and move to front */
      if (pnode != ENULL)
	{
	  pnode->next = node->next;
	  node->next = U->list;
	  U->list = p16 (node);
	}
    }
  if (U->totalcnt > maxtotalcnt)
    halveallcounts (U);
  return (node);
}

/*===========================================*/

eventnode *
decode_event (U, success, e)
     register eventset *U;
     boolean *success;
     event *e;
{
  register eventnode *node, *pnode;
  register int tget, lbnd, totl;

  if (U->list == (point)NULL)
    {
      *success = false;
      U->totalcnt += increment;
      U->notfound += increment;
      GETNEWNODE (NULL, node);
      INSERTNODE (U, node);
      return (node);
    }
  totl = 0;
  node = p32 (U->list);
  while (node != ENULL)
    {
      if (!excluded[node->eventnum])
	totl += node->count;
      node = p32 (node->next);
    }
  totl += U->notfound;
  tget = arithmetic_decode_target (totl);

  if (tget >= totl - U->notfound)
    {
      if (totl > U->notfound)
	arithmetic_decode (totl - U->notfound, totl, totl);
      U->totalcnt += increment;
      U->notfound += increment;
      *success = false;
      GETNEWNODE (NULL, node);
      INSERTNODE (U, node);
    }
  else
    {
      pnode = ENULL;
      node = p32 (U->list);
      lbnd = 0;
      for (;;)
	{
	  if (!excluded[node->eventnum])
	    {
	      lbnd += node->count;
	      if (tget < lbnd)
		break;
	    }
	  pnode = node;
	  node = p32 (node->next);
	}

      arithmetic_decode (lbnd - node->count, lbnd, totl);
      node->count += increment;
      U->totalcnt += increment;
      *e = node->eventnum;
      *success = true;
      /* and move to front */
      if (pnode != ENULL)
	{
	  pnode->next = node->next;
	  node->next = U->list;
	  U->list = p16 (node);
	}
    }
  if (U->totalcnt > maxtotalcnt)
    halveallcounts (U);
  return (node);
}

/*===========================================*/

eventnode *
newnode (e)
     event e;
{
  register eventnode *node;
  GETNEWNODE (e, node);
  node->next = (point)NULL;
  node->prev = (point)NULL;
  return (node);
}

/*===========================================*/

/* not required in this version */

#if 0
eventnode *
addevent (U, e)
     register eventset *U;
     event e;
{
  register eventnode *node;
  /* get an event node */
  GETNEWNODE (e, node);
  INSERTNODE (U, node);
  if (U->totalcnt > maxtotalcnt)
    halveallcounts (U);
  return (node);
}
#endif
