/*
 * TypeEnv.java
 *
 * Created on 17 de Junho de 2005, 17:36
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package net.sourceforge.czt.typecheck.circus.util;

import java.util.Stack;
import java.util.List;
import java.util.ArrayList;

import static net.sourceforge.czt.typecheck.circus.util.GlobalDefs.*;

import net.sourceforge.czt.base.ast.*;
import net.sourceforge.czt.circus.ast.*;
import net.sourceforge.czt.circus.impl.CircusFactoryImpl;
import net.sourceforge.czt.circustools.ast.ActionType;
import net.sourceforge.czt.typecheck.z.util.TypeEnv;
import net.sourceforge.czt.z.ast.RefName;
import net.sourceforge.czt.z.ast.Type;

import net.sourceforge.czt.z.ast.ZFactory;
import net.sourceforge.czt.z.ast.NameTypePair;
import net.sourceforge.czt.z.ast.DeclName;
import net.sourceforge.czt.z.impl.ZFactoryImpl;

import net.sourceforge.czt.typecheck.circus.*;
import net.sourceforge.czt.typecheck.circus.impl.*;

/**
 *
 * @author Manuela 
 */
public class LocalTypeEnv
//  extends net.sourceforge.czt.typecheck.z.util.TypeEnv
{

  /** A Factory. */
  protected Factory circusFactory_;

  /** The namesets. */
  protected Stack<List<DeclName>> namesets_;

    /** The actions. */
  protected Stack<List<ActionInfo>> actions_;

  /** The list of variables declared so far. */
  protected Stack<List<NameTypePair>> stateVars_;
  
  /** The list of all declarations. */
  protected Stack<List<ActionPara>> onTheFlyActions_;
  
  /** The list of used channels */
  protected Stack<List<NameTypePair>> usedChans_;
  
  /** A pilha dos canais implicitos e genéricos */
  protected Stack<List<DeclName>> genericImplicitChans_;
  
  /** Uma referencia ao TypeEnv */
  protected TypeEnv localDefs_;
    
  //<<15/06/2006>>
  protected Stack<List<NameTypePair>> localVars_;
  //
  
  /** Creates a new instance of LocalTypeEnv */
  public LocalTypeEnv(CircusFactory circusFactory, TypeEnv typeEnv)
  {
    circusFactory_ = new Factory(circusFactory);
    namesets_ = new Stack<List<DeclName>>();
    actions_ = new Stack<List<ActionInfo>>();
    stateVars_ = new Stack<List<NameTypePair>>();
    onTheFlyActions_ = new Stack<List<ActionPara>>();
    usedChans_ = new Stack<List<NameTypePair>>();
    genericImplicitChans_ = new Stack<List<DeclName>>();
    localDefs_ = typeEnv;
    localVars_ = new Stack<List<NameTypePair>>();
  }
  
  public List<DeclName> getNamesets() {
    return namesets_.peek();
  }

  public List<ActionInfo> getActions() {
    return actions_.peek();
  }

  public List<NameTypePair> getStateVars() {
    return stateVars_.peek();
  }

  public List<ActionPara> getOnTheFlyActions() {
    return onTheFlyActions_.peek();
  }

  public List<NameTypePair> getUsedChans() {
    return usedChans_.peek();
  }

  public List<DeclName> getGenericImplicitChans() {
    return genericImplicitChans_.peek();
  }
  
  public List<NameTypePair> getLocalVars() {
    return localVars_.peek();
  }
 
  public void enterScope()
  {
    List<DeclName> nameset = new ArrayList<DeclName>();
    namesets_.push(nameset);
    List<ActionInfo> action = new ArrayList<ActionInfo>();
    actions_.push(action);
    List<NameTypePair> local = new ArrayList<NameTypePair>();
    stateVars_.push(local);
    List<ActionPara> onTheFly = new ArrayList<ActionPara>();
    onTheFlyActions_.push(onTheFly);
    List<NameTypePair> usedChans = new ArrayList<NameTypePair>();
    usedChans_.push(usedChans);
    List<DeclName> genericImplicitChans = new ArrayList<DeclName>();
    genericImplicitChans_.push(genericImplicitChans);
    List<NameTypePair> paramsIndexes = new ArrayList<NameTypePair>();
  }
  
  public void enterScopeLocalVars() {
    List<NameTypePair> vars = new ArrayList<NameTypePair>();
    localVars_.push(vars);
  }

  public void exitScope()
  {
    namesets_.pop();
    actions_.pop();
    stateVars_.pop();
    onTheFlyActions_.pop();
    usedChans_.pop();
    genericImplicitChans_.pop();
  }
  
  public void exitScopeLocalVars() {
    localVars_.pop();
  }

  public boolean isNameSet(DeclName name){
    boolean result = false;
    List<DeclName> namesets = namesets_.peek();
    for (DeclName decl : namesets) {
      if(compareDeclName(decl, name, false)) {
        result = true;
        break;
      }
    }
    return result;
  }
  
  public boolean isStateVar(DeclName name){
    boolean result = false;
    List<NameTypePair> locals = stateVars_.peek();
    for (NameTypePair var : locals) {
      DeclName decl = var.getName();
      if(compareDeclName(decl, name, false)) {
        result = true;
        break;
      }
    }
    return result;
  }

  public boolean isLocalVar(DeclName name){
    boolean result = false;
    for (List<NameTypePair> list : localVars_) {
      for (NameTypePair pair : list) {
        if (compareDeclName(pair.getName(), name, false)) {
          result = true;
          break;
        }
      }
    }
    return result;
  }

  public boolean isAction(DeclName name){
    boolean result = false;
    List<ActionInfo> actions = actions_.peek();
    for (ActionInfo action : actions) {
      DeclName decl = action.getActionName();
      if(compareDeclName(decl, name, false)) {
        result = true;
        break;
      }
    }
    return result;
  }
  
  public boolean addAction(DeclName declName)
  {
    boolean result = true;
    List<ActionInfo> actions = actions_.peek();
    for (ActionInfo action : actions) {
      if(compareDeclName(action.getActionName(), declName, false)) {
        result = false;
      }
    }

    if(result){
      ActionInfo insert = new ActionInfo(declName);
      actions.add(insert);
    }
    return result;
  }
  
  public ActionInfo getActionInfo(DeclName name) {
    ActionInfo result = null;
    List<ActionInfo> actions = actions_.peek();
    for (ActionInfo action : actions) {
      if(compareDeclName(action.getActionName(), name, false)) {
        result = action;
      }
    }
    return result;
  }
  
  public boolean addStateVar(NameTypePair pair)
  {
    boolean result = true;
    DeclName name = pair.getName();
    List<NameTypePair> locals = stateVars_.peek();
    for (NameTypePair local : locals) {
      if(compareDeclName(local.getName(), name, false)) {
        result = false;
      } 
    }

    if(result) {
      locals.add(pair);
      localDefs_.add(pair);
      //ARRUMADINHO TEMPORÁRIO, ATÉ RESOLVER A QUESTÃO DOS STROKES
      // COLOCAR TAMBÉM ? E ! ?????
      DeclName primedVar = circusFactory_.createDeclName(pair.getName().getWord() + "'", null, null);
      localDefs_.add(primedVar, pair.getType());
    }
        
    return result;
  }
  
  public boolean addLocalVar(NameTypePair pair)
  {
    boolean result = true;
    DeclName name = pair.getName();
    List<NameTypePair> locals = localVars_.peek();
    for (NameTypePair local : locals) {
      if(compareDeclName(local.getName(), name, false)) {
        result = false;
      } 
    }

    if(result) {
      locals.add(pair);
      DeclName primedVar = circusFactory_.createDeclName(pair.getName().getWord() + "'", null, null);
      NameTypePair primedPair = circusFactory_.createNameTypePair(primedVar, pair.getType());
      locals.add(primedPair);
    }
        
    return result;
  }

  public boolean addStateVars(List<NameTypePair> vars)
  {
    boolean result = true;
    for (NameTypePair local : vars) {
      result = addStateVar(local);
      if(!result) {
        break;
      }
    }
    return result;
  }

  public boolean addLocalVars(List<NameTypePair> vars)
  {
    boolean result = true;
    for (NameTypePair local : vars) {
      result = addLocalVar(local);
      if(!result) {
        break;
      }
    }
    return result;
  }

  public boolean addNameSet(DeclName declName)
  {
    boolean result = true;
    List<DeclName> namesets = namesets_.peek();
    for (DeclName nameset : namesets) {
      if(compareDeclName(nameset, declName, false)) {
        result = false;
      }
    }

    if(result){
      namesets.add(declName);
    }
    
    return result;
  }
  
  public Type getStateVarType(DeclName name) {
    Type result = null;
    List<NameTypePair> locals = stateVars_.peek();
    for(NameTypePair pair : locals){
      if(compareDeclName(pair.getName(), name, false)) {
        result = pair.getType();
        break;
      }
    }
    return result;
  }
  
  public Type getLocalVarType(DeclName name) {
    Type result = null;
    List<NameTypePair> locals = localVars_.peek();
    for(NameTypePair pair : locals){
      if(compareDeclName(pair.getName(), name, false)) {
        result = pair.getType();
        break;
      }
    }
    return result;
  }

  public boolean isParamAction(DeclName name) {
    boolean result = false;
    List<ActionInfo> actions = actions_.peek();
    for (ActionInfo action : actions) {
      DeclName decl = action.getActionName();
      if(compareDeclName(decl, name, false)) {
        result = action.isParam();
        break;
      }
    }
    return result;
  }

  public void addUsedChans(List<NameTypePair> chans) {
    List<NameTypePair> usedChans = usedChans_.peek();
    for(NameTypePair pair : chans) {
      if(!usedChans.contains(pair)) {
        usedChans.add(pair);
      }
    }
  }

  public void addGenericImplicitChan(DeclName name) {
    List<DeclName> genericChans = genericImplicitChans_.peek();
    if(!genericChans.contains(name)) {
      genericChans.add(name);
    }
  }
  
  public void setActionType(DeclName name, ActionType type) {
    List<ActionInfo> actions = actions_.peek();
    for (ActionInfo action : actions) {
      DeclName decl = action.getActionName();
      if(compareDeclName(decl, name, false)) {
        action.setActionType(type);
        break;
      }
    }
  }
  
  public ActionType getActionType(DeclName name) {
    ActionType result = null;
    ActionInfo info = getActionInfo(name);
    
    if(info != null) {
      result = info.getActionType();
    }
    return result;
  }
  
}
