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

/***********************************
  
  David Larrabeiti Lopez
  
  4 February 1993
  
  Pre-processing for the Interleaved Expansion.
  
  PP(B) = B =    Sumi ChiGi gi;Bi
  []
  Sumi ChiGi(B1i[>B2i)
  []            .    
  Sumi ChiGi(B1i>>B2i)
  []                                      .       .
  Sumi relabel rfl in hide Ah in ChiGi(B1i|[A]|B2i)
  
  
  COMPILATION OPTIONS: The behaviour of this module can be modified
  by the following compilation flags:
  
  (none)
  
  ************************************/


#include "limisc.h"
#include "lilists.h"
#include "badefca.h"
#include "balotosf.h"
#include "basynset.h"
#include "eximmed.h"
#include "expre_br.h"


/******************************************************************
 *                                                                *
 *         One level expansion function                           *
 *                                                                *
 *******************************************************************/


/* ExpanD
 * One level expansion function.
 */
static BehTyp ExpanD( b )
     BehTyp b;
{
  BehTyp res;
  int    i_rm_depth;
  
  /*
   * expansion_flags = the current ones
   *
   */
  b               = ShareB(b);
  i_rm_depth      = 0;
  res             = Pre_Branch( b, &i_rm_depth );
  b               = UnshareB(b);
  
  return res;
}


/******************************************************************
 *                                                                *
 *                  Iexp Pre-Processing                           *
 *                                                                *
 *******************************************************************/


/* AllGatesSync
 * Say if all the gates offered by a One-immediate behaviour belong to a
 * parallel.
 */
static boolean AllGatesSync( ib, par )
     BehTyp ib, par;
{
  int             i;
  PSyncGateSetTyp egs;
  
  egs = Parallel_to_SS( par );
  for ( i = NumArgIB(ib); i>0; i-- ){
    if (!GateInSS( LookActionArgIB(ib,i), egs ) ){
      FreeSS(egs);
      return FALSE;
    }
  }
  FreeSS(egs);
  return TRUE;
}

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

static boolean IsCGGate( b )
     BehTyp b;
{
  boolean guard=FALSE;
  
  while (b!=NULL)
    switch (LookTypeB(b))
      {
      case GateC:
      case IC:
      case ExitC:
        return TRUE;
      case ChoiceC:
        if ( guard )
          return FALSE; 
        b = LookArgB(b,1);
        break;
      case GuardC:
        guard = TRUE;
        b     = LookArgB(b,1);
        break;
      default:
        return FALSE;
      }
  return FALSE;
}

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

/* IsGuardedChoice
 * Say if a behaviour is a guarded choice.
 */
static boolean IsGuardedChoice( b )
     BehTyp b;
{
  int i;
  
  if ( LookTypeB(b)==AlternativeC ) {
    for ( i = NumArgIB(b); i>1; i-- )
      if ( !IsCGGate( LookArgB(b,i) ) )
        return FALSE;
    b = LookArgB(b,1);
  }
  return IsCGGate( b );
}
/*----------------------------------------------------------------*/

/* ExtractGCGate
 * in  : ( Sumi ChiGigi;Bi ) [] Sumj Bj  
 * out :
 *  *rest = Sumj Bj 
 *  return ( Sumi ChiGigi;Bi )
 */
static BehTyp ExtractGCGate( b, restPt )
     BehTyp b, *restPt;
{
  int i,n;
  BehTyp guardedChoice,bi;
  
  guardedChoice = NULL;
  *restPt       = NULL;
  if ( IsCGGate(b) ) {
    return b;
  }
  if ( LookTypeB(b)==AlternativeC ) {
    for ( n = NumArgIB(b), i=1; i<=n; i++ ) {
      if ( IsCGGate( bi = GetArgIB(b,i) ) )
        guardedChoice = AppendUB( guardedChoice, bi );
      else
        *restPt = AppendUB( *restPt, bi );
    }
    if ( n>1 )
      FreeB(b);
  }
  else
    *restPt = b;
  return guardedChoice;
}

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

/* Ap
 * Iexp_Pre_Proc of the parallel operator b1|A|b2 . where b1 and b2 have been
 * Iexp_Pre_Processed.
 */
static BehTyp Ap( b )
     BehTyp b;
{
  BehTyp b1,b2,rest,result,guardedChoice,par;
  
  LASSERT(LookTypeB(b)==ParallelC);
  
  b1 = GetArgB(b,1);
  b2 = GetArgB(b,2);
  
  /*
     if ( LookTypeB(b1)==StopC && LookTypeB(b2)==StopC ){
     AddArgB(b,b1);
     AddArgB(b,b2);
     return b;
     }
     */
  
  if ( LookTypeB(b1)==StopC && LookTypeB(b2)==StopC ){
    FreeB(b1);
    FreeB(b2);
    FreeB(b);
    return MakeB(0,StopC);
  }
  
  if ( (IsGuardedChoice(b1) && AllGatesSync(b1,b)) )
    {
      /* All gates of operand one synchronize */
      
      result        = NULL;
      guardedChoice = ExtractGCGate( b2, &rest );
      
      if ( rest!=NULL ) {
        par = CopyOperB(b);
        AddArgB( par, b1 );
        AddArgB( par, rest );
        result = AppendUB( result, par );
      }
      
      if ( guardedChoice!=NULL ) {
        par = CopyOperB(b);
        AddArgB( par, b1 );
        AddArgB( par, guardedChoice );
        GlueB( par, ExpanD( ShareB(par) ) );
        par = UnshareB(par);
      }
      else {
        FreeB(b);
        return result;
      }
      
      /*
	 for ( n = NumArgIB(par), i=1 ; i<=n; i++ ) {
	 bi = LookActionArgIB(par,i);
	 PutArgB( bi, Iexp_Pre_Proc(GetArgB(bi,1)), 1 );
	 }
	 */
      
      result = AppendUB( result, par );
      
      FreeB(b);
      return result;
      
    }
  else
    if ( (IsGuardedChoice(b2) && AllGatesSync(b2,b)) )
      {
	/* All gates of operand two synchronize */
	
	result        = NULL;
	guardedChoice = ExtractGCGate( b1, &rest );
	
	if ( rest!=NULL ) {
	  par = CopyOperB(b);
	  AddArgB( par, rest );
	  AddArgB( par, b2 );
	  result = AppendUB( result, par );
	}
	
	if ( guardedChoice!=NULL ) {
	  par = CopyOperB(b);
	  AddArgB( par, guardedChoice );
	  AddArgB( par, b2 );
	  GlueB( par, ExpanD( par ) );
	}
	else {
	  FreeB(b);
	  return result;
	}
	
	/*      
	   for ( n = NumArgIB(par), i=1 ; i<=n; i++ ) {
	   bi = LookActionArgIB(par,i);
	   PutArgB( bi, Iexp_Pre_Proc(GetArgB(bi,1)), 1 );
	   }
	   */
	
	result = AppendUB( result, par );
	
	FreeB(b);
	return result;
	
      }
  
    else {
      AddArgB(b,b1);
      AddArgB(b,b2);
      return b;
    }
}

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

/* EnabAp
 * Post Iexp_Pre_Proc of the enabling operator b1>>b2 . where b1 is
 * Iexp_Pre_Processed.
 */
static BehTyp EnabAp( b )
     BehTyp b;
{
  BehTyp b1,b2,rest,result,guardedChoice,enab;
  
  LASSERT(LookTypeB(b)==EnablingC);
  
  result = NULL;
  b1     = GetArgB(b,1);
  b2     = GetArgB(b,2);
  
  guardedChoice = ExtractGCGate( b1, &rest );
  
  if ( rest!=NULL ) {
    enab = CopyOperB(b);
    AddArgB( enab, rest );
    AddArgB( enab, b2 );
    result = AppendUB( result, enab );
  }
  if ( guardedChoice!=NULL ) {
    enab = CopyOperB(b);
    AddArgB( enab, guardedChoice );
    AddArgB( enab, b2 );
    GlueB( enab, ExpanD( enab ) );
  }
  else {
    FreeB(b);
    return result;
  }
  result = AppendUB( result, enab );
  FreeB(b);
  return result;
}

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

/* Iexp_Pre_Proc
 * Pre-processing previous to the application of the iexpansion at every
 * sub-state of the exploration.
 * b must be got-until-actions.
 * return the canonical representation of the state.
 */
BehTyp Iexp_Pre_Proc( b )
     BehTyp b;
{
  int     i,n,cero=0;
  boolean cont;
  
  cont = TRUE;
  while (cont) {
    switch (LookTypeB(b)) 
      {
        
	/*
	 * IPP( stop ) = stop
	 *
	 */
      case TerminationC: /**/
      case StopC: 
        cont = FALSE;
        break;
        
        
	/*
	 * IPP( g[BE];B' ) = g[BE];B'            if rw(BE)!=false
	 *                = stop                otherwise
	 */
      case GateC:
        SolvePredicateBeh( b );
        cont = FALSE;
        break;
        
      case IC:
      case ExitC:
        cont = FALSE;
        break;
        
        
	/*
	 * IPP( Sumi Bi )  = PBS( PBA(Sumi IPP(Bi)) )
	 *
	 */
      case AlternativeC:
        n = NumArgB( b );
        for ( i=1; i<=n; i++ ) 
          PutArgB( b, Iexp_Pre_Proc(GetArgB(b,i)), i );
        b    = Pre_Branch_Alt( b );
        b    = Pre_Branch_Stop( b ); 
        cont = FALSE;
        break;
	
	
	/*
	 * IPP( choice vdl[]B ) = PBC( choice vdl[]IPP(B) )
	 *
	 */
      case ChoiceC:
        PutArgB( b, Iexp_Pre_Proc(GetArgB(b,1)), 1 );
        b    = Distribute_Choice( b );
        cont = FALSE;
        break;
        
	
	/*
	 * IPP( [BE]->B ) = PBG( [BE]->IPP(B) )   if rw(BE)!=false
	 *               = stop                 otherwise
	 */
      case GuardC:
        if ( LookPredicate(b) != 'i' )
          SolvePredicateBeh( b );
        else {
          PutArgB( b, Iexp_Pre_Proc(GetArgB(b,1)), 1 );
          b    = Distribute_Guard( b );
          cont = FALSE;
        }
        break;
        
	/*
	 * IPP( CS ) = CS
	 *
	 */
      case ContSetC:
        cont = FALSE;
        break;
	
	/*
	 * IPP( B1|A|B2 ) = Ap( IPP(B1)|A|IPP(B2) )
	 *
	 */
      case ParallelC:
        PutArgB( b, Iexp_Pre_Proc( GetArgB(b,1) ), 1 );
        PutArgB( b, Iexp_Pre_Proc( GetArgB(b,2) ), 2 );
        /* b    = Ap( b ); */
        cont = FALSE;
        break;
	
	/*
	 * IPP( B1>>accept vdl in B2 ) = IPP(B1) >> accept vdl in B2
	 *
	 */
      case EnablingC:
        PutArgB( b, Iexp_Pre_Proc( GetArgB(b,1) ), 1 );
        b    = EnabAp( b );
        cont = FALSE;
        break;
	
	/*
	 * IPP( B1[>B2 ) = IPP(B1) [> IPP(B2)
	 *
	 */
      case DisablingC:
        PutArgB( b, Iexp_Pre_Proc( GetArgB(b,1) ), 1 );
        PutArgB( b, Iexp_Pre_Proc( GetArgB(b,2) ), 2 );
        cont = FALSE;
        break;
	
	/*
	 * IPP( hide Ah in B )         = HP( hide Ah in IPP(B) )
	 *
	 */
      case HidingC:
        b    = Iexp_Hide_Proc( b );
        if ( LookTypeB(b)==HidingC )
          cont = FALSE;
        else
          b = Iexp_Pre_Proc( b );
        break;
	
	/*
	 * IPP( relabelling rfl in B ) = RP( relabelling rfl in IPP(B) )
	 *
	 */
      case RelabellingC:
        b = Iexp_Relabel_Proc( b );
        if ( LookTypeB(b)==RelabellingC )
          cont = FALSE;
        else
          b = Iexp_Pre_Proc( b );
        break;
	
	/*
	 * IPP( pi[gl](el) )           = IPP( I_P(pi[gl](el)) )
	 * IPP( let val in B )         = IPP( L_P(let val in B) )
	 * IPP( plet val in B )        = IPP( PL_P(plet val in B) )
	 * IPP( choice gdl[]B )        = IPP( SE_P(choice gdl[]B) )
	 * IPP( par gdl |A| B )        = IPP( PE_P(par gdl |A| B) )
	 *
	 */
      case ProcessInstC:
      case LetC:
      case PletC:
      case GateChoiceC:
      case ParC:
        b = Pre_Processing( b, &cero );
        break;
        
      default:           
        Error("Iexp_Pre_Proc : unexpected cell.");
      }
  }
  return b;
  
}




/******************************************************************
 *                                                                *
 *                  Iexp_Relabel_Processing                       *
 *                                                                *
 *******************************************************************/

/* R_P2
 * Application of a rfl to a Iexp_Pre_Processed behaviour
 */
static BehTyp R_E_IPP( b, rfla )
     BehTyp b;
     PAttrTyp rfla;
{
  int              NumArg,i;
  DescriptorTyp    name;
  BehTyp           bi,out,rf,relab;
  RelabFuncListTyp rfl2;
  PAttrTyp         rfla2;
  
  switch( LookTypeB(b) )
    {
    case GateC:
      name = ActualRFL( (RelabFuncListTyp)LookAInfo(rfla), LookNameB(b) );
      if ( name!=(DescriptorTyp)NULL )
        PutNameB( b, name );
      
      if ( LookTypeB(LookArgB(b,1))==HidingC ) {
        rfl2 = CopyRFL((RelabFuncListTyp)LookAInfo( rfla ));
        rfl2 = SimplifyRFL( rfl2,
                           (GateSetTyp)LookAInfo(LookA(LookArgB(b,1),GSA)) );
        if ( rfl2==NULL ) {
          out = b;
          break;
        }
        else
          FreeRFL( rfl2 );  /**/ /* temporary. could be passed to R_E_IPP */
      }
      
      rf = MakeB( 0, RelabellingC );
      PutA( rf, rfla );                                 /* shared attr */
      bi = GetArgB( b, 1 );
      PutArgB( b, rf, 1 );
      PutArgB( rf, bi, 1 );
      out = b;
      break;
      
    case RelabellingC:
      UnshareA( b, RFLA );
      rfla2 = LookA( b, RFLA );
      rfl2  = (RelabFuncListTyp)GetAInfo( rfla2 );
      rfl2  = JunctionRFL( CopyRFL((RelabFuncListTyp)LookAInfo(rfla)), rfl2 );
      if ( rfl2==NULL ){
        out = GetArgB(b,1);
        FreeB(b);
      }
      else {
        PutAInfo( rfla2, (AttrValueTyp)rfl2 );
        out = b; /**/
      }
      break;
      
    case EnablingC:     /* rfl in B1>>B2 = R_E_IPP(rfl in B1)>>(rfl in B2) */
      bi = GetArgB( b, 1 );
      PutArgB( b, R_E_IPP(bi,rfla), 1 );
      bi = GetArgB( b, 2 );
      rf = MakeB( 0, RelabellingC );
      PutA( rf, rfla );                                 /* shared attr */
      PutArgB( b, rf, 2 );
      PutArgB( rf, bi, 1 );
      out = b;
      break;
      
    case DisablingC:
    case AlternativeC:
      NumArg = NumArgB( b );
      for ( i=1; i<=NumArg; i++ ) {
        bi = GetArgB( b, i );
        PutArgB( b, R_E_IPP(bi,rfla), i );
      }
      out = b;
      break;
      
    case GuardC:
      bi = GetArgB( b, 1 );
      PutArgB( b, R_E_IPP(bi,rfla), 1 );
      out = b;
      break;
      
    case ChoiceC:
      bi = GetArgB( b, 1 );
      PutArgB( b, R_E_IPP(bi,rfla), 1 );
      out = b;
      break;
      
    case StopC:
    case ExitC:
      out = b;
      break;
      
    case IC:
      if ( LookTypeB(LookArgB(b,1))==HidingC ) {
        rfl2 = CopyRFL((RelabFuncListTyp)LookAInfo( rfla ));
        rfl2 = SimplifyRFL( rfl2,
                           (GateSetTyp)LookAInfo(LookA(LookArgB(b,1),GSA)) );
        if ( rfl2==NULL ) {
          out = b;
          break;
        }
        else
          FreeRFL( rfl2 );  /**/ /* temporary. could be passed to R_E_IPP */
      }
      rf = MakeB( 0, RelabellingC );
      PutA( rf, rfla );
      bi= GetArgB( b, 1 );
      PutArgB( b, rf, 1 );
      PutArgB( rf, bi, 1 );
      out = b;
      break;
      
      
    case HidingC:
    case ParallelC:
      relab = MakeB( 0, RelabellingC );
      PutA( relab, rfla );
      PutArgB( relab, b, 1 );
      out = relab;
      break;
      
    case ContSetC:
      out = b;
      break;
      
    default:
      Error("Iexp_Relabel_Proc : unexpected cell type");
      break;
    }
  
  return out;
}


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

/*
 * Application of a rfl to any behaviour
 */
static BehTyp R_E( b, rfla )
     BehTyp b;
     PAttrTyp rfla;
{
  int              n,i,cero=0;
  BehTyp           bi,out,rf;
  RelabFuncListTyp rfl2;
  PAttrTyp         rfla2;
  
  switch( LookTypeB(b) )
    {
    case GuardC:
    case ChoiceC:
    case AlternativeC:
    case DisablingC:
      for ( n=NumArgB(b),i=1; i<=n; i++ ) {
        bi = GetArgB( b, i );
        rf = MakeB( 0, RelabellingC );
        PutA( rf, rfla );                                 /* shared attr */
        PutArgB( b, rf, i );
        PutArgB( rf, bi, 1 );
      }
      out = b;
      break;
      
    case StopC:
    case ExitC:
      out = b;
      break;
      
    case IC:
      out = R_E_IPP( b, rfla );
      break;
      
    case GateC:
      out = R_E_IPP( Iexp_Pre_Proc( b ), rfla );    /* solve predicate */
      break;
      
    case HidingC:
      b = Iexp_Hide_Proc( b );
      if ( LookTypeB(b)==HidingC )
        out = R_E_IPP( b, rfla );
      else
        out = R_E( b, rfla );
      break;
      
    case RelabellingC:
      UnshareA( b, RFLA );
      rfla2 = LookA( b, RFLA );
      rfl2  = (RelabFuncListTyp)GetAInfo( rfla2 );
      rfl2  = JunctionRFL( CopyRFL((RelabFuncListTyp)LookAInfo(rfla)), rfl2 );
      if ( rfl2==NULL ){
        out = GetArgB(b,1);
        FreeB(b);
      }
      else {
        PutAInfo( rfla2, (AttrValueTyp)rfl2 );
        out = Iexp_Relabel_Proc( b );
      }
      break;
      
    case EnablingC:
    case ParallelC:
      out = R_E_IPP( Iexp_Pre_Proc(b), rfla );
      break;
      
    case ContSetC:
      out = b;
      break;
      
      
    case ProcessInstC:
    case LetC:
    case PletC:
    case ParC:
    case GateChoiceC:
      out = R_E( Pre_Processing( b, &cero ),rfla ); 
      break;
      
    default:
      Error("Iexp_Relabel_Proc : unexpected cell type");
      break;
    }
  
  return out;
}


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

/* Iexp_Relabel_Proc
 * Processing of the Relabel operator relab.
 *
 *     relab = relab rfl in b
 *
 */
BehTyp Iexp_Relabel_Proc( relab )
     BehTyp relab;
{
  BehTyp   b, out;
  PAttrTyp rfla;
  
  LASSERT ( LookTypeB(relab)==RelabellingC );
  
  rfla = LookA( relab, RFLA );
  b    = GetArgB( relab, 1 );
  out  = R_E( b, rfla );
  LASSERT(LookCopy(relab)==0);
  FreeB( relab );
  return out;
}


/******************************************************************
 *                                                                *
 *                  Iexp_Hide_Processing                          *
 *                                                                *
 *******************************************************************/


static BehTyp MkChoice( ol )
     OfferListTyp ol;
{
  BehTyp choice;
  ExprListTyp el;
  
  el = Create_list();
  for ( ; ol!=NULL; ol=MvNextOffer(ol) )
    if ( LookKindOffer(ol)==QUESTION )
      el = AddEL( CopyE(LookExprOffer(ol)), el );  /*mse*/
  
  choice = MakeB( 0, ChoiceC );
  PutA( choice, MakeA( (AttrValueTyp)el, ELA ) );
  FreeOL( ol );
  
  return choice;
}


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

/* H_E_IPP
 * hide processing when b is iexp_pre_Processed
 */
static BehTyp H_E_IPP( b , gs )
     BehTyp     b;
     GateSetTyp gs;
{
  BehTyp           out,hide,hide2,choice,guard,iact,bi;
  PAttrTyp         ola,gsa,rfla;
  GateSetTyp       gs2,gs2bk,dif,inter;
  OfferListTyp     ol;
  RelabFuncListTyp rfl;
  int              numArg,i;
  
  switch ( LookTypeB(b) )
    {
    case GateC:
      choice = NULL;
      guard  = NULL;
      hide   = MakeB( 0, HidingC );
      PutA( hide, MakeA( (AttrValueTyp)CopyGS(gs), GSA ) );
      if ( GateInGS( LookNameB(b), gs ) ) {
        bi   = GetArgB( b, 1 );
        iact = MakeB( LookNameB(b) , IC );
        
        if ( LookA(b,OLA)!=NULL ) {
          ola = CopyA( LookA(b,OLA) );
          ol  = (OfferListTyp)LookAInfo( ola );
          if ( IsThereQuestionOL(ol) )
            choice = MkChoice( ol );
	  Convert_to_AdmirationOL((OfferListTyp)LookAInfo(ola));
	  PutA( iact, ola );
        }
	
	if ( LookA(b,PA)!=NULL ) {
	  guard = MakeB( 0, GuardC );   /*mse*/
	  PutA(guard,GetA( b, PA ));
	}
	
        out = ConcatUB(ConcatUB(ConcatUB(ConcatUB(
                                                  choice,
                                                  guard),
                                         iact),
                                hide),
                       bi);
        FreeB( b );
      }
      else {
        bi = GetArgB( b, 1 );
        PutArgB( b, hide, 1 );
        PutArgB( hide, bi, 1 );
        out = b;
      }
      break;
      
    case IC:
      hide = MakeB( 0, HidingC );
      PutA( hide, MakeA( (AttrValueTyp)CopyGS(gs), GSA ) );
      bi = GetArgB( b, 1 );
      PutArgB( b, hide, 1 );
      PutArgB( hide, bi, 1 );
      out = b;
      break;
      
    case DisablingC:
    case AlternativeC:
      numArg = NumArgB(b);
      for ( i=1; i<=numArg; i++ )
        PutArgB( b, H_E_IPP( GetArgB( b, i ), gs ), i );
      out = b;
      break;
      
    case StopC:
    case ExitC:
      out = b;
      break;
      
    case GuardC:
    case ChoiceC:
      PutArgB( b, H_E_IPP( GetArgB( b, 1 ), gs ), 1 );
      out = b;
      break;
      
    case HidingC:
      UnshareA( b, GSA );
      gsa = GetA( b, GSA );
      gs2 = (GateSetTyp)GetAInfo( gsa );
      gs2 = JunctionGS( gs, gs2bk=gs2 );
      PutAInfo( gsa, (AttrValueTyp)gs2 );
      PutA( b, gsa );
      FreeGS( gs2bk );
      out = b; /* Iexp_Hide_Proc( b ); */
      break;
      
    case RelabellingC:
      UnshareA( b, RFLA );
      rfla  = LookA( b, RFLA );
      rfl   = (RelabFuncListTyp)GetAInfo( rfla );
      /*
	 rng   = RangeRFL( rfl );
	 dif   = DiffGS( gs, rng );
	 img   = ImageRFL(rfl);
	 inter = IntersGS( img, gs );
	 inv   = InvApplyRFL( rfl, inter );
	 gs2   = JunctionGS( dif, inv );
	 FreeGS( rng );
	 FreeGS( dif );
	 FreeGS( img );
	 FreeGS( inter );
	 FreeGS( inv );
	 */
      gs2   = InvApplyRFL( rfl, gs );
      
      rfl = SimplifyRFL( rfl, gs2 );
      PutAInfo( rfla, (AttrValueTyp)rfl );
      bi = GetArgB(b,1);
      if ( rfl == NULL ) {  /* => gs2 not empty */
        FreeB(b);
        out = H_E_IPP( bi, gs2 );
      }
      else {
        if ( !IsEmptyGS(gs2) )
          PutArgB( b, H_E_IPP( bi, gs2 ), 1 );
        else
          AddArgB( b, bi );
        out = b;
      }
      FreeGS(gs2);
      break;
      
    case ParallelC:
      if ( LookNameB(b)!=FULL_SYNC ) {
        if ( LookNameB(b)==INTER_SYNC ) {
          dif   = CopyGS(gs);
          inter = NewGS();
        }
        else {
          gs2   = (GateSetTyp)LookAInfo(LookA(b,GSA));
          dif   = DiffGS( gs, gs2 );
          inter = IntersGS( gs, gs2 );
        }
        if ( !IsEmptyGS( dif ) ){
          b    = GetOperB(b);
          hide = MakeB( 0, HidingC );
          PutA( hide, MakeA((AttrValueTyp)dif,GSA) );
          hide2 = CopyB( hide );
          bi = GetArgB( b, 1 );
          PutArgB( b, hide, 1 );
          AddArgB( hide, bi );
          bi = GetArgB( b, 2 );
          PutArgB( b, hide2, 2 );
          AddArgB( hide2, bi );
        }
        else
          FreeGS(dif);
      }
      else
        inter = CopyGS(gs);                /* || => Ah-A = empty, Ah*A = Ah  */
      
      if ( !IsEmptyGS(inter) ) {
        hide = MakeB( 0, HidingC );
        PutA( hide, MakeA((AttrValueTyp)inter,GSA) );
        AddArgB( hide, b );
        out = hide;
      }
      else {
        out = b;
        FreeGS( inter );
      }
      break;
      
      
      /*
       *     HP(hide A in B1>>B2) = (hide A in B1) >> hide A in B2
       *
       */
      
    case EnablingC:
      LASSERT(!IsEmptyGS(gs));
      gs2  = CopyGS(gs);
      b    = GetOperB(b);
      hide = MakeB( 0, HidingC );
      PutA( hide, MakeA((AttrValueTyp)gs2,GSA) );
      hide2 = CopyB( hide );
      bi = GetArgB( b, 2 );
      PutArgB( b, hide, 2 );
      PutArgB( hide, bi, 1 );
      PutArgB( b, H_E_IPP( GetArgB( b, 1 ), gs ), 1 );
      out = b;
      break;
      
      /*
	 LASSERT(!IsEmptyGS(gs));
	 gs2  = CopyGS(gs);
	 b    = GetOperB(b);
	 hide = MakeB( 0, HidingC );
	 PutA( hide, MakeA((AttrValueTyp)gs2,GSA) );
	 hide2 = CopyB( hide );
	 bi = GetArgB( b, 1 );
	 PutArgB( b, hide, 1 );
	 AddArgB( hide, bi );
	 bi = GetArgB( b, 2 );
	 PutArgB( b, hide2, 2 );
	 AddArgB( hide2, bi );
	 out = b;
	 break;
	 */
      
    case ContSetC:
      out = b;
      break;
      
    default:
      Error("Iexp_Hide_Proc: unexpected cell type");
      break;
    }
  
  return out;
  
}

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


static BehTyp H_E( b , gs )
     BehTyp     b;
     GateSetTyp gs;
{
  BehTyp           out,hide,hide2,bi;
  PAttrTyp         gsa,rfla;
  GateSetTyp       gs2,gs2bk;
  RelabFuncListTyp rfl;
  int              numArg,i,cero=0;
  
  switch ( LookTypeB(b) )
    {
    case EnablingC:
    case ParallelC:
    case GateC:
      out = H_E_IPP( Iexp_Pre_Proc(b), gs );
      break;
      
    case IC:
      hide = MakeB( 0, HidingC );
      PutA( hide, MakeA( (AttrValueTyp)CopyGS(gs), GSA ) );
      bi = GetArgB( b, 1 );
      PutArgB( b, hide, 1 );
      PutArgB( hide, bi, 1 );
      out = b;
      break;
      
    case GuardC:
    case ChoiceC:
    case AlternativeC:
      numArg = NumArgB(b);
      for ( i=1; i<=numArg; i++ ){
        hide = MakeB( 0, HidingC );
        PutA( hide, MakeA( (AttrValueTyp)CopyGS(gs), GSA ) );
        bi = GetArgB( b, i );
        PutArgB( b, hide, i );
        PutArgB( hide, bi, 1 );
      }
      out = b;
      break;
      
    case StopC:
    case ExitC:
      out = b;
      break;
      
    case HidingC:
      UnshareA( b, GSA );
      gsa = GetA( b, GSA );
      gs2 = (GateSetTyp)GetAInfo( gsa );
      gs2 = JunctionGS( gs, gs2bk=gs2 );
      PutAInfo( gsa, (AttrValueTyp)gs2 );
      PutA( b, gsa );
      FreeGS( gs2bk );
      out = Iexp_Hide_Proc( b );
      break;
      
    case RelabellingC:
      UnshareA( b, RFLA );
      rfla  = LookA( b, RFLA );
      rfl   = (RelabFuncListTyp)GetAInfo( rfla );
      
      /*
	 rng   = RangeRFL( rfl );
	 dif   = DiffGS( gs, rng );
	 img   = ImageRFL(rfl);
	 inter = IntersGS( img, gs );
	 inv   = InvApplyRFL( rfl, inter );
	 gs2   = JunctionGS( dif, inv );
	 FreeGS( rng );
	 FreeGS( dif );
	 FreeGS( img );
	 FreeGS( inter );
	 FreeGS( inv );
	 */
      gs2 = InvApplyRFL( rfl, gs );
      
      rfl = SimplifyRFL( rfl, gs2 );
      PutAInfo( rfla, (AttrValueTyp)rfl );
      bi = GetArgB(b,1);
      if ( rfl == NULL ) {  /* => gs2 not empty */
        FreeB(b);
        out = H_E( bi, gs2 );
      }
      else {
        if ( !IsEmptyGS(gs2) )
          PutArgB( b, H_E( bi, gs2 ), 1 );
        else
          AddArgB( b, bi );
        out = b;
      }
      FreeGS(gs2);
      break;
      
      
      /*
       *     HP(hide A in B1[>B2) = (hide A in B1) [> hide A in B2
       *
       */
      
    case DisablingC:
      /* case EnablingC: *//**/
      LASSERT(!IsEmptyGS(gs));
      gs2  = CopyGS(gs);
      b    = GetOperB(b);
      hide = MakeB( 0, HidingC );
      PutA( hide, MakeA((AttrValueTyp)gs2,GSA) );
      hide2 = CopyB( hide );
      bi = GetArgB( b, 1 );
      PutArgB( b, hide, 1 );
      AddArgB( hide, bi );
      bi = GetArgB( b, 2 );
      PutArgB( b, hide2, 2 );
      AddArgB( hide2, bi );
      out = b;
      break;
      
    case ContSetC:
      out = b;
      break;
      
    case ProcessInstC:
    case LetC:
    case PletC:
    case ParC:
    case GateChoiceC:
      out = H_E( Pre_Processing( b, &cero ), gs ); 
      break;
      
    default:
      Error("Iexp_Hide_Proc: unexpected cell type");
      break;
    }
  
  return out;
  
}

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

/* Iexp_Hide_Proc
 */
BehTyp Iexp_Hide_Proc( hide )
     BehTyp hide;
{
  BehTyp out;
  GateSetTyp gs;
  
  LASSERT( LookTypeB(hide)==HidingC );
  
  gs  = (GateSetTyp)LookAInfo( LookA( hide, GSA ) );
  out = H_E( GetArgB( hide, 1 ), gs );
  FreeB( hide );
  
  return out;
}




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

/* Distribute_Choice
 * Distribute a value choice into a behaviour choice ( alternative )
 * just after the guards.
 * choice v:s [] ( B1[]B2 ) = (choice v:s [] B1) [] (choice v:s [] B2)
 */
BehTyp Distribute_Choice( b )
     BehTyp b;
{
  BehTyp c,a,bi;
  int n,i;
  
  LASSERT(LookCopy(b)==0);
  a = GetArgB( b, 1 );
  LASSERT(LookCopy(a)==0);
  
  switch ( LookTypeB(a) )
    {
    case AlternativeC:
      n = NumArgB( a );
      for ( i=1 ; i<=n ; i++ ) {
        bi = GetArgB( a, i );
        c  = CopyB(b);
        AddArgB( c, bi );
        PutArgB( a, Distribute_Choice(c), i );
      }
      FreeB( b );
      return a;
      
    case GuardC:
    case ChoiceC:
    case GateC:
    case IC:
    case ExitC:
    case DisablingC:
    case EnablingC:
    case HidingC:
    case RelabellingC:
    case ParallelC:
      PutArgB( b, a, 1 );    /* stop and do nothing */
      return b;
      
    case TerminationC:
    case StopC:
      FreeB( b );
      return a;
      
    default :
      Error("Distribute_Choice: unexpected cell.");
    }
  return NULL;
}

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

/* Distribute_Guard
 * Distribute a guard into a behaviour choice ( alternative )
 * [ BE ]-> ( B1[]B2 ) = ([ BE ]-> B1) [] ([ BE ]-> B2)
 */
BehTyp Distribute_Guard( b )
     BehTyp b;
{
  BehTyp c,a,bi,b1,b2;
  int n,i;
  
  LASSERT(LookCopy(b)==0);
  a = GetArgB( b, 1 );
  LASSERT(LookCopy(a)==0);
  
  switch ( LookTypeB(a) )
    {
    case AlternativeC:
      n = NumArgB( a );
      for ( i=1 ; i<=n ; i++ ) {
        bi = GetArgB( a, i );
        c  = CopyB(b);
        AddArgB( c, bi );
        PutArgB( a, Distribute_Guard(c), i );
      }
      FreeB( b );
      return a;
      
    case ChoiceC:
      b2 = a;
      b1 = LookArgB( b2, 1 );
      while ( LookTypeB(b1)==ChoiceC ) {
        b2 = b1;
        b1 = LookArgB( b2, 1 );
      }
      b1 = GetArgB( b2, 1 );
      AddArgB( b, b1 );
      PutArgB( b2, b, 1 );
      return a;
      
    case GuardC:
    case GateC:
    case IC:
    case ExitC:
    case DisablingC:
    case EnablingC:
    case HidingC:
    case RelabellingC:
    case ParallelC:
      PutArgB( b, a, 1 );
      return b;
      
    case TerminationC:
    case StopC:
      FreeB( b );
      return a;
      
    default :
      Error("Distribute_Guard: unexpected cell.");
    }
  return NULL;
}

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

