/**
   * Gets Xpath results
   *
   * @param contextNode
   * @param xpathValue
   * @return
   * @throws XPathExpressionException
   */
  private NodeList getXPathResults(Node contextNode, String xpathValue)
      throws XPathExpressionException {

    XPathFactory factory = XPathFactory.newInstance();
    XPath xpath = factory.newXPath();

    // see if the request root is in a namespace
    String namespace = contextNode.getNamespaceURI();
    // name spaces are used, so we need to lookup the correct
    // prefix to use in the search string
    NamedNodeMap namedNodeMap = contextNode.getAttributes();

    Map<String, String> nsMap = new HashMap<String, String>();

    for (int i = 0; i < namedNodeMap.getLength(); i++) {
      Node n = namedNodeMap.item(i);
      // we found the matching namespace, so get the prefix
      // and then break out
      String prefix = DOMHelper.getLocalName(n);
      String nodeValue = n.getNodeValue();
      nsMap.put(prefix, nodeValue);
    }

    // if there is not any namespace is defined for content element, default
    // XACML request
    // name space would be there.
    if (XACMLConstants.REQUEST_CONTEXT_3_0_IDENTIFIER.equals(namespace)
        || XACMLConstants.REQUEST_CONTEXT_2_0_IDENTIFIER.equals(namespace)
        || XACMLConstants.REQUEST_CONTEXT_1_0_IDENTIFIER.equals(namespace)) {
      nsMap.put("xacml", namespace);
    }

    NamespaceContext namespaceContext = new DefaultNamespaceContext(nsMap);
    xpath.setNamespaceContext(namespaceContext);

    XPathExpression expression = xpath.compile(xpathValue);
    return (NodeList) expression.evaluate(contextNode, XPathConstants.NODESET);
  }
  @SuppressWarnings("unused")
  @Override
  public EvaluationResult findAttribute(
      String contextPath,
      URI attributeType,
      String contextSelector,
      Node root,
      EvaluationCtx context,
      String xpathVersion) {

    Node contextNode = null;
    NamespaceContext namespaceContext = null;

    System.out.println(
        "Context path ==> "
            + contextPath
            + " AttributeType ==> "
            + attributeType
            + " Context Selector ==> "
            + contextSelector
            + " Root Node name ==> "
            + root.getNodeName()
            + " root node type==> "
            + root.getNodeType()
            + " root node value==> "
            + root.getNodeValue()
            + " Context ==> "
            + context
            + " XPath version ==> "
            + xpathVersion);

    if (root == null) {
      System.out.println("Root node is null ");

      // root == null means there is not content element defined with the
      // attributes element
      // therefore complete request is evaluated.
      // get the DOM root of the request document
      contextNode = context.getRequestRoot();
    } else if (contextSelector != null) {
      System.out.println("Content selector is not null ");

      // root != null means content element is there. we can find the
      // context node by
      // evaluating the contextSelector

      // 1st assume context node as the root

      // TODO - Check if the contextNode should be assigned to root

      contextNode = root;

      XPathFactory factory = XPathFactory.newInstance();
      XPath xpath = factory.newXPath();

      // see if the request root is in a namespace
      String namespace = null;
      if (contextNode != null) {
        namespace = contextNode.getNamespaceURI();
        System.out.println(" nameSpace ==> " + contextNode);
      }
      // name spaces are used, so we need to lookup the correct
      // prefix to use in the search string
      NamedNodeMap namedNodeMap = contextNode.getAttributes();

      Map<String, String> nsMap = new HashMap<String, String>();

      for (int i = 0; i < namedNodeMap.getLength(); i++) {
        Node n = namedNodeMap.item(i);
        // we found the matching namespace, so get the prefix
        // and then break out
        String prefix = DOMHelper.getLocalName(n);
        String nodeValue = n.getNodeValue();
        System.out.println("nodeValue of nameaspace ==> " + nodeValue);
        nsMap.put(prefix, nodeValue);
      }

      // if there is not any namespace is defined for content element,
      // default XACML request
      // name space would be there.
      if (XACMLConstants.REQUEST_CONTEXT_3_0_IDENTIFIER.equals(namespace)
          || XACMLConstants.REQUEST_CONTEXT_2_0_IDENTIFIER.equals(namespace)
          || XACMLConstants.REQUEST_CONTEXT_1_0_IDENTIFIER.equals(namespace)) {
        nsMap.put("xacml", namespace);
      }

      namespaceContext = new DefaultNamespaceContext(nsMap);
      xpath.setNamespaceContext(namespaceContext);

      try {
        XPathExpression expression = xpath.compile(contextSelector);
        NodeList result = (NodeList) expression.evaluate(contextNode, XPathConstants.NODESET);
        if (result == null || result.getLength() == 0) {
          throw new Exception("No node is found from context selector id evaluation");
        } else if (result.getLength() != 1) {
          throw new Exception("More than one node is found from context selector id evaluation");
        }
        contextNode = result.item(0);
      } catch (Exception e) {
        List<String> codes = new ArrayList<String>();
        codes.add(Status.STATUS_SYNTAX_ERROR);
        Status status = new Status(codes, e.getMessage());
        return new EvaluationResult(status);
      }
    } else {
      contextNode = root;
    }

    XPathFactory factory = XPathFactory.newInstance();
    XPath xpath = factory.newXPath();

    if (namespaceContext == null) {

      // see if the request root is in a namespace
      String namespace = null;
      if (contextNode != null) {
        namespace = contextNode.getNamespaceURI();
      }
      // name spaces are used, so we need to lookup the correct
      // prefix to use in the search string
      NamedNodeMap namedNodeMap = contextNode.getAttributes();

      Map<String, String> nsMap = new HashMap<String, String>();

      for (int i = 0; i < namedNodeMap.getLength(); i++) {
        Node n = namedNodeMap.item(i);
        // we found the matching namespace, so get the prefix
        // and then break out
        String prefix = DOMHelper.getLocalName(n);
        String nodeValue = n.getNodeValue();
        nsMap.put(prefix, nodeValue);
      }

      // if there is not any namespace is defined for content element,
      // default XACML request
      // name space would be there.
      if (XACMLConstants.REQUEST_CONTEXT_3_0_IDENTIFIER.equals(namespace)
          || XACMLConstants.REQUEST_CONTEXT_2_0_IDENTIFIER.equals(namespace)
          || XACMLConstants.REQUEST_CONTEXT_1_0_IDENTIFIER.equals(namespace)) {
        nsMap.put("xacml", namespace);
      }

      namespaceContext = new DefaultNamespaceContext(nsMap);
    }

    xpath.setNamespaceContext(namespaceContext);

    NodeList matches;

    try {
      XPathExpression expression = xpath.compile(contextPath);
      matches = (NodeList) expression.evaluate(contextNode, XPathConstants.NODESET);
      if (matches == null || matches.getLength() < 1) {
        throw new Exception("No node is found from xpath evaluation");
      }
    } catch (XPathExpressionException e) {
      List<String> codes = new ArrayList<String>();
      codes.add(Status.STATUS_SYNTAX_ERROR);
      Status status = new Status(codes, e.getMessage());
      return new EvaluationResult(status);
    } catch (Exception e) {
      List<String> codes = new ArrayList<String>();
      codes.add(Status.STATUS_SYNTAX_ERROR);
      Status status = new Status(codes, e.getMessage());
      return new EvaluationResult(status);
    }

    if (matches.getLength() == 0) {
      // we didn't find anything, so we return an empty bag
      return new EvaluationResult(BagAttribute.createEmptyBag(attributeType));
    }

    // there was at least one match, so try to generate the values
    try {
      ArrayList<AttributeValue> list = new ArrayList<AttributeValue>();
      AttributeFactory attrFactory = Balana.getInstance().getAttributeFactory();

      for (int i = 0; i < matches.getLength(); i++) {
        String text = null;
        Node node = matches.item(i);
        short nodeType = node.getNodeType();

        // see if this is straight text, or a node with data under
        // it and then get the values accordingly
        if ((nodeType == Node.CDATA_SECTION_NODE)
            || (nodeType == Node.COMMENT_NODE)
            || (nodeType == Node.TEXT_NODE)
            || (nodeType == Node.ATTRIBUTE_NODE)) {
          // there is no child to this node
          text = node.getNodeValue();
        } else {
          // the data is in a child node
          text = node.getFirstChild().getNodeValue();
        }

        list.add(attrFactory.createValue(attributeType, text));
      }

      return new EvaluationResult(new BagAttribute(attributeType, list));

    } catch (ParsingException pe) {
      ArrayList<String> code = new ArrayList<String>();
      code.add(Status.STATUS_PROCESSING_ERROR);
      return new EvaluationResult(new Status(code, pe.getMessage()));
    } catch (UnknownIdentifierException uie) {
      ArrayList<String> code = new ArrayList<String>();
      code.add(Status.STATUS_PROCESSING_ERROR);
      return new EvaluationResult(new Status(code, "Unknown attribute type : " + attributeType));
    }
  }