/*
   * (non-Javadoc)
   * @see com.aptana.editor.js.parsing.ast.JSTreeWalker#visit(com.aptana.editor.js.parsing.ast.JSIdentifierNode)
   */
  @Override
  public void visit(JSIdentifierNode node) {
    String name = node.getText();
    Collection<PropertyElement> properties = null;

    if (this._scope != null && this._scope.hasSymbol(name)) {
      IParseNode parent = node.getParent();

      if (parent != null && parent.getNodeType() == IJSNodeTypes.PARAMETERS) {
        // special handling of parameters to potentially get the type
        // from documentation and to prevent an infinite loop since
        // parameters point to themselves in the symbol table
        this.addParameterTypes(node);
      } else {
        // Check the local scope for type first
        JSSymbolTypeInferrer symbolInferrer =
            new JSSymbolTypeInferrer(this._scope, this._index, this._location);
        PropertyElement property = symbolInferrer.getSymbolPropertyElement(name);
        if (property != null) {
          // We found a match in the local scope
          properties = CollectionsUtil.newList(property);
        } else {
          // No match in the local scope, query the globals in index
          properties = this._queryHelper.getGlobals(this._index, getProject(), getFileName(), name);
        }
      }
    } else {
      // Scope says it doesn't has a symbol with that name, so query the globals in index
      properties = this._queryHelper.getGlobals(this._index, getProject(), getFileName(), name);
    }

    // Hopefully we found at least one match...
    if (properties != null) {
      for (PropertyElement property : properties) {
        if (property instanceof FunctionElement) {
          FunctionElement function = (FunctionElement) property;
          for (String type : function.getSignatureTypes()) {
            this.addType(type);
          }
        } else {
          for (String type : property.getTypeNames()) {
            this.addType(type);
          }
        }
      }
    }
  }
  /**
   * addParameterTypes
   *
   * @param identifierNode
   */
  private void addParameterTypes(JSIdentifierNode identifierNode) {
    IParseNode parent = identifierNode.getParent();
    IParseNode grandparent = (parent != null) ? parent.getParent() : null;
    boolean foundType = false;

    if (grandparent != null && grandparent.getNodeType() == IJSNodeTypes.FUNCTION) {
      DocumentationBlock docs = ((JSNode) grandparent).getDocumentation();

      if (docs != null) {
        String name = identifierNode.getText();
        int index = identifierNode.getIndex();
        List<Tag> params = docs.getTags(TagType.PARAM);

        if (params != null && index < params.size()) {
          ParamTag param = (ParamTag) params.get(index);

          if (name.equals(param.getName())) {
            for (Type parameterType : param.getTypes()) {
              String type = parameterType.getName();

              // Fix up type names as might be necessary
              type = JSTypeMapper.getInstance().getMappedType(type);

              this.addType(type);
              foundType = true;
            }
          }
        }
      }
    }

    // Use "Object" as parameter type if we didn't find types by other
    // means
    if (!foundType) {
      this.addType(JSTypeConstants.DEFAULT_PARAMETER_TYPE);
    }
  }