/******************************************************************
 *  (C) Copyright 1994; dit/upm
 *  Distributed under the conditions stated in the
 *  TOPO General Public License (see file LICENSE)
 ******************************************************************
 *  $Log$
 ******************************************************************/

#ifndef lint
static char rcsid[]= "$Id$";
#endif

/******************************************************************
 *  
 *  Santiago Pavon Gomez
 *
 *  Management of LOTOS behaviour expressions
 *
 *  LOTOS has nullary operators (e.g stop), unitary operators
 *  (e.g action prefix) and binary operators (e.g. parallel).
 *  An exception is made for the choice expression.
 *  This interface considers the choice expression of n behaviours
 *  (n-1 choice operators B1[]B2[]...[]Bn) to be an n-ary operator
 *  ( only one operator ! ). 
 *  The access to an operand of all LOTOS operators is homogeneous.
 *
 *  Behaviours, alike LOTOS, always referres to trees.
 *  Operators are always implemented by a single cell
 *  except for the choice expression B1[]B2[]...[]Bn where
 *  n alternative cells are implied.
 *  When behaviours are copied its attributes are shared unless
 *  otherwise stated.
 *
 *  30 Nov 1990
 *
 *  COMPILATION FLAGS:
 *     SDEBUG : activate debugging checks
 *  
 *  LOG:
 *
 ******************************************************************/

/* LINTLIBRARY */


#include "badefca.h"
#include "babeh.h"
#include "limisc.h"
#include "batables.h"
#include "listdout.h"

/*----------------------------------------------------------------*/

/* PutNameB
 * Put the name d to the behaviour b.
 */
void PutNameB( b , d )
     BehTyp         b;
     DescriptorTyp  d;  
{
  PutName( b, d );
}

/*----------------------------------------------------------------*/

/* NumArgB
 * Current number of arguments of the behaviour b.
 */
int NumArgB( b )
     BehTyp  b;
{
  int i;
  
  LASSERT(b!=NULL);
  if (LookType(b)==AlternativeC) {
    for ( i=0 ; b!=NULL ; i++, b=LookB2(b) )
#ifdef SDEBUG
      if (LookB1(b)==NULL)
        Warning("NumArgB: argument empty.")
#endif
          ;
    return i;
  }
  if (LookB1(b)==NULL)
    if (LookB2(b)==NULL)
      return 0;
    else {
#ifdef SDEBUG
      Warning("NumArgB: First argument is empty.");
#endif
      return 2;
    }
  else
    if (LookB2(b)==NULL)
      return 1;
  return 2;
}

/*----------------------------------------------------------------*/

/* LookArgB
 * Look at the n-th argument of the behaviour b.
 */
BehTyp LookArgB( b , n )
     BehTyp  b; 
     int     n;  
{
  LASSERT(b!=NULL && n>0);
  if ( n==1 ) {
    /*  LASSERT(LookB1(b)!=NULL); ClearBeh complains */
    return LookB1(b);
  }
  if (LookType(b)==AlternativeC) {
    for (;n>1;n--,b=LookB2(b)) {
      LASSERT(b!=NULL);
    }
    LASSERT(LookB1(b)!=NULL);
    return LookB1(b);
  }
  else {
    /*    LASSERT(LookB2(b)!=NULL); */
    return LookB2(b);
  }
}

/*----------------------------------------------------------------*/

/* GetArgB
 * Get the n-th argument of the behaviour b.
 * The n-th argument will be NULL after calling this function.
 */
BehTyp GetArgB( b , n )
     BehTyp   b; 
     int      n;  
{
  BehTyp  a;
  
  LASSERT(b!=NULL&&n>0);
  if (n==1)
    { LASSERT(LookB1(b)!=NULL);/* Argument 1 is empty */
      a = LookB1(b);
      PutB1(b,(BehTyp)NULL);
      DecCopyC(a);
      return a;
    }
  if (LookType(b)==AlternativeC) {
    for (;n>1;n--,b=LookB2(b)) {
      LASSERT(b!=NULL);        /* Argument overflow   */
    }
    LASSERT(LookB1(b)!=NULL);  /* Argument n is empty */
    a = LookB1(b);
    PutB1(b,(BehTyp)NULL);
    DecCopyC(a);
    return a;
  }
  else {
    LASSERT(LookB2(b)!=NULL);  /* Argument 2 is empty */
    a = LookB2(b);
    PutB2(b,(BehTyp)NULL);
    DecCopyC(a);
    return a;
  }
}

/*----------------------------------------------------------------*/

/* PutArgB
 * Put the n-th argument to the behaviour b.
 * The n-th argument must be NULL.
 */
void PutArgB( b , a , n )
     BehTyp  b, a; 
     int      n;  
{
  int i;
  
  LASSERT(b!=NULL);
  
  if ( n==1 ) {
    LASSERT(LookB1(b)==NULL);            /* argument 1 not empty */
    IncCopyC(a);
    PutB1(b,a);
    return;
  }
  
  if (LookType(b)==AlternativeC) {
    for (i=1 ; i<n ; b = LookB2(b) , i++)
      LASSERT(b!=NULL)                   /* argument number too big */
        ;
    LASSERT(LookB1(b)==NULL);            /* argument n empty */
    IncCopyC(a);
    PutB1(b,a);
    return;
  }
  
  LASSERT(LookB2(b)==NULL&&n==2);        /* argument 2 is not empty */
  IncCopyC(a);
  PutB2(b,a);
  
}

/*----------------------------------------------------------------*/

/* LookNameB
 * Name of the behaviour operator b.
 * This descriptor can be an index in the table of gates, processes, etc ...
 */
DescriptorTyp LookNameB( b )
     BehTyp  b;  
{
  return LookName(b);
}

/*----------------------------------------------------------------*/

/* MakeB
 * Make a behaviour operator of type k with a name d . 
 * Its arguments can be added with AddArgB or PutArgB later.
 */
BehTyp MakeB( d, k )
     DescriptorTyp  d;
     CellTypeTyp    k;  
{
  BehTyp  b;
  
  b = NewCell(k);
  PutName(b,d);
  PutCopy(b,0);
  PutB1(b,NULL);
  PutB2(b,NULL);
  PutAttr(b,NULL);
  return b;
}

/*----------------------------------------------------------------*/

/* AddArgB
 * Add an argument to the behaviour b.
 */
void AddArgB( b, a )
     BehTyp  b, a;
{
  BehTyp op;
  
  LASSERT(b!=NULL);
  if ( LookB1(b)==NULL ){
    PutB1(b,a);
    IncCopyC(a);
  }
  else if ( LookType(b)==AlternativeC ) {
    while ( LookB2(b)!=NULL )
      b = LookB2(b);
    if (LookType(a)==AlternativeC)
      op = a;
    else
      { op = NewCell(AlternativeC);
        PutCopy(op,1);
        PutB1(op,a);
        PutB2(op,NULL);
        PutAttr(op,NULL);
        PutName(op,0);
      }
    PutB2(b,op);
    IncCopyC(a);
  }
  else
    if ( LookB2(b)==NULL ) {
      PutB2(b,a);
      IncCopyC(a);
    }
    else
      Error("AddArgB.");
} 

/*----------------------------------------------------------------*/

/* OwnersB
 * Return the number of parents sharing a behaviour b.
 */
int OwnersB( b )
     BehTyp b; 
{
  return LookCopy(b);
}

/*----------------------------------------------------------------*/

/* FreeB
 * Free a behaviour b.
 */
void FreeB( b )
     BehTyp b;      
{
  LASSERT(b!=NULL);
  FreeTree(b);
}

/*----------------------------------------------------------------*/

/* ShareB
 * Increment the copy counter of the behaviour in one unit.
 */
BehTyp  ShareB( b )
     BehTyp b;      
{
  LASSERT(b!=NULL);
  IncCopyC(b);
  return b;
}

/*----------------------------------------------------------------*/

/* UnshareB
 * Decrement the copy counter of a behaviour in one unit.
 */  
BehTyp UnshareB( b )
     BehTyp b;
{
  LASSERT(LookCopy(b)!=0);
  DecCopyC(b);
  return b;
}

/*----------------------------------------------------------------*/

/* SharedB
 * Say if the cell is shared by more than one owners
 */
boolean SharedB( b )
     BehTyp b;
{
  return (LookCopy(b)>1);
}

/*----------------------------------------------------------------*/

/* CopyOperB
 * Copy the operator b and share its arguments and attributes.
 */
BehTyp CopyOperB( b )
     BehTyp b;      
{
  BehTyp    nb;
  PAttrsTyp as;
  PAttrTyp  a;
  int       i,n;
  
  LASSERT(b!=NULL);
  nb = MakeB(LookNameB(b),LookTypeB(b));
  for (as = (PAttrsTyp) b->attrlist;as != NULL;as = Next_list(as)) {
    a = (PAttrTyp)LookInfo_list(as);
    PutA(nb,a);
  }
  n = NumArgB(b);
  for ( i=1; i<=n; i++ ) 
    AddArgB(nb,LookArgB(b,i));
  return nb;
}

/*----------------------------------------------------------------*/

/* GetOperB
 * Subtract a copy of the operator b.
 * The arguments are shared.
 */
BehTyp GetOperB( b )       
     BehTyp b;       
{
  LASSERT(b!=NULL);
  if (OwnersB(b)!=0) 
    return CopyOperB(b);
  return b;
}    

/*----------------------------------------------------------------*/

/* CopyB
 * Copy the cells and shares the attributes of the behaviour b
 */
BehTyp CopyB( b )
     BehTyp b;      
{
  BehTyp    nb,arg;
  PAttrsTyp as;
  PAttrTyp  a;
  int       i,n;
  
  LASSERT(b!=NULL);
  nb = MakeB(LookNameB(b),LookTypeB(b));
  for (as = (PAttrsTyp) b->attrlist;as != NULL;as = Next_list(as)) {
    a = (PAttrTyp)LookInfo_list(as);
    PutA(nb,a);
  }
  if (LookType(b)==PletC && (arg=LookArgB(b,1))!=NULL ) 
    AddArgB(nb,arg);
  else {
    n = NumArgB(b);
    for (i=1;i<=n;i++) 
      AddArgB(nb,CopyB(LookArgB(b,i)));
  }
  return nb;
}

/*----------------------------------------------------------------*/

/* CopyUntilActB
 * Copy the cells and share the attributes of the behaviour b
 * until actions are found.
 */
BehTyp  CopyUntilActB( b )
     BehTyp b;       
{
  BehTyp    nb;
  PAttrsTyp as;
  int       i,n;
  PAttrTyp  a;
  
  LASSERT(b!=NULL);
  nb = MakeB(LookNameB(b),LookTypeB(b));
  for ( as = (PAttrsTyp)b->attrlist; as!=NULL; as = Next_list(as) ) {
    a = (PAttrTyp)LookInfo_list(as);
    PutA(nb,a);
  }
  if ((LookType(b)==PletC) || (LookType(b)==GateC) || (LookType(b)==IC))
    AddArgB(nb,LookArgB(b,1));
  else {
    n = NumArgB(b);
    for ( i=1; i<=n; i++ ) 
      AddArgB( nb, CopyUntilActB(LookArgB(b,i)) );
  }
  return nb;
}

/*----------------------------------------------------------------*/

/* GetB
 * Subtract a copy of the behaviour b. i.e. copy & free old behaviour
 * Cells are copied and attributes are shared.
 */
BehTyp GetB( b )
     BehTyp b;      
{
  BehTyp nb;
  
  LASSERT(b!=NULL);
  nb = CopyB(b);
  FreeB(b);
  return nb;
}    

/*----------------------------------------------------------------*/

/* GetUntilActB
 * Subtract a copy of the behaviour b until actions are found.
 */
BehTyp GetUntilActB( b )       
     BehTyp b;       
{
  BehTyp nb;
  
  LASSERT(b!=NULL);
  nb = CopyUntilActB(b);
  FreeB(b);
  return nb;
}    

/*----------------------------------------------------------------*/

/* UnshareAttrsB
 * Unshare the attributes of a behaviour b until the end of 
 * the b or a shared subbehaviour is found.
 */
void UnshareAttrsB( b )
     BehTyp  b;  
{
  UnshareAttrsOfTree(b);
}

/*----------------------------------------------------------------*/

/* UnshareAttrsUntilActB
 * Take the behaviour b and unshare its attributes until an action is found.
 * b must have been unshared until actions.
 */     
void UnshareAttrsUntilActB( b )
     BehTyp  b; 
{       
  LASSERT(LookCopy(b)==0 || LookCopy(b)==1);

  if (LookCopy(b)<=1) {
    UnshareAS(b);
    if ( (LookType(b)!=IC) && (LookType(b)!=GateC) ) {
      if (b->b1 != NULL)
        UnshareAttrsUntilActB(b->b1);
      if (b->b2 != NULL)
        UnshareAttrsUntilActB(b->b2);
    }
  }
}

/*----------------------------------------------------------------*/

/* DrawB
 * Print the behaviour b in internal format.
 * pstr is the function used to print strings.
 */
void DrawB( b, pstr )
     BehTyp  b;
     void (*pstr)(); 
{
  LASSERT(b!=NULL);
  DrawTree( b, -1, pstr );
}

/*----------------------------------------------------------------*/

/* DB
 * Draw a behaviour using printTarget.
 */
void DB(b)
     BehTyp b;
{
  DrawTree( b, -1, printTarget);
}

/*----------------------------------------------------------------*/

/* DBN
 * Draw a behaviour until depth cells using printTarget.
 */
void DBN(b,depth)
     BehTyp b;
     int    depth;
{
  DrawTree( b, depth, printTarget);
}

/*----------------------------------------------------------------*/

/* GlueB
 * Glue the behaviour b2 into b1.
 * After glueing b2 occupies the memory of b1, so that all pointers
 * to b1 point now to b2, and b1 does not exist any more.
 */
void GlueB( b1, b2 )
     BehTyp b1,b2;
{
  LASSERT( LookB1(b2)!=b1 && LookB2(b2)!=b1 );
  if (LookTypeB(b2)==AlternativeC) 
    b2 = GetOperB(b2);
  GlueCell(b1,b2);
}

/*----------------------------------------------------------------*/

/* GlueArgB
 * Glue the argument n of b into b.
 */
void GlueArgB( b, n )
     BehTyp b; 
     int    n;
{
  LASSERT(b!=NULL);
  LASSERT(LookArgB(b,n)!=NULL);
  GlueB(b,LookArgB(b,n));
}

/*----------------------------------------------------------------*/

/* FreeArgB
 * Free the argument n of the behaviour b.
 */
void FreeArgB( b, n )
     BehTyp b; 
     int    n; 
{ 
  int    i;
  BehTyp a,a1;
  
  LASSERT(b!=NULL);
  LASSERT(n<=NumArgB(b));
  if (LookType(b)==AlternativeC) {
    a = b;
    if (n==1) 
      GlueCellB2(a);
    else {
      for (i=2;i<n;i++)
        a = LookB2(a);
      a1 = LookB2(a);
      if (LookB2(a1)==NULL) {
        PutCopy(a1,0);
        FreeB(a1);
        PutB2(a,(BehTyp)NULL);
      }
      else 
        GlueCellB2(a1);
    }
    if (LookB2(b)==NULL)
      GlueB(b,LookArgB(b,1));
  }
  else {
    LASSERT(n < 3);
    if (n==1)
      { LASSERT(LookB1(b)!=NULL);
        /* FreeArgB: argument 1 is empty. */
        FreeB(GetArgB(b,1));
      }
    else {
      LASSERT(LookB2(b)!=NULL);
      /* FreeArgB: argument 2 is empty. */
      FreeB(GetArgB(b,2));
    }
  }
}

/*----------------------------------------------------------------*/

/* SubtractChoiceB
 * Takes out the n-th operand from the behaviour choice b.
 * The alternativeC the operand hangs from is removed.
 */
BehTyp SubtractChoiceB( b, n )
     BehTyp b; 
     int    n; 
{ 
  int    i;
  BehTyp a,a1,out;
  
  LASSERT(b!=NULL);
  LASSERT(n<=NumArgB(b));
  LASSERT(LookType(b)==AlternativeC);
  a = b;
  if ( n==1 ){
    out = LookB1(a);
    DecCopyC(out);
    PutB1(a,(BehTyp)NULL);
    GlueCellB2(a);
  }
  else {
    for (i=2;i<n;i++)
      a = LookB2(a);
    a1 = LookB2(a);
    if (LookB2(a1)==NULL) {
      GlueCellB1(a1);
      PutB2(a,(BehTyp)NULL);
      DecCopyC(a1);
      out = a1;
    }
    else {
      out = LookB1(a1);
      PutB1(a1,(BehTyp)NULL);
      DecCopyC(out);
      GlueCellB2(a1);
    }
  }
  if (LookB2(b)==NULL)
    GlueCellB1(b);
  return out;
}

/*----------------------------------------------------------------*/

/* ApplyProcChoiceB
 * Apply a procedure to all the branches of a behaviour choice operator.
 */
void ApplyProcChoiceB( b, p )
     BehTyp b;
     void (*p)();
{
  LASSERT(LookTypeB(b)==AlternativeC);
  while ( b!=NULL ) {
    p(LookB1(b));
    b = LookB2(b);
  }
}

/*----------------------------------------------------------------*/

/* ApplyFuncChoiceB
 * Apply a function to all the branches of a behaviour choice operator
 */
void ApplyFuncChoiceB( b, f )
     BehTyp b, (*f)();
{
  LASSERT(LookTypeB(b)==AlternativeC);
  while ( b!=NULL ) {
    PutB1( b, f(LookB1(b)) );
    b = LookB2(b);
  }
}

/*----------------------------------------------------------------*/

/*
 *  list to mark cells with copy greater than one.
 */
static ListTyp visitedCells;

static void ChangeCopySign( b )
     BehTyp b;
{
  LASSERT(b!=NULL);
  PutCopy(b,-LookCopy(b));
}

/*----------------------------------------------------------------*/

/* Begin_VisitB
 * Start a visit to a behaviour .
 */
void Begin_VisitB()
{
  visitedCells  = Create_list();
}

/*----------------------------------------------------------------*/

/* VisitedB
 * Declare a cell as "visited".
 * If it had already been visited return TRUE else FALSE.
 * Those cells with (|copy|>1) are stored and their copy fields get
 * changed of signus.
 * Therefore End_VisitB should be called to undo changes on the behaviour.
 */
boolean VisitedB( b )
     BehTyp b;
{
  if ( LookCopy(b)<0 ) {
    LASSERT(In_list((DataListTyp)b,visitedCells,EqInt));
    return TRUE;
  }
  if ( LookCopy(b)>1 ) {
    LASSERT(!In_list((DataListTyp)b,visitedCells,EqInt));
    ChangeCopySign( b );
    visitedCells = Insert_list((DataListTyp)b,visitedCells);
  }
  return FALSE;
}

/*----------------------------------------------------------------*/

/* UnVisitB
 * Declare a cell as "not visited".
 * Set its copy signus to positive.
 */
void UnVisitB( b )
     BehTyp b;
{
  ListTyp n;
  
  if ( LookCopy(b)<0 ) {
    ChangeCopySign( b );
    n = LookFor_list( (DataListTyp)b, visitedCells, EqInt );
    LASSERT( n!=NULL );
    visitedCells = DeleteNode_list(n,visitedCells);
  }
}

/*----------------------------------------------------------------*/

/* End_VisitB
 * End a visit to a behaviour .
 * Release track of visited cells and restore altered copy fields.
 */
void End_VisitB()
{
  Free_list( visitedCells, ChangeCopySign );
  visitedCells = Create_list();
}

/*----------------------------------------------------------------*/








