content: package org.apache.lucene.queryparser.flexible.aqp.nodes;
  
  import org.antlr.runtime.CommonToken;
  import org.apache.lucene.queryparser.flexible.aqp.util.AqpCommonTree;
  import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
  import org.apache.lucene.queryparser.flexible.core.nodes.QueryNodeImpl;
  import org.apache.lucene.queryparser.flexible.core.parser.EscapeQuerySyntax;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * When Aqp parser starts processing the AST (abstract syntax tree)
   * every node in the tree is made of {@link AqpANTLRNode} and it wraps
   * the {@link AqpCommonTree} through which you can access information
   * about the string, its position, type etc... these are courtesy of
   * ANTLR.
   * <p>
   * We provide a few utility methods for setting different attributes
   * of the original ANTLR object.
   */
  public class AqpANTLRNode extends QueryNodeImpl {
  
      private static final long serialVersionUID = 5128762709928473351L;
  
      private final AqpCommonTree tree;
  
      private int tokenType;
  
      private String tokenLabel;
  
      private String tokenName;
  
      private String tokenInput = null;
  
      private boolean isCloning;
  
      /**
       * @param node - AST node
       */
      public AqpANTLRNode(AqpCommonTree node) {
  
          tree = node;
          String input = node.getTokenInput();
  
          if (input != null) {
              setTokenInput(input);
          }
  
          setTokenLabel(node.getTokenLabel());
  
          setTokenType(node.getTokenType());
  
          setTokenName(node.getTypeLabel());
  
          if (node.getChildCount() > 0) {
              setLeaf(false);
              allocate();
          }
      }
  
      public CharSequence toQueryString(EscapeQuerySyntax escaper) {
          if (getTokenInput() != null) {
              return "(" + getTokenLabel() + ":" + getTokenInput() + ")";
          } else {
              return getTokenLabel();
          }
      }
  
  
      public String escapeXmlVal(String v) {
          return v.replace("&", "&amp;").replace("\"", "&quot;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;");
      }
  
      public String escapeJsonVal(String v) {
          return v.replace("\"", "\\\""); //replace("\\", "\\\\").replace("\"", "\\\"").replace("'", "\\'").replace("\t", "\\t").replace("\n", "\\n");
      }
  
      /**
       * Method to transform the tree into JSON - so that we can send it to the
       * javascript clients
       *
       * @return json representation of the node
       */
      public String toJson() {
          return toJson(0);
      }
  
      public String toJson(int level) {
          StringBuffer buf = new StringBuffer();
          buf.append("\n");
          for (int i = 0; i < level; i++) {
              buf.append(" ");
          }
  
          buf.append("{\"name\":\"");
          buf.append(getTokenName());
          buf.append("\"");
  
          if (getTokenInput() != null) {
              buf.append(", \"input\":\"");
              buf.append(escapeJsonVal(getTokenInput()));
              buf.append("\", \"start\":" + getTokenStart());
              buf.append(", \"end\":" + getTokenEnd());
          } else {
              buf.append(", \"label\":\"");
              buf.append(getTokenLabel());
              buf.append("\"");
          }
  
          List<QueryNode> children = this.getChildren();
  
          if (children != null) {
              buf.append(", \"children\": [");
              boolean notFirst = false;
              for (QueryNode child : children) {
                  if (notFirst)
                      buf.append(",");
                  if (child instanceof AqpANTLRNode) {
                      buf.append(((AqpANTLRNode) child).toJson(level + 4));
                  } else {
                      buf.append("{\"xvalue\":\"");
                      buf.append(escapeJsonVal(child.toString()));
                      buf.append("\"}");
                  }
                  notFirst = true;
              }
              buf.append("]");
          }
  
          if (isLeaf()) {
              buf.append("}");
          } else {
              buf.append("\n");
              for (int i = 0; i < level; i++) {
                  buf.append(" ");
              }
              buf.append("}");
          }
  
          return buf.toString();
      }
  
      public String toStringNodeOnly() {
          if (getTokenInput() != null) {
              return "<ast" + getTokenName() + " value=\"" + escapeXmlVal(getTokenInput())
                      + "\" start=\"" + getTokenStart() + "\" end=\"" + getTokenEnd()
                      + "\" />";
          } else {
              return "<ast" + getTokenName() + " type=\"" + getTokenLabel() + "\" />";
          }
      }
  
      public String toString() {
          return toString(0);
      }
  
      public String toString(int level) {
          StringBuffer buf = new StringBuffer();
          buf.append("\n");
          for (int i = 0; i < level; i++) {
              buf.append(" ");
          }
  
          buf.append("<ast" + getTokenName() + " ");
  
          if (getTokenInput() != null) {
              buf.append("value=\"" + escapeXmlVal(getTokenInput()) + "\" start=\"" + getTokenStart()
                      + "\" end=\"" + getTokenEnd() + "\"");
          } else {
              buf.append("label=\"" + getTokenLabel() + "\"");
          }
          buf.append(" name=\"" + getTokenName() + "\"" + " type=\"" + getTokenType()
                  + "\" ");
  
          List<QueryNode> children = this.getChildren();
  
          if (children != null) {
              buf.append(">");
              for (QueryNode child : children) {
                  if (child instanceof AqpANTLRNode) {
                      buf.append(((AqpANTLRNode) child).toString(level + 4));
                  } else {
                      buf.append(child.toString());
                  }
              }
          }
  
          if (isLeaf()) {
              buf.append("/>");
          } else {
              buf.append("\n");
              for (int i = 0; i < level; i++) {
                  buf.append(" ");
              }
              buf.append("</ast" + getTokenName() + ">");
          }
  
          return buf.toString();
      }
  
      public int getTokenType() {
          return tokenType;
      }
  
      public void setTokenType(int tokenType) {
          this.tokenType = tokenType;
      }
  
      /**
       * Label is what is displayed in the AST tree, for example and, And, AND will
       * all have label=AND
       * <p>
       * (But their internal name is an 'OPERATOR')
       *
       * @return string, token label
       */
      public String getTokenLabel() {
          return tokenLabel;
      }
  
      /**
       * Label is what is displayed in the AST tree, for example and, And, AND will
       * all have label=AND
       * <p>
       * (But their internal name is an 'OPERATOR')
       */
      public void setTokenLabel(String tokenLabel) {
          this.tokenLabel = tokenLabel;
      }
  
      /**
       * Name is the internal token name, for example and, And, AND will
       * all have name=OPERATOR
       */
      public String getTokenName() {
          return tokenName;
      }
  
      /**
       * Name is the name of the group, ie. 'AND' is an OPERATOR (but its label
       * says: 'AND')
       *
       * @param tokenName string to set
       */
      public void setTokenName(String tokenName) {
          this.tokenName = tokenName;
      }
  
      public String getTokenInput() {
          return tokenInput;
      }
  
      public void setTokenInput(String tokenInput) {
          this.tokenInput = tokenInput;
      }
  
      public int getTokenStart() {
          return tree.getStartIndex();
      }
  
      /*
       * I'm confused, this method added just now,
       * there should be only one method for setting
       */
      public void setTokenStart(int start) {
          tree.setStartIndex(start);
          tree.getToken().setCharPositionInLine(start);
      }
  
      public int getTokenEnd() {
          return tree.getStopIndex();
      }
  
      public AqpCommonTree getTree() {
          return tree;
      }
  
      public int getInputTokenStart() {
          return tree.getToken().getCharPositionInLine();// getStartIndex();
      }
  
      public int getInputTokenEnd() {
          return ((CommonToken) tree.getToken()).getStopIndex();
      }
  
      public void setInputTokenEnd(int stop) {
          ((CommonToken) tree.getToken()).setStopIndex(stop);
      }
  
      public void setInputTokenStart(int start) {
          ((CommonToken) tree.getToken()).setStartIndex(start);
      }
  
      public AqpANTLRNode getChild(String tokenLabel) {
          List<QueryNode> children = getChildren();
          if (children != null) {
              for (QueryNode child : children) {
                  AqpANTLRNode n = (AqpANTLRNode) child;
                  if (n.getTokenLabel().equals(tokenLabel)) {
                      return n;
                  }
              }
  
          }
          return null;
      }
  
      public int hasTokenName(String tokenName, int level) {
          List<QueryNode> children = getChildren();
          if (children != null) {
              for (QueryNode child : children) {
                  if (child instanceof AqpANTLRNode) {
                      AqpANTLRNode n = (AqpANTLRNode) child;
                      if (n.getTokenLabel().equals(tokenName)) {
                          return level + 1;
                      }
                      int nl = n.hasTokenName(tokenName, level + 1);
                      if (nl > level + 1)
                          return nl;
                  }
              }
          }
          return level;
      }
  
      public AqpANTLRNode findChild(String tokenLabel) {
          ArrayList<QueryNode> lst = new ArrayList<QueryNode>();
          findChild(this, tokenLabel, lst);
  
          if (lst.size() == 1) {
              return (AqpANTLRNode) lst.get(0);
          } else if (lst.size() > 1) {
              throw new RuntimeException(
                      "This method is not meant to search for n>1 nodes");
          }
          return null;
      }
  
      private void findChild(QueryNode node, String tokenLabel,
                             ArrayList<QueryNode> lst) {
          if (((AqpANTLRNode) node).getTokenLabel().equals(tokenLabel)) {
              lst.add(node);
          } else {
              if (!node.isLeaf()) {
                  for (QueryNode child : node.getChildren()) {
                      findChild(child, tokenLabel, lst);
                  }
              }
          }
      }
  
      public Float getTokenInputFloat() {
          if (this.tokenInput != null) {
              return Float.valueOf(this.tokenInput);
          }
          return null;
      }
  
  
  }
  