    /*

    Copyright (C) 2000 Stefan Westerfeld
                       stefan@space.twc.de

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
  
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.
   
    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

    */

#include "dynamicrequest.h"
#include "common.h"
#include "debug.h"
#include <iostream>

using namespace Arts;
using namespace std;

class Arts::DynamicRequestPrivate {
public:
	Connection *connection;
	Buffer *buffer;
	MethodDef method;
	Object object;

	/**
	 * methodID is kept between the requests, so that we don't need to lookup
	 * a method again when it gets called twice - the value for "we need to
	 * lookup again" is -1, which gets set whenever the current request differs
	 * from the last
	 */
	long requestID, methodID, objectID;
	unsigned long paramCount;

	/**
	 * constructor
	 */
	DynamicRequestPrivate(const Object &obj)
		: buffer(0), object(obj), methodID(-1)
	{
	}
};

DynamicRequest::DynamicRequest(const Object& obj)
{
	d = new DynamicRequestPrivate(obj);
	d->connection = obj._base()->_connection;
	d->objectID = obj._base()->_objectID;
}

DynamicRequest::~DynamicRequest()
{
	delete d;
}

DynamicRequest& DynamicRequest::method(const string& method)
{
	assert(!d->buffer);

	// methodID will be set later
	d->buffer = Dispatcher::the()->createRequest(d->requestID, d->objectID, 0);

	if(d->method.name != method)
	{
		d->method.name = method;
		d->methodID = -1;
	}
	d->paramCount = 0;
	return *this;
}

DynamicRequest& DynamicRequest::param(const AnyConstRef& ref)
{
	if(d->paramCount == d->method.signature.size())
	{
		ParamDef pd;
		pd.type = ref.type();
		d->method.signature.push_back(pd);
	}
	else
	{
		if(d->method.signature[d->paramCount].type != ref.type())
		{
			d->method.signature[d->paramCount].type = ref.type();
			d->methodID = -1;
		}
	}
	d->paramCount++;
	ref.write(d->buffer);
	return *this;
}

bool DynamicRequest::invoke()
{
	AnyRef voidReference;
	return invoke(voidReference);
}

bool DynamicRequest::invoke(const AnyRef& returnCode)
{
	if(d->method.type != returnCode.type())
	{
		d->method.type = returnCode.type();
		d->methodID = -1;
	}
	if(d->method.signature.size() != d->paramCount)
		d->methodID = -1;

	/*
	 * need to lookup method? (if the requested method is exactly the
	 * same as the last, we need not, which signigicantly improves performance
	 */
	if(d->methodID == -1)
	{
		d->method.signature.resize(d->paramCount);
		d->methodID = d->object._lookupMethod(d->method);

		if(d->methodID == -1)
		{
			arts_warning("DynamicRequest: invalid method called");
			return false;
		}
	}


	d->buffer->patchLength();
	d->buffer->patchLong(16,d->methodID);
	d->connection->qSendBuffer(d->buffer);
	d->buffer = 0;

	Buffer *result =
		Dispatcher::the()->waitForResult(d->requestID,d->connection);

	if(result)
	{
		returnCode.read(result);
		delete result;
	}
	return result != 0;
}
