//
// See the file LICENSE for redistribution information.
//
// Copyright (c) 2002-2003
//	Sleepycat Software.  All rights reserved.
//

static const char revid[] = "$Id: Results.cpp,v 1.31 2003/12/09 14:07:04 merrells Exp $";

#include "dbxml_config.h"
#include "dbxml/XmlPortability.hpp"
#include "dbxml/XmlException.hpp"
#include "Results.hpp"
#include "QueryContext.hpp"
#include "OperationContext.hpp"
#include "Container.hpp"

using namespace DbXml;

Results::Results(QueryContext &context, DbTxn *txn)
	: context_(context),
	txn_(txn),
	container_(0),
	qp_(0),
	vv_(0),
	vvi_(0)
{}

Results::~Results()
{
	if (container_) {
		container_->release();
		container_ = 0;
	}
	delete vv_;
	delete vvi_;
}

int Results::set(Container &container, QueryPlan::SharedPtr &qp)
{
	int err = 0;
	if (context_.getEvaluationType() == XmlQueryContext::Eager) {
		// For Eager evaluation we copy the values into a vector.
		//
		if (vv_ == 0) {
			vv_ = new XmlValueVector;
		}
		vv_->reserve(qp->getResultSize());
		context_.setTransaction(txn_);
		XmlValue value;
		while ((err = qp->next(context_, value)) == 0 && !value.isNull()) {
			vv_->push_back(value);
		}
	} else // type==XmlQueryContext::Lazy
	{
		// For Lazy evaluation we maintain references to the Container,
		// Query Context, and Query Plan.
		//
		container_ = &container;
		container_->acquire();
		qp_ = qp;
	}
	return err;
}

void Results::reset()
{
	if (qp_) {
		throw XmlException(XmlException::LAZY_EVALUATION, "This result set is lazily evaluated. reset() can only be called for eagerly evaluated result sets.");
	} else {
		delete vvi_;
		vvi_ = 0;
	}
}

void Results::size(size_t &size, SizeType &type) const
{
	if (qp_) {
		size= qp_->getResultSize();
		if(qp_->contains(QueryPlan::RESTRICTION_FILTER) ||
			qp_->contains(QueryPlan::RESTRICTION_FILTER_AND_PROJECT))
		{
			type= Estimate;
		}
		else
		{
			type= Actual;
		}
	} else {
		size= vv_->size();
		type= Actual;
	}
}

int Results::next(XmlValue &value)
{
	int err = 0;
	if (context_.getEvaluationType() == XmlQueryContext::Lazy)
	{
		if (!container_->isOpen())
		{
			throw XmlException(XmlException::CONTAINER_CLOSED, "This result set is lazily evaulated. The referenced container was found to be close. The container must be open for lazy result set iteration support.");
		}
		context_.setTransaction(txn_);
		err = qp_->next(context_, value);
	} else	{
		if (vvi_ == 0)
		{
			vvi_ = new XmlValueVector::iterator;
			*vvi_ = vv_->begin();
		}
		if (*vvi_ != vv_->end())
		{
			value = **vvi_;
			(*vvi_)++;
		} else
		{
			value = XmlValue();
		}
	}
	return err;
}

void Results::add(const XmlValue &value)
{
	if (context_.getEvaluationType() == XmlQueryContext::Lazy) {
		throw XmlException(XmlException::LAZY_EVALUATION, "This result set is lazily evaluated, add() can only be called for eagerly evaluated result sets.");
	} else {
		if (vv_ == 0) {
			vv_ = new XmlValueVector;
		}
		vv_->push_back(value);
	}
}

void Results::add(const XmlValueVector &vv)
{
	if (context_.getEvaluationType() == XmlQueryContext::Lazy) {
		throw XmlException(XmlException::LAZY_EVALUATION, "This result set is lazily evaluated, add() can only be called for eagerly evaluated result sets.");
	} else {
		if (vv_ == 0) {
			vv_ = new XmlValueVector;
		}
		vv_->insert(vv_->end(), vv.begin(), vv.end());
	}
}
