/**
 *  Compares the two ExprResults based on XPath 1.0 Recommendation (section 3.4)
 */
bool RelationalExpr::compareResults(txIEvalContext* aContext,
                                    txAExprResult* aLeft,
                                    txAExprResult* aRight) {
  short ltype = aLeft->getResultType();
  short rtype = aRight->getResultType();
  nsresult rv = NS_OK;

  // Handle case for just Left NodeSet or Both NodeSets
  if (ltype == txAExprResult::NODESET) {
    if (rtype == txAExprResult::BOOLEAN) {
      BooleanResult leftBool(aLeft->booleanValue());
      return compareResults(aContext, &leftBool, aRight);
    }

    txNodeSet* nodeSet = static_cast<txNodeSet*>(aLeft);
    RefPtr<StringResult> strResult;
    rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
    NS_ENSURE_SUCCESS(rv, false);

    int32_t i;
    for (i = 0; i < nodeSet->size(); ++i) {
      strResult->mValue.Truncate();
      txXPathNodeUtils::appendNodeValue(nodeSet->get(i), strResult->mValue);
      if (compareResults(aContext, strResult, aRight)) {
        return true;
      }
    }

    return false;
  }

  // Handle case for Just Right NodeSet
  if (rtype == txAExprResult::NODESET) {
    if (ltype == txAExprResult::BOOLEAN) {
      BooleanResult rightBool(aRight->booleanValue());
      return compareResults(aContext, aLeft, &rightBool);
    }

    txNodeSet* nodeSet = static_cast<txNodeSet*>(aRight);
    RefPtr<StringResult> strResult;
    rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
    NS_ENSURE_SUCCESS(rv, false);

    int32_t i;
    for (i = 0; i < nodeSet->size(); ++i) {
      strResult->mValue.Truncate();
      txXPathNodeUtils::appendNodeValue(nodeSet->get(i), strResult->mValue);
      if (compareResults(aContext, aLeft, strResult)) {
        return true;
      }
    }

    return false;
  }

  // Neither is a NodeSet
  if (mOp == EQUAL || mOp == NOT_EQUAL) {
    bool result;
    const nsString *lString, *rString;

    // If either is a bool, compare as bools.
    if (ltype == txAExprResult::BOOLEAN || rtype == txAExprResult::BOOLEAN) {
      result = aLeft->booleanValue() == aRight->booleanValue();
    }

    // If either is a number, compare as numbers.
    else if (ltype == txAExprResult::NUMBER || rtype == txAExprResult::NUMBER) {
      double lval = aLeft->numberValue();
      double rval = aRight->numberValue();
      result = (lval == rval);
    }

    // Otherwise compare as strings. Try to use the stringobject in
    // StringResult if possible since that is a common case.
    else if ((lString = aLeft->stringValuePointer())) {
      if ((rString = aRight->stringValuePointer())) {
        result = lString->Equals(*rString);
      } else {
        nsAutoString rStr;
        aRight->stringValue(rStr);
        result = lString->Equals(rStr);
      }
    } else if ((rString = aRight->stringValuePointer())) {
      nsAutoString lStr;
      aLeft->stringValue(lStr);
      result = rString->Equals(lStr);
    } else {
      nsAutoString lStr, rStr;
      aLeft->stringValue(lStr);
      aRight->stringValue(rStr);
      result = lStr.Equals(rStr);
    }

    return mOp == EQUAL ? result : !result;
  }

  double leftDbl = aLeft->numberValue();
  double rightDbl = aRight->numberValue();
  switch (mOp) {
    case LESS_THAN: {
      return (leftDbl < rightDbl);
    }
    case LESS_OR_EQUAL: {
      return (leftDbl <= rightDbl);
    }
    case GREATER_THAN: {
      return (leftDbl > rightDbl);
    }
    case GREATER_OR_EQUAL: {
      return (leftDbl >= rightDbl);
    }
    default: { MOZ_ASSERT_UNREACHABLE("We should have caught all cases"); }
  }

  return false;
}
/**
 *  Compares the two ExprResults based on XPath 1.0 Recommendation (section 3.4)
 */
PRBool
RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
                               txAExprResult* aRight)
{
    short ltype = aLeft->getResultType();
    short rtype = aRight->getResultType();
    nsresult rv = NS_OK;

    // Handle case for just Left NodeSet or Both NodeSets
    if (ltype == txAExprResult::NODESET) {
        if (rtype == txAExprResult::BOOLEAN) {
            BooleanResult leftBool(aLeft->booleanValue());
            return compareResults(aContext, &leftBool, aRight);
        }

        txNodeSet* nodeSet = static_cast<txNodeSet*>(aLeft);
        nsRefPtr<StringResult> strResult;
        rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
        NS_ENSURE_SUCCESS(rv, PR_FALSE);

        PRInt32 i;
        for (i = 0; i < nodeSet->size(); ++i) {
            strResult->mValue.Truncate();
            txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
                                              strResult->mValue);
            if (compareResults(aContext, strResult, aRight)) {
                return PR_TRUE;
            }
        }

        return PR_FALSE;
    }

    // Handle case for Just Right NodeSet
    if (rtype == txAExprResult::NODESET) {
        if (ltype == txAExprResult::BOOLEAN) {
            BooleanResult rightBool(aRight->booleanValue());
            return compareResults(aContext, aLeft, &rightBool);
        }

        txNodeSet* nodeSet = static_cast<txNodeSet*>(aRight);
        nsRefPtr<StringResult> strResult;
        rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
        NS_ENSURE_SUCCESS(rv, PR_FALSE);

        PRInt32 i;
        for (i = 0; i < nodeSet->size(); ++i) {
            strResult->mValue.Truncate();
            txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
                                              strResult->mValue);
            if (compareResults(aContext, aLeft, strResult)) {
                return PR_TRUE;
            }
        }

        return PR_FALSE;
    }

    // Neither is a NodeSet
    if (mOp == EQUAL || mOp == NOT_EQUAL) {
        PRBool result;
        const nsString *lString, *rString;

        // If either is a bool, compare as bools.
        if (ltype == txAExprResult::BOOLEAN ||
            rtype == txAExprResult::BOOLEAN) {
            result = aLeft->booleanValue() == aRight->booleanValue();
        }

        // If either is a number, compare as numbers.
        else if (ltype == txAExprResult::NUMBER ||
                 rtype == txAExprResult::NUMBER) {
            double lval = aLeft->numberValue();
            double rval = aRight->numberValue();
            result = TX_DOUBLE_COMPARE(lval, ==, rval);
        }