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

/***********************************
  
  David Larrabeiti Lopez
  
  25-04-91
  
  Extended Parallel Expansion.
  
  ************************************/


#include "baattr.h"
#include "badefca.h"
#include "eximmed.h"
#include "excount.h"
#include "basust_v.h"
#include "expre_br.h"


#define MAXFORMALGATES 50
#define MAXACTUALGATES 50

static int m;             /* number of formal gates ( digits of the counter )*/
static int n;             /* number of actual gates ( module of the counter )*/
static DescriptorTyp formal[MAXFORMALGATES],
actual[MAXACTUALGATES];



/* Initialize_GateNames_and_Counter
 * Fills in formal[] and actual[] with the formalgatenames and with the
 * actualgatenames respectively , of the gate declaration list.
 * Initializes the counter according to the existing numbers of gates.
 */
static void Initialize_GateNames_and_Counter( gatedeclist )
     GateDecListTyp gatedeclist;
{
  PGateDecTyp gatedecPt;
  GateListTyp glist,glistNode;
  
  gatedecPt=(PGateDecTyp)LookInfo_list( gatedeclist );
  glist=gatedecPt->agl;
  for ( n=0; glist!= NULL ; glist=Next_list(glist),n++ )
    actual[n]=(DescriptorTyp)LookInfo_list(glist);
  
  glist=GateSet_to_GateList( gatedecPt->fgs );
  glistNode=glist;
  for ( m=0; glistNode!= NULL ; glistNode=Next_list(glistNode),m++ )
    formal[m]=(DescriptorTyp)LookInfo_list(glistNode);
  FreeGL( glist );
  
  Initialize_Counter( m, n );
}




/* MakeRelabel
 * Builds a relabel cell with the combination of gates given by the current
 * value of "counter".
 */
static BehTyp MakeRelabel()
{
  int i;
  RelabFuncListTyp rfl;
  BehTyp relab;
  
  rfl = CreateRFL();
  
  for ( i=0 ; i<m ; i++ )
    rfl = AddRFL( rfl, actual[ counter[m-1-i] ], formal[ i ] );
  
  relab = MakeB(0,RelabellingC);
  PutA( relab, MakeA( (AttrValueTyp)rfl, RFLA ) );
  
  return relab;
}



/* Append_Parallel
 * Appends an element b2 to b1 through a parallel operator whose name and
 * attribute ( GSA ) must be provided in order to be shared.
 * b1 or b2 can be NULL.
 *
 * Example.   Append_Parallel( NULL, b, gsa, syncClass )=b
 *            Append_Parallel( b1, b2, gsa, syncClass )= b2|[LookAInfo(gsa)]|b1
 */
static BehTyp Append_Parallel( b1, b2, parAttr, syncClass )
     BehTyp b1,b2;
     PAttrTyp parAttr;
     DescriptorTyp syncClass;
{
  BehTyp par;
  
  if ((b1==NULL) || (b2==NULL))
    return  (  (b1==NULL)? b2: b1 );
  
  par = MakeB( syncClass, ParallelC );
  if ( parAttr!=NULL )
    PutA( par, parAttr );
  PutArgB( par, b2, 1 );
  PutArgB( par, b1, 2 );
  
  return par;
}




/* SingleExtPar_Expand
 * Expands a single gate declaration extended-parallel into the parallel
 * of relabels .
 */
static BehTyp SingleExtPar_Expand( b )
     BehTyp b;
{
  BehTyp relab,bi,bi2,result;
  PAttrTyp gsa;
  SVdescriptorTyp sv;
  boolean first;
  
  bi=GetArgB(b,1);
  gsa=GetA(b,GSA);
  
  result=NULL;
  first=TRUE;
  Initialize_GateNames_and_Counter( (GateDecListTyp)LookAInfo(LookA(b,GDLA)) );
  do {
    if ( first ) {
      bi2=bi;
      first=FALSE;
    }
    else {
      bi2=CopyB(bi);
      sv=CreateSV();
      InsertBehDefSV( bi2, &sv );
      SubstBehSV( bi2, &sv );
      /* ( SubstBehSV unshares the attrs that modifies ) */
      FreeSV( &sv );
    }
    relab  = MakeRelabel();
    result = Append_Parallel( result, relab, gsa, LookNameB(b) );
    PutArgB( relab, bi2, 1 );
  }
  while (Increment());
  
  FreeB(b);
  
  return result;
}



/* Normalize_ExtPar
 * Splits a multiple gate-declaration ext. parallel into a succesion of 
 * single ones.
 * Ex. par a,b in [ x, y ], c in [ y ] |[c]| B =
 *     par a,b in [ x, y ] |[c]|
 *         ( par c in [ y ] |[c]| B )
 */
static BehTyp Normalize_ExtPar( b )
     BehTyp b;
{
  BehTyp bi,newpar,out;
  GateDecListTyp gdl,gdnode;
  PAttrTyp gdla, gsa;
  
  if ( Length_list( (ListTyp)LookAInfo(LookA( b, GDLA )) ) == 1 )
    return b;
  else
    {
      bi   = GetArgB( b, 1 );
      UnshareA( b, GDLA );
      gdla = GetA( b, GDLA );
      gdl  = (GateDecListTyp)GetAInfo( gdla );
      gsa  = GetA( b, GSA );
      
      out=NULL;
      while( gdl!=NULL ) {
	gdnode = gdl;
	gdl    = ExtractNode_list( gdnode, gdl );
	newpar = MakeB( LookNameB(b), ParC );
	PutA( newpar, MakeA( (AttrValueTyp)gdnode, GDLA) );
	if ( gsa!=NULL )
	  PutA( newpar, gsa );
	out = ConcatUB( out, newpar );
      }
      PutArgB( newpar, bi, 1 );
      
      FreeB(b);
      FreeA(gdla);
      
      return out;
    }
  
}




/* Par_Expr_Processing
 * Expands any extended parallel.
 */
BehTyp Par_Expr_Processing( b )
     BehTyp b;
{
  return SingleExtPar_Expand( Normalize_ExtPar( b ) );
}

