MojoNewWhereMatcher::MatchResult MojoNewWhereMatcher::CheckClause(
	const MojObject& clause, const MojObject& response, MatchMode mode) const
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);

	if (clause.type() == MojObject::TypeArray) {
		return CheckClauses(clause, response, mode);
	} else if (clause.type() != MojObject::TypeObject) {
		throw std::runtime_error("Clauses must be either an object or array "
			"of objects");
	}

	LOG_AM_DEBUG("Checking clause '%s' against response '%s' (%s)",
		MojoObjectJson(clause).c_str(), MojoObjectJson(response).c_str(),
		(mode == AndMode) ? "and" : "or");

	if (clause.contains(_T("and"))) {
		MojObject andClause;
		clause.get(_T("and"), andClause);

		return CheckClause(andClause, response, AndMode);
	} else if (clause.contains(_T("or"))) {
		MojObject orClause;
		clause.get(_T("or"), orClause);

		return CheckClause(orClause, response, OrMode);
	}

	MojObject prop;
	bool found = clause.get(_T("prop"), prop);
	if (!found) {
		throw std::runtime_error("Clauses must contain \"and\", \"or\", "
			"or a comparison to make");
	}

	MojObject op;
	found = clause.get(_T("op"), op);
	if (!found) {
		throw std::runtime_error("Clauses must specify a comparison operation "
			"to perform");
	}

	MojObject val;
	found = clause.get(_T("val"), val);
	if (!found) {
		throw std::runtime_error("Clauses must specify a value to compare "
			"against");
	}

	MatchResult result = CheckProperty(prop, response, op, val, mode);

	LOG_AM_DEBUG("Where Trigger: Clause %s %s",
		MojoObjectJson(clause).c_str(), (result == Matched) ? "matched" :
	    "did not match");

	return result;
}
bool MojoWhereMatcher::CheckClauses(const MojObject& clauses,
	const MojObject& response) const
{
	MojLogTrace(s_log);

	if (clauses.type() == MojObject::TypeObject) {
		return CheckClause(clauses, response);
	} else if (clauses.type() == MojObject::TypeArray) {
		for (MojObject::ConstArrayIterator iter = clauses.arrayBegin();
			iter != clauses.arrayEnd(); ++iter) {
			if (!CheckClause(*iter, response)) {
				return false;
			}
		}
	} else {
		throw std::runtime_error("Clauses must consist of either a single "
			"where clause or array of where clauses");
	}

	return true;
}
MojoNewWhereMatcher::MatchResult MojoNewWhereMatcher::CheckClauses(
	const MojObject& clauses, const MojObject& response, MatchMode mode) const
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);

	if (clauses.type() == MojObject::TypeObject) {
		return CheckClause(clauses, response, mode);
	} else if (clauses.type() != MojObject::TypeArray) {
		throw std::runtime_error("Multiple clauses must be specified as an "
			"array of clauses");
	}

	LOG_AM_DEBUG("Checking clauses '%s' against response '%s' (%s)",
		MojoObjectJson(clauses).c_str(), MojoObjectJson(response).c_str(),
		(mode == AndMode) ? "and" : "or");

	for (MojObject::ConstArrayIterator iter = clauses.arrayBegin();
		iter != clauses.arrayEnd(); ++iter) {
		MatchResult result = CheckClause(*iter, response, mode);

		if (mode == AndMode) {
			if (result != Matched) {
				return NotMatched;
			}
		} else {
			if (result == Matched) {
				return Matched;
			}
		}
	}

	if (mode == AndMode) {
		return Matched;
	} else {
		return NotMatched;
	}
}
bool MojoNewWhereMatcher::Match(const MojObject& response)
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);

	MatchResult result = CheckClause(m_where, response, AndMode);
	if (result == Matched) {
		LOG_AM_DEBUG("Where Matcher: Response %s matches",
			MojoObjectJson(response).c_str());
		return true;
	} else {
		LOG_AM_DEBUG("Where Matcher: Response %s does not match",
			MojoObjectJson(response).c_str());
		return false;
	}
}
bool MojoNewWhereMatcher::Match(const MojObject& response)
{
	MojLogTrace(s_log);

	MatchResult result = CheckClause(m_where, response, AndMode);
	if (result == Matched) {
		MojLogInfo(s_log, _T("Where Matcher: Response %s matches"),
			MojoObjectJson(response).c_str());
		return true;
	} else {
		MojLogInfo(s_log, _T("Where Matcher: Response %s does not match"),
			MojoObjectJson(response).c_str());
		return false;
	}
}
MojoNewWhereMatcher::MatchResult MojoNewWhereMatcher::CheckMatch(
	const MojObject& rhs, const MojObject& op, const MojObject& val) const
{
	MojString opStr;
	MojErr err = op.stringValue(opStr);
	if (err) {
		throw std::runtime_error("Failed to convert operation to string "
			"value");
	}

	bool result;

	if (opStr == "<") {
		result = (rhs < val);
	} else if (opStr == "<=") {
		result = (rhs <= val);
	} else if (opStr == "=") {
		result = (rhs == val);
	} else if (opStr == "!=") {
		result = (rhs != val);
	} else if (opStr == ">=") {
		result = (rhs >= val);
	} else if (opStr == ">") {
		result = (rhs > val);
	} else if (opStr == "where") {
		result = CheckClause(val, rhs, AndMode);
	} else {
		throw std::runtime_error("Unknown comparison operator in where "
			"clause");
	}

	if (result) {
		return Matched;
	} else {
		return NotMatched;
	}
}