/******************************************************************
 *  (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

/******************************************************************
 *  
 *  Gualberto Rabay Filho
 *  David Larrabeiti Lopez
 *
 *  23 Apr 1994
 *
 *  Time Attribute Functions
 *  
 *
 *  COMPILATION FLAGS:
 *     TIME : Activate time
 *  
 *  LOG:
 *
 ******************************************************************/
#ifdef TIME

#include "limisc.h"
#include "baattr.h"
#include "listrbk.h"
#include "badefca.h"
#include "baexpr.h"
#include "licell.h"
#include "batyperw.h"
#include "eximmed.h"
#include "basust_v.h"
#include "batables.h"
#include "balotosf.h"
#include "expre_br.h"

/* 
 *  count of time  structs used and released.
 */
static int new_time_count      = 0;
static int released_time_count = 0;
static int max_time_count      = 0;

/* StatTime
 * Give statistics about the time cells allocated and released.
 * uc  : number of time cell queries originated by this module. 
 * rc  : time cell releases.
 * mc  : max used time cells
*/ 
void StatTime( nc, rc, mc )
 int * nc, *rc, *mc;
{
  *nc = new_time_count;
  *rc = released_time_count;
  *mc = max_time_count;
}

  
/* InitT
 * Call TranslateTime to eliminate the "time" gates from spec
 * and to add time attributes to other gates 
 */
void InitT()
{  
#ifdef SDEBUG
  new_time_count      = 0;
  released_time_count = 0;
  max_time_count      = 0;
#endif
  TranslateTime();
}

/* NewT
 *  Create an empty time structure 
 */
PTimeTyp NewT()
{ 
  PTimeTyp  time; 
#ifdef SDEBUG
  new_time_count++;
  max_time_count = MAX( max_time_count, new_time_count-released_time_count );
#endif
  time = (PTimeTyp) NewCellM(sizeof(TimeTyp));
  time->lower_bound = NULL;
  time->upper_bound = NULL;
  time->tvar = NULL;
  return time;
}

/*  MakeT
 *   Create and  initialize a time structure
 *   t0 is the time variable,t1 is the lower bound, 
 *   t2 is the upper bound
 */
PTimeTyp MakeT( t0,t1, t2 )
     ExprTyp  t0, t1, t2;
{ PTimeTyp  time;
  time=NewT() ;    /* tvar */
  if (t0!=NULL)
    time->tvar =ShareE(t0) ;
  else
    time->tvar =(ExprTyp)NULL;
  time->lower_bound=ShareE(t1);
  time->upper_bound=ShareE(t2);
  return time; 
}

/* PT 
 * Print the time - used for debuging  purpose 
 */ 
void PT (t) 
 PTimeTyp   t;
{ 
  PrintT(t,PrintString); 
 } 

/* PrintT
 * Print the time 
 * pstr is the function used to print strings.
 */
void PrintT( t, pstr )
     PTimeTyp   t;
     void    (*pstr)(); 
{
  char * str; 
  
  str = SPrintT(t);
  pstr(str);
  (void) free (str); 
}


/* SPrintT
 * Return a char string with the time bounds
 */
char * SPrintT( t )
     PTimeTyp   t;
{ char    * str;
  StrBckTyp strBck;
  
  strBck = CreateStrBck();
  strBck  = ConcatStrBck( strBck, "{" );
  if (t->tvar !=NULL){
    str = ExprToStringE (t->tvar);
    strBck  = ConcatStrBck( strBck,str );
    free( str ); 
    if (IsConstE(t->tvar)) {
      strBck  = ConcatStrBck( strBck, "}" ); 
      str = GetStrStrBck( strBck) ;
      FreeStrBck( strBck );
      return str;
    }
    strBck  = ConcatStrBck( strBck, " in " );  
  }
  str = ExprToStringE (t->lower_bound);
  strBck  = ConcatStrBck( strBck,str );
  free( str );
 
  if (!EqualE(t->lower_bound,t->upper_bound)) {
    strBck  = ConcatStrBck( strBck, ".." ); 
    str = ExprToStringE (t->upper_bound) ;
    strBck  = ConcatStrBck( strBck,str );
    free( str );
  }
  strBck  = ConcatStrBck( strBck, "}" ); 
  str = GetStrStrBck( strBck) ;
  FreeStrBck( strBck );
  return str;
}

/* DispT
 * Free the memory used by the time cell t
 */
void DispT( t )
     PTimeTyp t;
{  
#ifdef SDEBUG
  released_time_count++;
#endif
   FreeCellM((void*)t,sizeof(TimeTyp));
}


/*  FreeT 
 *  Free the memory used by the time attribute t
 */
void FreeT (t)
     PTimeTyp t;
{  
  if (t !=NULL) {
    LASSERT(OwnersE(t->lower_bound)!=0);
    LASSERT(OwnersE(t->upper_bound)!=0); 
    if (t->tvar !=NULL) {
      LASSERT(OwnersE(t->tvar)!=0);
      FreeE(UnshareE(t->tvar));
    }
    FreeE(UnshareE(t->lower_bound));
    FreeE(UnshareE(t->upper_bound));
    DispT(t);
  }
}

/* CopyT 
 * Copy  the time attribute t
*/
PTimeTyp  CopyT (t)
     PTimeTyp  t;
{  
  PTimeTyp nt;

  LASSERT(OwnersE(t->lower_bound)!=0);
  LASSERT(OwnersE(t->upper_bound)!=0); 
  nt = NewT();
  
  if (t->tvar != NULL)
    nt->tvar =  ShareE(CopyE(t->tvar));
  else  
    nt->tvar = (ExprTyp) NULL;
  nt->lower_bound = ShareE(CopyE(t->lower_bound)); 
  nt->upper_bound = ShareE(CopyE(t->upper_bound)); 
  return nt;
}

/* UnshareT
 * Decrement the share counter of all expressions contained in the time cell
*/
PTimeTyp UnshareT (t)
     PTimeTyp t;
{  
  PTimeTyp nt ;
  
  nt=t; 
  if (nt != NULL){
    if (nt->tvar!=NULL)
      nt ->tvar =  ShareE(GetE(UnshareE(nt->tvar)));
    nt->lower_bound =   ShareE(GetE(UnshareE(nt->lower_bound)));
    nt->upper_bound =   ShareE(GetE(UnshareE(nt->upper_bound)));
  }
return t;
}


/*   TransTime
 *   Remove from behaviour b the "time" gates and adds the time 
 *   gate offers as time attributes to each following gate.  
*/
static void TransTime( b )
     BehTyp b;
{
  int i;
  PTimeTyp  ntime;
  PAttrTyp ola;
  OfferListTyp ol,oln;
  DescriptorTyp zero,inf;
  BehTyp gate;
  DescriptorTyp  tvar;
  while ( b!=NULL )
    switch ( LookTypeB(b) )
      {
      case EnablingC:
	TransTime( LookArgB(b,2) );
	b = LookArgB(b,1);
	break;
      case DisablingC:
	TransTime( LookArgB(b,2) );
	b = LookArgB(b,1);
	break;
      case ParallelC:
	TransTime( LookArgB(b,2) );
	b = LookArgB(b,1);
	break;
	
      case AlternativeC:
	for ( i=NumArgB(b); i>1; i-- )      
	  TransTime( LookArgB(b,i) );   
	b = LookArgB(b,1);  
	break;
      case ExitC: 
      case IC:  
      case GateC:
	ntime = NewT();
	if ((LookType(b)==GateC) &&
	    strcmp (  GetG_name(LookNameB(b)),"time")==0 ){
	  LASSERT(LookTypeB(LookArgB(b,1))==GateC||
		  LookTypeB(LookArgB(b,1))==IC )
	    ola = GetA(b,OLA);
	  ol=(OfferListTyp) GetAInfo(ola);
	  oln = ol; 
	  LASSERT(ol!=NULL);
	  
	  if (LookKindOffer(ol)==QUESTION){ 
	    ntime->tvar = ShareE(CopyE(LookExprOffer(ol)));
	    oln = MvNextOffer( oln ); 
	  }  
	  if (oln != NULL){
	    ntime->lower_bound =ShareE(CopyE(LookExprOffer(oln)));
	    oln = MvNextOffer(oln);                 
	    if (oln != NULL) 
	      ntime->upper_bound = ShareE(CopyE(LookExprOffer(oln)));
	    else
	      ntime->upper_bound = ShareE(CopyE(ntime->lower_bound));
	  }
	  FreeOL(ol); 
	  FreeA(ola);
	  gate = LookArgB(b,1); 
	  GlueB( b, gate );
	}	
	if (ntime->upper_bound == NULL){
	  zero = FindO_time("0");
          if (zero == 0) {
	    Error("Fatal error: sort Time  not found.");
	  }
	  ntime->lower_bound = ShareE(MakeE(zero,OperationC));
	  inf  =  FindO_time("inf");
	  ntime->upper_bound = ShareE(MakeE(inf,OperationC));
	}
	if (!(EqualE(ntime->upper_bound,ntime->lower_bound))
	    && (ntime->tvar == NULL)){
	  if ((tvar=FindV("time", FindS("time")))==0)
	    tvar =  Declare_var("time",FindS("time"));
	  else 
	    tvar = EqualV_entry(tvar);
	  ntime->tvar = MakeE(tvar ,VariableC);
	  ShareE( ntime->tvar);
	}
	PutA( b, MakeA( (AttrValueTyp)ntime, TA ) );
	b=( LookArgB(b,1));   
	break;
	
      case ChoiceC:
      case GuardC:
	b=( LookArgB(b,1));   
	break;
	
      case StopC:
	b = NULL;
	break;
	
      case RelabellingC:
      case HidingC:
      case PletC:
      case LetC:
	b = LookArgB(b,1);
	break;
	
      case ProcessInstC:
	DeleteT(b); 
	b=  LookArgB(b,1) ;
	break;
	
      case ProcessDefC:
	DeleteT(b); 
	b=  LookArgB(b,1) ;
	break;
	
      case SpecificationC:          
	DeleteT(b);
	b =  LookArgB(b,1) ;
	break;
      case GateChoiceC:
      case ParC:
      case BehaviourC:
      case InterleavedC:
      case TerminationC:
      default:
	Error("TransTime : Unexpected cell type");
      } 
}

/*  TranslateTime 
 *  Apply the translation from time actions to time attribute 
 *  over the whole specification 
 */
void TranslateTime()
{
  DescriptorTyp last, i;
  
  last = LastTableP();
  for ( i=1; i<=last; i++ )
    TransTime(GetP_def(i));
}


/* DeleteT 
 * Remove the "time" gates from the spec and processes gate lists 
 */
void  DeleteT (b)
     BehTyp b;
{ 
  GateListTyp gl,gl1;
  PAttrTyp gla;
  gla = LookA(b,GLA);
      if (gla !=NULL){
        gl = (GateListTyp) GetAInfo(gla); 
         gl1 = gl;
    while (gl1 != NULL) {
      if ( strcmp((char*)GetG_name((DescriptorTyp)LookInfo_list(gl1)),"time")== 0 )   
	break;
      gl1 = gl1->next;
    }
    if (gl1!=NULL) 
      gl= DeleteNode_list( gl1, gl );
    PutAInfo( gla,(AttrValueTyp) gl );
  }
}


/* InterT 
 * Check if there is a intersection between time intervals t1 and t2
 */ 
ExprTyp InterT (t1,t2)
     PTimeTyp t1,t2;
{
  ExprTyp res,aux1,aux2,expmin,expmax,expge; 
  DescriptorTyp opmin,opmax,opge;
  
  opmin = FindO_time("min"); 
  expmin = MakeE(opmin,OperationC);
  AddArgE(expmin,t1->upper_bound);
  AddArgE(expmin,t2->upper_bound);
  aux1 = CopyE(expmin) ; 
  Rewrite (aux1); 
  if (NumArgE(aux1)>= NumArgE(expmin)) 
    FreeE(aux1);
  else {
    FreeE(expmin);
    expmin = aux1;
  }
  opmax = FindO_time("max"); 
  expmax = MakeE(opmax,OperationC);
  AddArgE(expmax,t1->lower_bound);
  AddArgE(expmax,t2->lower_bound); 
  aux2 = CopyE(expmax);
  Rewrite(aux2);
  if (NumArgE(aux2)>= NumArgE(expmax)) 
    FreeE(aux2);
  else {
    FreeE(expmax);
    expmax = aux2;
  }
  opge = FindO_time("ge"); 
  expge = MakeE(opge,OperationC);
  
  AddArgE(expge,expmin); 
  AddArgE(expge,expmax);
  res = CopyE(expge); 
  Rewrite(res);
  if (NumArgE(res)>=NumArgE(expge)) {
    FreeE(res);
    return expge;
  }
  else {
    FreeE(expge);
    return res;
  }
}


/* LowerT
 * Calculate the greatest lower bound between time intervals t1 and t2 
*/
ExprTyp LowerT (t1,t2)
  PTimeTyp t1,t2;
{
  DescriptorTyp max;
  ExprTyp lower;
  if (!IsConstE(t1->lower_bound)||!IsConstE(t2->lower_bound)) {
    max = FindO_time("max");
    lower = MakeE(max,OperationC); 
    AddArgE(lower,CopyE(t1->lower_bound));
    AddArgE (lower,CopyE(t2->lower_bound));
    Rewrite(lower); 
    return lower; 
  }
  if (IsGe( t2->lower_bound, t1->lower_bound))
    return  t2->lower_bound;
  return  t1->lower_bound;
}


/* UpperT
 * Calculate the least upper bound between time intervals t1 and t2 
 */
ExprTyp UpperT (t1,t2)
     PTimeTyp t1,t2;
{   DescriptorTyp min;
    ExprTyp upper;
    if (!IsConstE(t1->upper_bound)||!IsConstE(t2->upper_bound)) {
      min = FindO_time("min");
      upper = MakeE(min,OperationC); 
      AddArgE(upper,CopyE(t1->upper_bound));
      AddArgE (upper,CopyE(t2->upper_bound));
      Rewrite(upper); 
      return upper; 
    }
    if (IsGe( t2->upper_bound, t1->upper_bound))
    return t1->upper_bound;
    return  t2->upper_bound;
}

/* IsGt  
 * Checks if time instant t1  is gt than time instant t2
 */

boolean IsGt(t1,t2)
     ExprTyp t1,t2;
{ DescriptorTyp gt;
  ExprTyp egt; 
 
  gt= FindO_time("gt");
  egt = MakeE(gt,OperationC);
  AddArgE(egt,CopyE(t1));
  AddArgE(egt,CopyE(t2));
  Rewrite(egt);
  if (strcmp(ExprToStringE(egt),"true")==0) {
    FreeE(egt);
    return TRUE;
  }
  else {
    FreeE(egt);
    return FALSE;
  }
}



/* IsGe 
 * Check if time instant t1 is ge than time instant t2 
 */
boolean IsGe(t1,t2)
ExprTyp t1,t2;
{ DescriptorTyp ge;
  ExprTyp ege; 
  
  ge= FindO_time("ge");
  ege = MakeE(ge,OperationC);
  AddArgE(ege,CopyE(t1));
  AddArgE(ege,CopyE(t2));
  Rewrite(ege);
  if (strcmp(ExprToStringE(ege),"true")==0) {
    FreeE(ege);
    return TRUE;
  }
  else {
    FreeE(ege);
    return FALSE;
  }
}


/* AgeGateT 
 * Age the time attribute of a gate
 * return false if time attribute is lesser than age value 
 */
boolean AgeGateT(e,b)
     ExprTyp e;
     BehTyp  b;
{ 
  ExprTyp  e1,e2, new1,new2; 
  PTimeTyp  time;
  PAttrTyp  ta;
  DescriptorTyp minus;
  
  ta =  LookA(b,TA); 
  time =(PTimeTyp)LookAInfo(ta); 
  if (LookNameE(time->upper_bound)==FindO_time("inf") &&
      LookNameE(time->lower_bound)==FindO_time("0")  )
    return TRUE; 
  if (LookNameE(time->upper_bound)==FindO_time("neg"))
    return FALSE;
  if ((IsConstE(e)) && IsGt(e,time->upper_bound))
    return FALSE;
  
  time =(PTimeTyp)GetAInfo(ta);
  e1 = CopyE(time->lower_bound);
  e2 = CopyE(time->upper_bound);
    minus = FindO_time("-");
  new2 = MakeE(minus,OperationC);
  AddArgE(new2,CopyE(e2));
  AddArgE(new2,e); 
  Rewrite(new2);
  FreeE(UnshareE(time->upper_bound)); 
  time->upper_bound=ShareE(new2);
  if (EqualE(e1,e2))  {
    FreeE(UnshareE(time->lower_bound)); 
    time->lower_bound=ShareE(new2);
  } 
  else 
    if  ((!IsConstE(e)) || !IsGt(e,time->lower_bound))
      if (LookNameE(time->lower_bound)!=FindO_time("0")){
	minus = FindO_time("-");
	new1 = MakeE(minus,OperationC);
	AddArgE(new1,CopyE(e1));
	AddArgE(new1,e); 
	Rewrite(new1);
	FreeE(UnshareE(time->lower_bound)); 
	time->lower_bound=ShareE(new1);
      }
      else 
	ChangeNameE(time->lower_bound, FindO_time("0"));
  PutAInfo( ta,(AttrValueTyp)time );
  FreeE(e1);
  FreeE(e2);
  return TRUE;
}

/* Age1T  (e, b)
 * Age behaviour b  with "e" units of time
 */   
void Age1T (e,b)
     ExprTyp e;  
     BehTyp b;
{
  int i;
  while (b!=NULL)
    switch( LookType(b)) {
    case ChoiceC:
    case GuardC:
    case PletC:
      b=( LookArgB(b,1));   
      break;
    case StopC:  
    case ExitC: 
      return;
    case IC:            
    case GateC: 
      if (!AgeGateT(e,b)) 
 	(void) TrfStop(b);
      return;
    case AlternativeC:
      for ( i=NumArgB(b); i>1; i-- )    
	Age1T( e,LookArgB(b,i));
      b = LookArgB(b,1);        
      break;
    default:
      Error("Age1T : Unexpected cell type");
    } 
}


/* ChoiceT 
 * Construct  a choice with guards from time attributes
 * For instance:   
 *      choice time:nat [] [t1 le time]->[time le t2]-> 
*/ 

BehTyp  ChoiceT ( td , t1,t2)
     ExprTyp t1,t2;
     DescriptorTyp td;  
{
  BehTyp g1,g2;
  ExprTyp e1,e2,et1,et2;
  DescriptorTyp ge,le, tr  ;
  
  g2 = MakeB(0, GuardC); 
  ge =  FindO_time("ge");
  et2 =  MakeE(td,VariableC);
  e2 = MakeE(ge,OperationC);
  Rewrite(t2);
  AddArgE(e2,CopyE(t2)); 
  AddArgE(e2,et2); 
  PutA( g2, MakeA( (AttrValueTyp)NewPred(e2,(ExprTyp)NULL),PA) ); 
  if (LookNameE(t1)!= FindO_time("0") &&
      LookNameE(t1)!= FindO_time("neg") ) {
    le = FindO_time("le");
    et1 = CopyE(et2) ;
    e1 = MakeE(le,OperationC); 
    AddArgE(e1,CopyE(t1)); 
    AddArgE(e1,et1);
    g1 = MakeB(0, GuardC);   
    PutA( g1, MakeA( (AttrValueTyp)NewPred(e1,(ExprTyp)NULL),PA) );
    g2 = ConcatUB(g2 ,g1);
  }
  return g2 ;  
}

/*  AsapT 
 *  Apply the asap semantics  to behaviour b 
 */ 
BehTyp  AsapT(b) 
     BehTyp b;
{ ExprTyp tmin,aux;
  DescriptorTyp mind;
  
  mind = FindO_time("inf");
  tmin = MakeE(mind, OperationC);
  aux = CopyE(tmin); 
  MinT(&tmin,b);
  if (!EqualE(aux,tmin)){
    (void) CutAsapT(tmin,b);  
    Pre_Branch_Stop(b); 
  }
  
  FreeE(tmin); 
  FreeE(aux);
  return b;
}

/* MinT 
 *  Calculate the minimal lower bound of  the i gates  from behaviour b
 */
void  MinT ( tmin,b)
     BehTyp b;
     ExprTyp *tmin;
{
  PTimeTyp  time;
  ExprTyp lb1,ub1,expmin,expift,expge,aux1,aux2;
  DescriptorTyp opmin, opift, opge; 
  int i;

  while (b!=NULL)
    switch( LookType(b)) {
    case ChoiceC:
    case ProcessInstC:
      b=( LookArgB(b,1));   
      break;
    case GuardC:   
      b=AsapT(LookArgB(b,1));
      return;
    case StopC:
    case GateC:  
    case ExitC: 
      return;
    case IC:    
      if (LookAInfo(LookA(b,TA))!=NULL){
	time = (PTimeTyp)LookAInfo(LookA(b,TA));
	lb1 =time->lower_bound;
        ub1 =time->upper_bound;
	if (!IsConstE(*tmin)||!IsConstE(lb1) ||
            !IsConstE(ub1)) {
	  opge  =  FindO_time("ge"); 
          expge =MakeE(opge,OperationC); 
          AddArgE(expge,ub1); 
	  AddArgE(expge,lb1); 
          aux1 = CopyE(expge); 
          Rewrite(aux1);
	  if (NumArgE(aux1)>= NumArgE(expge)) 
	    FreeE(aux1);
	  else {
	    FreeE(expge);
	    expge = aux1;
	  }
          opmin = FindO_time("min"); 
	  expmin = MakeE(opmin,OperationC);
	  AddArgE(expmin,CopyE(*tmin));
          AddArgE(expmin,CopyE(ub1));  
	  Rewrite(expmin);
	  opift = FindO_time("ifthe"); 
	  expift = MakeE(opift,OperationC);
          AddArgE(expift,expge);
	  AddArgE(expift,expmin);
	  AddArgE(expift,CopyE(*tmin));
	  aux2 = CopyE(expift);
	  Rewrite(aux2);
	  if (NumArgE(aux2)>= NumArgE(expift)) 
	    FreeE(aux2);
	  else {
	    FreeE(expift);
	    expift = aux2;
	  }
	  FreeE(*tmin); 
	  *tmin = expift; 
	} 
	else 
	  if  (IsGt(*tmin,ub1)) {       /* i no-asap */
	    FreeE(*tmin);
	    * tmin = CopyE(ub1);
	  }
      } 
      return;
      
    case AlternativeC:
      for ( i=NumArgB(b); i>1; i-- ){    
	MinT( tmin,LookArgB(b,i));
      } 
      b = LookArgB(b,1);        
      break;
    default:
      Error("MinT : Unexpected cell type");
    }
  return;
}


/* CutAsapT
 * Transform into Stop those branches that do not conform with the time 
 * constraints
 */ 
void CutAsapT(tmin,b)
     BehTyp b;
     ExprTyp tmin;
{ 
  PTimeTyp  time;
  int i;

  VarAssignListTyp val;
  SVdescriptorTyp sv;
  DescriptorTyp  ifthe,gt,inf,opmin;
  ExprTyp    op1,aux2,  cond,  comp,expmin; 
  while (b!=NULL)
    switch( LookType(b)) {
    case ChoiceC:
      b=( LookArgB(b,1));   
      break;
    case GuardC: 
    case ExitC:
    case StopC: 
      return ;
    case GateC:  
    case IC:        
      time = (PTimeTyp)LookAInfo(LookA(b,TA));
      if (IsConstE(tmin) && IsConstE( time->lower_bound)){ 
	if (IsGt( time->lower_bound,tmin)){
	  (void)   TrfStop(b);
	  return ;
	}
      }
      else {
        if (LookNameE(time->lower_bound)!= FindO_time("0")) {
	  ifthe = FindO_time("ifthe");
	  gt    = FindO_time("gt"); 
	  inf  = FindO_time("inf");
	  cond = MakeE(ifthe,OperationC);
	  comp = MakeE(gt,OperationC); 
	  op1 = MakeE(inf,OperationC);
	  AddArgE(comp,CopyE(time->lower_bound));
	  AddArgE(comp,CopyE(tmin));             /*  tmin,inf,lower_bound)  */
	  AddArgE(cond,comp);
	  AddArgE(cond,op1);
	  AddArgE(cond,CopyE(time->lower_bound));
	  FreeE(UnshareE(time->lower_bound)); 
	  time->lower_bound = ShareE(cond); 
	}
      }
      if (IsConstE(tmin) && IsConstE( time->upper_bound)){   
	if  (IsGt(time->upper_bound,tmin)) {
	  FreeE(UnshareE(time->upper_bound));
	  time->upper_bound =  ShareE(CopyE(tmin));
	} 
      }
      else {  
        if (LookNameE(time->upper_bound) != FindO_time("inf")) {
	  opmin = FindO_time("min"); 
	  expmin = MakeE(opmin,OperationC);
	  AddArgE(expmin,CopyE(*tmin));
	  AddArgE(expmin,CopyE(time->upper_bound)); 
	  aux2 = CopyE(expmin);
	  Rewrite(aux2);
	  if (NumArgE(aux2)>= NumArgE(expmin)) 
	    FreeE(aux2);
	  else {
	    FreeE(expmin);
	    expmin = aux2;
	  }
	  FreeE(UnshareE(time->upper_bound)); 
	  time->upper_bound = ShareE(expmin);
	}
      }
      if (EqualE( time->lower_bound,time->upper_bound) && 
	  (time->tvar!=NULL) && !IsConstE(time->tvar)){ 
	val = CreateVAL();
	sv = CreateSV();
	val = AddVAL(val,LookNameE(time->tvar),ShareE(CopyE( time->lower_bound)));
	Insert_VAL_SV( val, &sv );
	
	if ( IsUsedInBehSV( &sv, b ) )
	  SubstBehSV( b, &sv );
	FreeSV(&sv);
	FreeVAL(val);
      }
      return ;
    case AlternativeC:
      for ( i=NumArgB(b); i>1; i-- )    
	CutAsapT(tmin,LookArgB(b,i));
      b = LookArgB(b,1);        
      break;
    default:
      Error("CutAsapT : Unexpected cell type");
    } 
}

/* AgeLet 
 * Age  assignments of time variables in let expressions  
 */ 
PAttrTyp AgeLet (e1,time,vala)  
     PAttrTyp         vala;
     PTimeTyp time ;
     ExprTyp e1;
{ 
  VarAssignListTyp val1,val2;
  DescriptorTyp plus,varfor1; 
  ExprTyp eplus;
  
  val1 = (VarAssignListTyp) LookAInfo(vala); 
  for ( ;val1 !=NULL; val1= Next_list(val1)) {
    varfor1 = LookVarVAL(val1);
    if (strcmp((char *) GetV_name(varfor1),"time") == 0)  
      if (LookNameE( LookExprVAL(val1))!= FindO_time("0")) {
	plus = FindO_time("+");
	eplus = MakeE(plus,OperationC);
	
	AddArgE(eplus,CopyE(time->tvar));
	AddArgE(eplus,CopyE( LookExprVAL(val1)));
	Rewrite(eplus); 
	val2 = CreateVAL();
	val2 =  AddVAL(val2,LookNameE(e1),eplus) ;  
	return  MakeA((AttrValueTyp) val2, VALA);  
      }
      else
	return NULL;
  }
  return NULL;   
}


#endif 
