/**
   * It parses the rule logical description to create the corresponding node conditions. i.e. ((A
   * and B ) or C) -> is parsed as: node_1 represents condition "A", node_2 represents condition
   * "B", node_3 represents expression "(node_1 and node_2)", node_4 represents condition "C" and
   * node_5 represents expression "(node_3 or node_4)". For example,a condition could be "has some
   * BRCA1_1"
   *
   * @param nodeExpression The logical description of the rule o a subsection of the rule
   */
  private NodeCondition getTypeNode(String nodeExpression) throws BadRuleDefinitionException {
    nodeExpression = nodeExpression.trim();
    String mainType = "";
    String mainNumber = "";
    String mainElement = "";
    String mainQuality = "";
    ArrayList<NodeCondition> mainListNodes = null;

    while (nodeExpression.length() > 0) {
      if (nodeExpression.startsWith("has")) {
        String hasType = "";
        String hasNumber = "";
        String hasElement = "";
        String hasQuality = "";
        ArrayList<NodeCondition> hasListNodes = null;

        nodeExpression = nodeExpression.substring(nodeExpression.indexOf("has") + 3).trim();
        if (nodeExpression.startsWith("some")) {
          hasType = "some";
          nodeExpression = nodeExpression.substring(nodeExpression.indexOf("some") + 4).trim();
        }
        if (nodeExpression.startsWith("min")) {
          hasType = "min";
          nodeExpression = nodeExpression.substring(nodeExpression.indexOf("min") + 3).trim();
          hasNumber = nodeExpression.substring(0, nodeExpression.indexOf(" "));
          nodeExpression = nodeExpression.substring(nodeExpression.indexOf(" ") + 1).trim();
        }
        if (nodeExpression.startsWith("exactly")) {
          hasType = "exactly";
          nodeExpression = nodeExpression.substring(nodeExpression.indexOf("exactly") + 7).trim();
          hasNumber = nodeExpression.substring(0, nodeExpression.indexOf(" "));
          nodeExpression = nodeExpression.substring(nodeExpression.indexOf(" ") + 1).trim();
        }
        if (nodeExpression.startsWith("(")) {
          hasListNodes = new ArrayList<NodeCondition>();
          String listElements = nodeExpression.substring(1, nodeExpression.indexOf(")")).trim();
          nodeExpression = nodeExpression.substring(nodeExpression.indexOf(")") + 1).trim();

          while (listElements.length() > 0) {
            if ((listElements.startsWith("and") && hasQuality.equals("or"))
                || (listElements.startsWith("and") && hasQuality.equals("or"))) {
              throw new BadRuleDefinitionException(
                  "and/or inconsistency in has expression condition: " + nodeExpression);
              // System.out.println("ERROR: and/or inconsistency in has expression condition");
              // return null;
            }
            if (listElements.startsWith("and")) {
              hasQuality = "and";
              listElements = listElements.substring(listElements.indexOf("and") + 3).trim();
              continue;
            }
            if (listElements.startsWith("or")) {
              hasQuality = "or";
              listElements = listElements.substring(listElements.indexOf("or") + 2).trim();
              continue;
            }
            String nodeElement = "";
            if (listElements.indexOf(" ") >= 0) {
              nodeElement = listElements.substring(0, listElements.indexOf(" ")).trim();
              listElements = listElements.substring(listElements.indexOf(" ") + 1).trim();
            } else {
              nodeElement = listElements;
              listElements = "";
            }

            NodeCondition subNode = new NodeCondition();
            subNode.setElement(nodeElement);
            hasListNodes.add(subNode);
          }
        } else {
          if (nodeExpression.indexOf(" ") >= 0) {
            hasElement = nodeExpression.substring(0, nodeExpression.indexOf(" ")).trim();
            nodeExpression = nodeExpression.substring(nodeExpression.indexOf(" ") + 1).trim();
          } else {
            hasElement = nodeExpression;
            nodeExpression = "";
          }
        }

        NodeCondition node = new NodeCondition();
        node.setElement(hasElement);
        node.setQuality(hasQuality);
        node.setType(hasType);
        node.setNumber(hasNumber);
        if (hasListNodes != null) {
          for (NodeCondition subNode : hasListNodes) {
            node.addNode(subNode);
          }
        }
        if (mainListNodes == null) mainListNodes = new ArrayList<NodeCondition>();
        mainListNodes.add(node);
      } else {
        if (nodeExpression.startsWith("and") || nodeExpression.startsWith("or")) {
          if ((nodeExpression.startsWith("or") && mainQuality.equals("and"))
              || (nodeExpression.startsWith("and") && mainQuality.equals("or"))) {
            throw new BadRuleDefinitionException(
                "and/or inconsistency in has expression condition: " + nodeExpression);
            // System.out.println("ERROR: and/or inconsistency");
            // return null;
          } else {
            if (nodeExpression.startsWith("or")) {
              mainQuality = "or";
              nodeExpression = nodeExpression.substring(nodeExpression.indexOf("or") + 2).trim();
            }
            if (nodeExpression.startsWith("and")) {
              mainQuality = "and";
              nodeExpression = nodeExpression.substring(nodeExpression.indexOf("and") + 3).trim();
            }
          }
        } else {
          if (nodeExpression.startsWith("(")) {
            int nCondition = 1;
            String subNodeString = nodeExpression.substring(1).trim();
            String completeNode = "";
            while (nCondition > 0) {
              if (subNodeString.indexOf("(") < subNodeString.indexOf(")")
                  && subNodeString.indexOf("(") >= 0) {
                nCondition++;
                if (subNodeString.startsWith("(")) {
                  completeNode += "(";
                  subNodeString = subNodeString.substring(1).trim();
                } else {
                  completeNode +=
                      " " + subNodeString.substring(0, subNodeString.indexOf("(") + 1).trim();
                  subNodeString = subNodeString.substring(subNodeString.indexOf("(") + 1).trim();
                }
              } else {
                nCondition--;
                if (nCondition > 0) {
                  completeNode +=
                      " " + subNodeString.substring(0, subNodeString.indexOf(")") + 1).trim();
                } else {
                  completeNode +=
                      " " + subNodeString.substring(0, subNodeString.indexOf(")")).trim();
                }
                subNodeString = subNodeString.substring(subNodeString.indexOf(")") + 1).trim();
              }
            }
            NodeCondition nodeCondition = getTypeNode(completeNode);
            if (mainListNodes == null) mainListNodes = new ArrayList<NodeCondition>();
            mainListNodes.add(nodeCondition);
            nodeExpression = subNodeString;
          } else {
            if (nodeExpression.indexOf(" ") >= 0) {
              String element = nodeExpression.substring(0, nodeExpression.indexOf(" ")).trim();
              nodeExpression = nodeExpression.substring(nodeExpression.indexOf(" ") + 1).trim();
              NodeCondition node = new NodeCondition();
              node.setElement(element);

              if (mainListNodes == null) mainListNodes = new ArrayList<NodeCondition>();
              mainListNodes.add(node);
            } else {
              mainElement = nodeExpression;
              nodeExpression = "";
            }
          }
        }
      }
    }
    NodeCondition mainNode = new NodeCondition();

    mainNode.setElement(mainElement);
    mainNode.setNumber(mainNumber);
    mainNode.setQuality(mainQuality);
    mainNode.setType(mainType);
    if (mainListNodes != null) {
      for (NodeCondition subnodes : mainListNodes) {
        mainNode.addNode(subnodes);
      }
    }
    return mainNode;
  }