#include <libwccl/values/matchvector.h>
#include <libwccl/values/match.h>
#include <libpwrutils/foreach.h>
#include <sstream>
#include <libwccl/exception.h>

namespace Wccl {

std::string MatchVector::to_raw_string() const
{
	std::stringstream ss;
	ss << "MATCH(";
	bool comma = false;
	foreach (const boost::shared_ptr<Match>& m, matches_) {
		if (comma) {
			ss << ",";
		}
		ss << m->to_raw_string();
		comma = true;
	}
	ss << ")";
	return ss.str();
}

int MatchVector::first_token(const boost::shared_ptr<Corpus2::AnnotatedSentence>& s) const
{
	if (matches_.empty()) {
		return Position::Nowhere;
	} else {
		// Negative positions are invalid, including specials like Nowhere,
		// so we can't just find minimum value but minimum *non-negative* value.
		// Note: yes, the code assumes the special values like Nowhere are indeed negative.
		int p = matches_.front()->first_token(s);
		size_t i = 1;
		while ((p < 0) && (i < matches_.size())) {
			p = matches_[i]->first_token(s);
			++i;
		}
		while (i < matches_.size()) {
			int c = matches_[i]->first_token(s);
			if ((c >= 0) && (c < p)) {
				p = c;
			}
			++i;
		}
		return p >= 0 ? p : Position::Nowhere;
	}
}

int MatchVector::last_token(const boost::shared_ptr<Corpus2::AnnotatedSentence>& s) const
{
	if (matches_.empty()) {
		return Position::Nowhere;
	} else {
		int p = matches_.front()->last_token(s);
		for (size_t i = 1; i < matches_.size(); ++i) {
			int c = matches_[i]->last_token(s);
			if (c > p) {
				p = c;
			}
		}
		return p >= 0 ? p : Position::Nowhere;
	}
}

bool MatchVector::empty() const
{
	foreach (const boost::shared_ptr<Match>& m, matches_) {
		if (!m->empty()) {
			return false;
		}
	}
	return true;
}

void MatchVector::append(const boost::shared_ptr<Match> &m)
{
	matches_.push_back(m);
}

void MatchVector::append(const boost::shared_ptr<MatchVector> &m)
{
	matches_.push_back(boost::shared_ptr<Match>(new Match(m)));
}

void MatchVector::append(const boost::shared_ptr<TokenMatch> &m)
{
	matches_.push_back(boost::shared_ptr<Match>(new Match(m)));
}

void MatchVector::append(const boost::shared_ptr<AnnotationMatch> &m)
{
	matches_.push_back(boost::shared_ptr<Match>(new Match(m)));
}

void MatchVector::append(const boost::shared_ptr<MatchData> &m)
{
	matches_.push_back(boost::shared_ptr<Match>(new Match(m)));
}

const boost::shared_ptr<const Match> MatchVector::submatch(size_t idx) const {
	if ((idx < matches_.size() + 1) || (idx == 0)) {
		return matches_[idx - 1];
	} else {
		throw Wccl::WcclError("Match vector index out of range.");
	}
}

const boost::shared_ptr<Match>& MatchVector::submatch(size_t idx)
{
	if ((idx < matches_.size() + 1) || (idx == 0)) {
		return matches_[idx - 1];
	} else {
		throw Wccl::WcclError("Match vector index out of range.");
	}
}

} /* end ns Wccl */