/*
 * DeclChecker.java
 *
 * Created on 17 de Junho de 2005, 19:51
 *
 * 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;

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

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

import net.sourceforge.czt.z.ast.*;
import net.sourceforge.czt.circus.ast.*;
import net.sourceforge.czt.circus.visitor.ChannelDeclVisitor;
import net.sourceforge.czt.circus.visitor.QualifiedDeclVisitor;
import net.sourceforge.czt.z.visitor.DeclVisitor;

/**
 *
 * @author Manuela
 */
public class DeclChecker 
  extends Checker
  implements ChannelDeclVisitor,
             DeclVisitor,
             QualifiedDeclVisitor
{
    
  //a Z decl checker
  protected net.sourceforge.czt.typecheck.z.DeclChecker zDeclChecker_;

  public DeclChecker(TypeChecker typeChecker)
  {
    super(typeChecker);
    zDeclChecker_ =
      new net.sourceforge.czt.typecheck.z.DeclChecker(typeChecker);
  }
  
  // Declaration
  public Object visitDecl(Decl decl)
  {
    return decl.accept(zDeclChecker_);
  }

  // CDeclaration ::= N+
  // CDeclaration ::= N+ : Expression
  // CDeclaration ::= [N+]N+ : Expression
  //ok - verificado em 15/09/2005 às 10:54
  public Object visitChannelDecl(ChannelDecl term)
  {
    List<NameTypePair> pairs = new ArrayList<NameTypePair>();
    List<NameTypePair> allPairs = new ArrayList<NameTypePair>();

    VarDecl declChan = (VarDecl)term.getDecl();
    List<DeclName> genericParams = term.getDeclName();
    
    //we enter a new variable scope for the generic parameters
    typeEnv().enterScope();

    //add the parameters to the local type env
    //essa função já checa se os nomes não estão repetidos
    addGenParamTypes(genericParams);
    
    if(declChan.getExpr() != null) {
      pairs.addAll((List<NameTypePair>) declChan.accept(declChecker()));
    } else {
      DeclName name = factory().createDeclName("Synch", null, null);
      Type2 type = factory().createGivenType(name);
      //get the DeclNames
      List<DeclName> declNames = declChan.getDeclName();
      for (DeclName declName : declNames) {
        //add the name and its type to the list of NameTypePairs
        NameTypePair pair = factory().createNameTypePair(declName, type);
        pairs.add(pair);
      }
    }

    //exit the variable scope
    typeEnv().exitScope();
    
    // armazena os parametros genéricos para futura verificação
    setCurrentGenParams(genericParams);

    //if the name already exists globally, raise an error
    for (NameTypePair pair : pairs) {
      if (!genericParams.isEmpty()) {
        // Um canal só pode ser considerado genérico se o seu tipo for genérico
        Type2 chanType = (Type2)pair.getType();
        boolean isGeneric = ((Boolean)chanType.accept(channelDeclChecker())).booleanValue();
        
        if(isGeneric) {
          if (!addGenChannel(pair.getName(), pair.getType(), genericParams)) {  
            Object [] params = {pair.getName()};
            error(term, ErrorMessage.REDECLARED_CHANNEL_NAME, params);
          } 
        } else {
          if (!addChannel(pair.getName(), pair.getType())) {  
            Object [] params = {pair.getName()};
            error(term, ErrorMessage.REDECLARED_CHANNEL_NAME, params);
          }
        }

      } else {
        if (!addChannel(pair.getName(), pair.getType())) {  
          Object [] params = {pair.getName()};
          error(term, ErrorMessage.REDECLARED_CHANNEL_NAME, params);
        }
      }
      allPairs.add(pair);
    }

    return allPairs;
  }
    
  // QualifiedDeclaration :: = val Declaration
  // QualifiedDeclaration :: = res Declaration
  // QualifiedDeclaration :: = valres Declaration
  // QualifiedDeclaration :: = QualifiedDeclaration;QualifiedDeclaration
  //ok - verificado em 15/09/2005 às 11:06
  public Object visitQualifiedDecl(QualifiedDecl term)
  {
    List<NameTypePair> pairs = new ArrayList<NameTypePair>();
    List<NameTypePair> allPairs = new ArrayList<NameTypePair>();

    List<Decl> decls = term.getDeclarations();

    for(Decl decl : decls) {
      pairs = (List<NameTypePair>)decl.accept(declChecker());
      allPairs.addAll(pairs);
    }
    
    return allPairs;
  }

}
