/***********************************
  (C) Copyright 1992-1993; dit/upm
  Distributed under the conditions stated in the
  TOPO General Public License (see file LICENSE)
  ***********************************/

/***********************************
  
  David Larrabeiti Lopez
  
  Feb 15, 1991
  
  Management of one-immediate behaviours IB.
  
  Mxk
  b= ( SUMk( CHk Gk gk;Bk ) )
  1
  where:
  
  gk:= visible-action | i-action | exit        (Mxk>1)
  gk:= visible-action | i-action | exit | stop (Mxk=1)
  
  
  Let us define UB (unitary behaviour) as a chain of cells
  with one operand utmost.
  
  Example: any branch of a one-immediate behaviour down to
  its action : Chi Gi gi
  
  Ch1
  Ch2
  Gd1
  action
  
  COMPILATION OPTIONS: The behaviour of this module can be modified
  by the following compilation flags:
  
  (none)
  
  
  ************************************/

/* LINTLIBRARY */


#include "limisc.h"
#include "licell.h"
#include "badefca.h"
#include "eximmed.h"


/******************************************************************
 *                                                                *
 *              Unitary Behaviour (UB) functions                  *
 *                                                                *
 *      UB is supposed to be a behaviour composed of              *
 *      one-operand cells                                         *
 *                                                                *
 ******************************************************************/

/* LookLastUB
 * Last cell in a UB. ( NumArgB( LookLastUB(b) )==0 )
 */
BehTyp LookLastUB(b)
     BehTyp b;
{
  BehTyp b1;
  
  LASSERT (b!=NULL);
  
  while ( (b1=LookArgB(b,1))!=NULL )
    b = b1;
  
  return b;
  
}

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

/* LookActionUB
 * First Action found in a UB .
 *  Action := gate | i | stop | exit | termination
 */
BehTyp LookActionUB( b )
     BehTyp b;
{
  
  LASSERT( b!=NULL );
  for (;;) {
    switch(LookTypeB(b))
      {
      case GateC:
      case StopC: 
      case ExitC:
      case IC:
      case TerminationC:
	return b;
      default:
	b = LookArgB( b, 1 );
	LASSERT(b!=NULL);
      }
  }
}

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

/* LookPreActionUB
 * Cell just before the Action in a UB .
 * ( Action:= [ gate | i | stop | exit ] ).
 * If there is not such a cell returns NULL.
 */
BehTyp LookPreActionUB(b)
     BehTyp b;
{
  BehTyp bck;
  CellTypeTyp  type;
  
  LASSERT( b!=NULL );
  bck  = NULL;
  type = LookTypeB(b);
  while ( type!=IC && type!=StopC && type!=ExitC && type!=GateC
	 && type!=TerminationC ) {
    bck  = b;
    b    = LookArgB( b, 1 );
    type = LookTypeB(b);
  }
  return bck;
}

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

/* LookPreLastUB
 * Cell just before the last cell in a UB .
 * If there is not such a cell returns NULL.
 */
BehTyp LookPreLastUB(b)
     BehTyp b;
{
  BehTyp bck;
  
  LASSERT( b!=NULL );
  
  bck = NULL;
  while ( LookArgB(b,1)!=NULL ) {
    bck = b;
    b   = LookArgB( b, 1 );
  }
  return bck;
  
}

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

/* SearchCellUntilActUB
 * Returns the first cell of type t that is found.
 * NULL if either an action or the end of the UB is found
 * without having found the cell.
 */
BehTyp SearchCellUntilActUB(b,t)
     BehTyp      b;
     CellTypeTyp t;
{
  CellTypeTyp type;
  
  LASSERT( b!=NULL );
  type = LookTypeB(b);
  while ( b!=NULL && type!=IC && type!=StopC && type!=ExitC && type!=GateC &&
	 type!=TerminationC && type!=t ) {
    b    = LookArgB( b, 1 );
    if ( b!=NULL )
      type = LookTypeB( b );
  }
  return ((type==t)?b:NULL); 
}

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

/* CopyEqualCellsUB
 * Returns a copy of the piece of UB whose cell types are equal to that given.
 * Example:
 *           Ch1<-     case b=Ch1:
 *           Ch2                   return a copy of Ch1
 *           Gd1<-                                  Ch2
 *           Gd2       case b=Gd1:
 *           Gd3                   return a copy of Gd1
 *           gate                                   Gd2
 *            :                                     Gd3
 *            :
 *            :
 */
BehTyp CopyEqualCellsUB( b )
     BehTyp b;
{
  BehTyp bck,fwd,out;
  CellTypeTyp type;
  
  LASSERT(b!=NULL);
  
  type = LookTypeB( b );
  out  = NULL;
  bck  = NULL;
  fwd  = b;
  while ( fwd!=NULL && LookTypeB(fwd)==type ) {
    bck = fwd;
    fwd = LookArgB( fwd, 1 );
  }
  if ( fwd!=NULL ){
    fwd = GetArgB( bck, 1 );
    out = CopyB(b);
    PutArgB( bck, fwd, 1 );
  }
  else
    out = CopyB(b);
  
  return out;
  
}

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

/* ConcatUB
 * Joins Two UBs . b2 becomes argument of LookLastUB(b1).
 * Any of them can be NULL.
 */
BehTyp ConcatUB(b1,b2)
     BehTyp b1,b2;
{
  if ( b1!=NULL && b2!=NULL )
    PutArgB( LookLastUB(b1), b2, 1 );
  
  return ((b1==NULL)? b2 : b1);  
}

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

/* ExtractUB
 * Picks up (copies) the cells of type t from b1 and b2 and concatenates
 * them together through ConcatUB.
 * Example:
 *           b1->Ch1     b2->Ch3  ExtractUB(b1, b2, GuardC)== copy of Gd1
 *               Ch2         Gd3                                      Gd2
 *               Gd1         Gd4                                      Gd3
 *               Gd2         Gd5                                      Gd4
 *               action      stop                                     Gd5
 *                : 
 *                :               ExtractUB(b1, b2,ChoiceC)== copy of Ch1
 *                                                                    Ch2
 *                                                                    Ch3
 */
BehTyp ExtractUB( b1, b2, t )
     BehTyp b1,b2;
     CellTypeTyp t;
{
  if ( b1!=NULL ){
    b1 = SearchCellUntilActUB( b1, t );
    if ( b1!=NULL )
      b1 = CopyEqualCellsUB( b1 );
  }
  if ( b2!=NULL ){
    b2 = SearchCellUntilActUB( b2, t );
    if ( b2!=NULL )
      b2 =CopyEqualCellsUB( b2 );
  }
  return ConcatUB( b1, b2 );
}

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

/* CountUB
 * Number of cells of a UB b
 */
int CountUB( b )
     BehTyp b;
{
  int i;
  
  for ( i=0; b!=NULL; b = LookArgB(b,1), ++i )
    ;
  return i;
}

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

/* RemoveCellUB
 * Remove cell victim from UB b. 
 */
BehTyp RemoveCellUB( victim, b )
     BehTyp victim,b;
{
  BehTyp top;
  
  LASSERT( victim!=NULL && b!=NULL );
  if ( victim == b ) {
    top = GetArgB(b,1);
    FreeB(victim);
    return top;
  }
  top  = b;
  while ( LookArgB( b, 1 )!=victim ) {
    b  = LookArgB( b, 1 );
  }
  PutArgB( b, GetArgB(GetArgB(b,1),1), 1 );
  FreeB(victim);
  return top;
}


/******************************************************************
 *                                                                                                *
 *              One-immediate Behaviour (IB) functions                    *
 *                                                                *
 *      IB is supposed to be a choice of UBs                      *
 *                                                                                                *
 *******************************************************************/

/* AppendUB
 * Appends argument b to a one-immediate behaviour ib.
 * ib or b can be NULL.
 * if ib has one operand then ib and b get joined by an alternative
 */
BehTyp AppendUB( ib, b )
     BehTyp ib,b;
{
  BehTyp aux;
  int    n,i;
  
  if ( ib==NULL )
    return b;
  else {
    if ( b==NULL )
      return ib;
    if ( LookTypeB(ib)!=AlternativeC ) {
      aux  = ib;
      ib = MakeB( 0, AlternativeC );
      AddArgB( ib, aux );
    }
    if ( LookTypeB(b)==AlternativeC ) {
      n = NumArgB(b);
      for (i=1 ; i<=n ; i++) {
	AddArgB(ib,LookArgB(b,i));
      }
      FreeB(b);
    }
    else
      AddArgB( ib, b );
    return ib;
  }
}

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

/* SubtractUB
 * Gets the n-th argument of a one-immediate behaviour *ib.
 * if *ib has only one operand and n=1 then *ib becomes NULL
 * SubtractUB differs from GetArgIB in the treatment of alternative cells:
 * SubtractUB removes the alternative cell where the n-th operand is placed.
 */
BehTyp SubtractUB( ib, n )
     BehTyp *ib;
     int     n;
{
  BehTyp out;
  
  LASSERT(ib!=NULL);
  if ( LookTypeB(*ib)==AlternativeC ){
    out = SubtractChoiceB( *ib, n );
  }
  else {
    LASSERT(n==1);
    out = *ib;
    *ib = NULL;
  }
  return out;
}

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

/* GetArgIB
 * Gets argument i from a one-immediate behaviour b for modification purposes.
 * This alternative will be reinserted afterwards.
 */
BehTyp GetArgIB( b, i )
     BehTyp b;
     int i;
{
  if ( LookTypeB(b)==AlternativeC )
    return GetArgB( b, i );
  else
    return b;
}

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

/* LookArgIB
 * Looks at argument i of a one-immediate behaviour b.
 */
BehTyp LookArgIB( b, i )
     BehTyp b;
     int i;
{
  if ( LookTypeB(b)==AlternativeC )
    return LookArgB( b, i );
  else
    return b;
}

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

/* NumArgIB
 * Returns the number of arguments in a one-immediate behaviour.
 */
int NumArgIB( b )
     BehTyp b;
{
  return (LookTypeB(b)==AlternativeC ? NumArgB(b):1);
}

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

/* ApplyFuncIB
 * Applies function f to every UB of a one-immediate behaviour b.
 */
BehTyp ApplyFuncIB( b, f )
     BehTyp b;
     BehTyp (*f)();
{
  if ( NumArgB(b) <= 1 )
    return f(b);
  else {
    ApplyFuncChoiceB( b, f );
    return b;
  }
}

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

/* LookActionArgIB
 * Look at the action of the n-th branch of a one-immediate behaviour b.
 */
BehTyp LookActionArgIB( b, n )
     BehTyp b;
     int n;
{  
  if ( LookTypeB(b)==AlternativeC )
    return LookActionUB( LookArgB(b,n) );
  else
    return LookActionUB( b );
}

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

/* ExtractIB
 * return the alternatives whose action is of type t
 * *b will contain the rest
 * ExtractIB deals with NULL values.
 */
BehTyp ExtractIB( b, t )
     BehTyp     *b;
     CellTypeTyp t;
{
  int    i,n;
  BehTyp arg,out;
  
  out = NULL;
  n   = NumArgIB(*b);
  if ( n==1 ){
    if (LookTypeB(LookActionUB(*b))==t){
      out = *b;
      *b  = NULL;
    }
  }
  else 
    for ( i=1; i<=n; i++ ){
      arg  = LookArgIB(*b,i);
      if ( LookTypeB(LookActionUB(arg))==t ){
	arg = SubtractUB( b, i );
	out = AppendUB( out, arg );
	i--;
	n--;
      }
    }
  
  return out;
}

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

