// $Id$
/*
 *  Copyright (C) 2003, Ian Reinhart Geiser <geiseri@kde.org>
 *
 *  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 <tdeapplication.h>
#include <dcopref.h>
#include <dcopclient.h>
#include <kdebug.h>
#include <tqregexp.h>

#include "dcop_imp.h"
#include "dcop_imp.moc"

#include <kdatastream.h>
#include <kurl.h>
#include <tqvariant.h>
#include <tqstring.h>
#include <tqmap.h>
#include <tqfont.h>
#include <tqpixmap.h>
#include <tqbrush.h>
#include <tqrect.h>
#include <tqsize.h>
#include <tqcolor.h>
#include <tqimage.h>
#include <tqpoint.h>
#include <tqvaluelist.h>
#include <tqiconset.h>
#include <tqpointarray.h>
#include <tqbitmap.h>
#include <tqcursor.h>
#include <tqdatetime.h>
#include <tqmemarray.h>
#include <tqkeysequence.h>
#include <tqbitarray.h>

#include <kjs/interpreter.h>
#include <kjs/identifier.h>
#include <kjs/types.h>
#include <kjs/ustring.h>
#include <kjs/value.h>

#include "../jsbinding.h"
#include <kjsembed/jsopaqueproxy.h>
#include <kjsembed/jsobjectproxy.h>
#include <kjsembed/kjsembedpart.h>
namespace KJSEmbed {
namespace Bindings {
KJS::Object JSDCOPRefLoader::createBinding(KJSEmbedPart *jspart, KJS::ExecState *exec, const KJS::List &args) const
{
    TQString application = extractTQString(exec, args, 0);
    TQString object = extractTQString(exec, args, 1);
    JSOpaqueProxy * prx;
    if( application.isEmpty() )
        prx= new JSOpaqueProxy( new DCOPRef(), "DCOPRef" );
    else
        prx= new JSOpaqueProxy( new DCOPRef(application.latin1(),object.latin1()), "DCOPRef" );
    
    KJS::Object proxyObj( prx );
    prx->setOwner( JSProxy::JavaScript );
    addBindings(jspart,exec,proxyObj);
    return proxyObj;
}

void JSDCOPRefLoader::addBindings( KJSEmbedPart *jspart, KJS::ExecState *exec, KJS::Object &proxy ) const
{
    JSDCOPRef::addBindings( exec, proxy );
}

JSDCOPRef::JSDCOPRef(KJS::ExecState *exec, int id)
    : JSProxyImp(exec), mid(id)
{
}

JSDCOPRef::~JSDCOPRef()
{
}

void JSDCOPRef::addBindings( KJS::ExecState *exec, KJS::Object &object )
{
    JSOpaqueProxy *op = JSProxy::toOpaqueProxy( object.imp() );
    if ( !op ) {
        kdWarning() << "JSDCOPRef::addBindings() failed, not a JSOpaqueProxy" << endl;
        return;
    }

    if ( op->typeName() != "DCOPRef" ) {
        kdWarning() << "JSDCOPRef::addBindings() failed, type is " << op->typeName() << endl;
        return;
    }

    DCOPRef *ref = op->toNative<DCOPRef>();

    JSProxy::MethodTable methods[] = {
	{ Methodcall, "call"},
	{ Methodsend, "send" },
	{ Methodapp, "app" },
	{ Methodobj, "obj" },
	{ Methodtype, "type" },
	{ MethodsetRef, "setRef" },
	{ 0, 0 }
	};

    int idx = 0;
    do {
        JSDCOPRef *meth = new JSDCOPRef( exec, methods[idx].id );
        object.put( exec, methods[idx].name, KJS::Object(meth) );
        ++idx;
    } while( methods[idx].id );

}

KJS::Value JSDCOPRef::call( KJS::ExecState *exec, KJS::Object &self, const KJS::List &args ) {


    JSOpaqueProxy *op = JSProxy::toOpaqueProxy( self.imp() );
    if ( !op ) {
        kdWarning() << "JSDCOPRef::call() failed, not a JSOpaqueProxy" << endl;
        return KJS::Boolean(false);
    }

    if ( op->typeName() != "DCOPRef" ) {
        kdWarning() << "JSDCOPRef::call() failed, type is " << op->typeName() << endl;
        return KJS::Boolean(false);
    }
    DCOPRef *ref = op->toNative<DCOPRef>();
    kdDebug() << "Ref valid" << ref << endl;
    if( !ref )
    {
    	kdWarning() << "Ref invalid" << ref << endl;
	return KJS::Null();
    }
    kdDebug() << "DCOPRef call. " << mid << endl;
    KJS::Value retValue = KJS::Value();
    switch ( mid ) {
	case Methodcall:
	{
            if ( args.size() < 1 )
            {
		kdWarning() << "Not enough args..."  << endl;
	        return KJS::Boolean(false);
	    }
            TQByteArray data, replyData;
	    TQDataStream ds( replyData, IO_ReadOnly);
            TQCString type;

            TQString app = ref->app();
            TQString interface = ref->obj();
            TQString function = extractTQString(exec, args, 0);
            TQStringList argTypes = JSDCOPClient::getTypes( function );

            if( args.size() > 1)
                   for( int idx = 1; idx < args.size(); ++idx)
                   {
                        JSDCOPClient::marshall(convertToVariant(exec,args[idx] ), argTypes[idx - 1], data);
                   }
	    if( !tdeApp->dcopClient()->call(app.local8Bit(), interface.local8Bit(), function.local8Bit(), data, type, replyData))
                retValue =  KJS::Boolean(false);
            else
                retValue = JSDCOPClient::demarshall(exec, type, ds);
            break;
	}
	case Methodsend:
	{
             if ( args.size() < 1 )
                  return KJS::Boolean(false);

             TQByteArray data;
             TQString app = ref->app();
             TQString interface = ref->obj();
             TQString function = extractTQString(exec, args, 0);

             TQStringList argTypes = JSDCOPClient::getTypes( function );

             if( args.size() > 1)
                for( int idx = 1; idx < args.size(); ++idx)
                {
                    JSDCOPClient::marshall(convertToVariant(exec,args[idx] ), argTypes[idx - 1], data);
                }
             retValue = KJS::Boolean( tdeApp->dcopClient()->send(app.local8Bit(), interface.local8Bit(),
                        function.local8Bit(), data));
            break;
	}
	case Methodapp:
	{
	    retValue = convertToValue( exec, ref->app() );
            break;
	}
	case Methodobj:
	{
	    retValue = convertToValue( exec, ref->obj() );
            break;
	}
	case Methodtype:
	{
	    retValue = convertToValue( exec, ref->type() );
            break;
	}
	case MethodsetRef:
	{
      TQString arg0 = extractTQString(exec, args, 0);
      TQString arg1 = extractTQString(exec, args, 1);
      TQString arg2 = extractTQString(exec, args, 0);
	    ref->setRef(arg0.latin1(), arg1.latin1(), arg2.latin1() );
            break;
	}
        default:
	{
            kdWarning() << "JSDCOPClient has no method " << mid << endl;
            break;
	}
    }
    op->setValue( ref, "DCOPRef" );
    return retValue;
}

KJS::Object JSDCOPClientLoader::createBinding(KJSEmbedPart *jspart, KJS::ExecState *exec, const KJS::List &/*args*/) const
{
    JSOpaqueProxy * prx = new JSOpaqueProxy( tdeApp->dcopClient(), "DCOPClient" );
    prx->setOwner( JSProxy::Native );
    KJS::Object proxyObj( prx );
    addBindings( jspart, exec, proxyObj );
    return proxyObj;
}

void JSDCOPClientLoader::addBindings( KJSEmbedPart *jspart, KJS::ExecState *exec, KJS::Object &proxy ) const
{
    JSDCOPClient::addBindings( exec, proxy );
}

JSDCOPClient::JSDCOPClient( KJS::ExecState *exec, int id  )
    : JSProxyImp(exec), mid(id)
{
}

JSDCOPClient::~JSDCOPClient()
{
}


void JSDCOPClient::addBindings( KJS::ExecState *exec, KJS::Object &object )
{
    if( !JSProxy::checkType(object, JSProxy::OpaqueProxy, "DCOPClient") ) return;

    JSProxy::MethodTable methods[] = {
    { Methodattach, "attach"},
    { Methoddetach, "detach"},
    { MethodisAttached, "isAttached" },
    { MethodregisteredApplications, "registeredApplications" },
    { MethodremoteObjects, "remoteObjects" },
    { MethodremoteInterfaces, "remoteInterfaces" },
    { MethodremoteFunctions, "remoteFunctions" },
    { MethodconnectDCOPSignal, "connectDCOPSignal" },
    { MethoddisconnectDCOPSignal, "disconnectDCOPSignal"},
    { Methodcall, "call"},
    { Methodsend, "send"},
    { MethodDCOPStart, "dcopStart"},
    { MethodappId, "appId"},
    { MethodisApplicationRegistered, "isApplicationRegistered" },
    { 0, 0 }
    };

    JSProxy::addMethods<JSDCOPClient>(exec, methods, object );
}

KJS::Value JSDCOPClient::call( KJS::ExecState *exec, KJS::Object &self, const KJS::List &args ) {
    if( !JSProxy::checkType(self, JSProxy::OpaqueProxy, "DCOPClient") ) return KJS::Value();
    
    JSOpaqueProxy *op = JSProxy::toOpaqueProxy( self.imp() );

    KJS::Value retValue = KJS::Value();
    switch ( mid ) {
        case Methodattach: {
	    retValue = KJS::Boolean(attach( ));
	    break;
	}
	case Methoddetach: {
	    retValue = KJS::Boolean(detach( ));
	    break;
	}
	case MethodisAttached: {
	    retValue = KJS::Boolean(isAttached( ));
	    break;
	}
	case MethodregisteredApplications: {
	    retValue = convertToValue(exec, registeredApplications());
	    break;
	}
	case MethodremoteObjects: {
	    TQString arg0 = extractTQString(exec, args, 0);
	    retValue = convertToValue( exec, remoteObjects(arg0));
	    break;
	}
	case MethodremoteInterfaces: {
	    TQString arg0 = extractTQString(exec, args, 0);
	    TQString arg1 = extractTQString(exec, args, 1);
	    this->remoteInterfaces(arg0, arg1);
	    break;
	}
	case MethodremoteFunctions: {
	    TQString arg0 = extractTQString(exec, args, 0);
	    TQString arg1 = extractTQString(exec, args, 1);
	    remoteFunctions(arg0, arg1);
	    break;
	}
	case MethodconnectDCOPSignal: {
	    TQString arg0 = extractTQString(exec, args, 0);
	    TQString arg1 = extractTQString(exec, args, 1);
	    TQString arg2 = extractTQString(exec, args, 2);
	    TQString arg3 = extractTQString(exec, args, 3);
	    TQString arg4 = extractTQString(exec, args, 4);
	    bool arg5 = (args.size() > 5) ? args[5].toBoolean(exec) : false;
	    connectDCOPSignal( arg0, arg1, arg2, arg3, arg4, arg5);
	    break;
	}
	case MethoddisconnectDCOPSignal: {
	    TQString arg0 = extractTQString(exec, args, 0);
	    TQString arg1 = extractTQString(exec, args, 1);
	    TQString arg2 = extractTQString(exec, args, 2);
	    TQString arg3 = extractTQString(exec, args, 3);
	    TQString arg4 = extractTQString(exec, args, 4);
	    disconnectDCOPSignal(arg0, arg1, arg2, arg3, arg4);
	    break;
	}
	case MethodDCOPStart: {
		TQString arg0 = extractTQString(exec, args, 0);

		retValue = KJS::String( dcopStart( arg0, TQStringList() ) );
		break;
	}
	case MethodappId:
		retValue = KJS::String( tdeApp->dcopClient()->appId().data() );
		break;
	case MethodisApplicationRegistered: {
		TQString arg0 = extractTQString(exec, args, 0);
		retValue = KJS::Boolean( tdeApp->dcopClient()->isApplicationRegistered( arg0.latin1() )  );
		break;
	}
	case Methodsend:
		return dcopSend( exec, self, args );
		break;
	case Methodcall:
		return dcopCall( exec, self, args );
		break;
        default:
        kdWarning() << "JSDCOPClient has no method " << mid << endl;
        break;
    }
    return retValue;
}

bool JSDCOPClient::attach() const
{
	if( !tdeApp->dcopClient()->isAttached() )
		return tdeApp->dcopClient()->attach();
	return true;
}
bool JSDCOPClient::detach() const
{	return tdeApp->dcopClient()->detach();

}

bool JSDCOPClient::isAttached() const
{
	return tdeApp->dcopClient()->isAttached();
}

KJS::Value JSDCOPClient::dcopCall( KJS::ExecState * exec, KJS::Object &, const KJS::List & args )
{
	if ( args.size() < 3 )
		return KJS::Boolean(false);

	TQStringList types;
	TQByteArray data, replyData;
	TQDataStream ds( replyData, IO_ReadOnly);
	TQCString type;

	TQString app = extractTQString(exec, args, 0);
	TQString interface = extractTQString(exec, args, 1);
	TQString function = extractTQString(exec, args, 2);
	TQStringList argTypes = getTypes( function );

	if( args.size() > 3)
		for( int idx = 3; idx < args.size(); ++idx)
		{
			TQVariant var = convertToVariant(exec,args[idx] );
			marshall(var, argTypes[idx -3 ], data);
		}
	if( !tdeApp->dcopClient()->call(app.local8Bit(), interface.local8Bit(), function.local8Bit(), data, type, replyData))
		return KJS::Boolean(false);
	else
		return demarshall(exec, type, ds);
}

KJS::Value JSDCOPClient::dcopSend( KJS::ExecState * exec, KJS::Object &, const KJS::List & args )
{
	if ( args.size() < 3 )
		return KJS::Boolean(false);

	TQByteArray data;
	TQString app = extractTQString(exec, args, 0);
	TQString interface = extractTQString(exec, args, 1);
	TQString function = extractTQString(exec, args, 2);
	TQStringList argTypes = getTypes( function );

	if( args.size() > 3)
		for( int idx = 3; idx < args.size(); ++idx)
		{
			TQVariant var = convertToVariant(exec,args[idx] );
			marshall(var, argTypes[idx - 3], data);
		}
	return KJS::Boolean( tdeApp->dcopClient()->send(app.local8Bit(), interface.local8Bit(),
                        function.local8Bit(), data));
}

KJS::Value JSDCOPClient::demarshall( KJS::ExecState * exec, const TQCString& type, TQDataStream& data)
{
	kdDebug() << "Demarshall " << type << endl;

	if( type == "DCOPRef" )
	{
		DCOPRef *ref = new DCOPRef();
                data >> *ref;
                JSOpaqueProxy *prx = new JSOpaqueProxy(ref, "DCOPRef" );

                KJS::Object proxyObj(prx);
		kdDebug() << "DCOPRef  " << ref->app() << endl;
		Bindings::JSDCOPRef::addBindings( exec, proxyObj );
                return proxyObj;
	}
	else
		return convertToValue(exec, demarshall(type, data));
}

TQStringList JSDCOPClient::getTypes( const TQString& function )
{
	TQCString myFunction = DCOPClient::normalizeFunctionSignature (function.latin1());
	TQString args = myFunction.mid( myFunction.find('(') + 1 );
	args = args.left( args.length() - 1);
	return TQStringList::split(',', args);
}

void JSDCOPClient::marshall( const TQVariant& data, const TQString& typeName, TQByteArray& buffer )
{
	TQDataStream stream(buffer, IO_WriteOnly | IO_Append);

	if ( typeName == "TQString" )
	{
		stream << data.toString();
	}
	else if ( typeName == "TQCString")
	{
		stream << data.toCString();
	}
	else if ( typeName == "int")
	{
		stream << data.toInt();
	}
	else if ( typeName == "uint")
	{
		stream << data.toUInt();
	}
	else if ( typeName == "bool")
	{
		stream << data.toBool();
	}
	else if ( typeName == "double")
	{
		stream << data.toDouble();
	}
	else if ( typeName == "TQMap" )
	{
		stream << data.toMap();
	}
	else if ( typeName == "TQValueList")
	{
		stream << data.toList();
	}
	else if ( typeName == "TQFont")
	{
		stream << data.toFont();
	}
	else if ( typeName == "TQPixmap")
	{
		stream << data.toPixmap();
	}
	else if ( typeName == "TQBrush")
	{
		stream << data.toBrush();
	}
	else if ( typeName == "TQRect")
	{
		stream << data.toRect();
	}
	else if ( typeName == "TQSize")
	{
		stream << data.toSize();
	}
	else if ( typeName == "TQColor")
	{
		stream << data.toColor();
	}
	else if ( typeName == "TQPalette")
	{
		stream << data.toPalette();
	}
	else if ( typeName == "TQColorGroup")
	{
		stream << data.toColorGroup();
	}
	/*else if ( typeName == "TQIconSet")
	{
		stream << data.toIconSet();
	}*/
	else if ( typeName == "TQPoint")
	{
		stream << data.toPoint();
	}
	else if ( typeName == "TQImage")
	{
		stream << data.toImage();
	}
	else if ( typeName == "TQPointArray")
	{
		stream << data.toPointArray();
	}
	else if ( typeName == "TQRegion")
	{
		stream << data.toRegion();
	}
	else if ( typeName == "TQBitmap")
	{
		stream << data.toBitmap();
	}
	else if ( typeName == "TQCursor")
	{
		stream << data.toCursor();
	}
	/*else if ( typeName == "TQSizePolicy")
	{
		stream << data.toSizePolicy();
	}*/
	else if ( typeName == "TQDate")
	{
		stream << data.toDate();
	}
	else if ( typeName == "TQTime")
	{
		stream << data.toTime();
	}
	else if ( typeName == "TQDateTime")
	{
		stream << data.toDateTime();
	}
	else if ( typeName == "TQByteArray")
	{
		stream << data.toByteArray();
	}
	else if ( typeName == "TQBitArray")
	{
		stream << data.toBitArray();
	}
	else if ( typeName == "TQKeySequence")
	{
		stream << data.toKeySequence();
	}
	else if ( typeName == "KURL" )
	{
		KURL url = data.toString();
		stream << url;
	}
	else
		stream << 0;

}

TQString JSDCOPClient::dcopStart( const TQString &appName, const TQStringList& args )
{
	TQString error;
	TQString startFunction;
	if (appName.endsWith(".desktop"))
		startFunction = "start_service_by_desktop_path(TQString,TQStringList)";
	else
		startFunction = "start_service_by_desktop_name(TQString,TQStringList)";

	TQByteArray data, replyData;
	TQCString replyType;
	TQDataStream arg(data, IO_WriteOnly);
	arg << appName << args;

	if ( !tdeApp->dcopClient()->call( "tdelauncher", "tdelauncher", startFunction.latin1(),  data, replyType, replyData) )
	{
		kdWarning() << "Error: Dcop call failed" << endl;
	}
	else
	{
		TQDataStream reply(replyData, IO_ReadOnly);

		if ( replyType != "serviceResult" )
		{
			kdWarning() << "Error: No serviceResult " << endl;
		}
		else
		{
			int result;
			TQCString dcopName;
			TQString error;
			reply >> result >> dcopName >> error;
			if (result != 0)
			{
				kdWarning() << "Error: " <<  error.local8Bit().data() << endl;
			}
			else if (!dcopName.isEmpty())
			{
				return dcopName;
			}
			else
				kdWarning() << "Error: no app name returned." << endl;
		}
	}

	return "";

}

TQStringList JSDCOPClient::remoteFunctions( const TQString & remApp, const TQString & remObj )
{
	TQStringList returnList;
	QCStringList lst = tdeApp->dcopClient()->remoteFunctions(remApp.local8Bit(), remObj.local8Bit());
	for(uint idx = 0; idx < lst.count(); ++idx)
		returnList += lst[idx];
	return returnList;
}

TQStringList JSDCOPClient::remoteInterfaces( const TQString & remApp, const TQString & remObj )
{
	TQStringList returnList;
	QCStringList lst = tdeApp->dcopClient()->remoteInterfaces(remApp.local8Bit(), remObj.local8Bit());
	for(uint idx = 0; idx < lst.count(); ++idx)
		returnList += lst[idx];
	return returnList;
}

TQStringList JSDCOPClient::remoteObjects( const TQString & remApp )
{
	TQStringList returnList;
	QCStringList lst = tdeApp->dcopClient()->remoteObjects(remApp.local8Bit());
	for(uint idx = 0; idx < lst.count(); ++idx)
		returnList += lst[idx];
	return returnList;
}

TQStringList JSDCOPClient::registeredApplications( )
{
	TQStringList returnList;
	QCStringList lst = tdeApp->dcopClient()->registeredApplications( );
	for(uint idx = 0; idx < lst.count(); ++idx)
		returnList += lst[idx];
	return returnList;
}

bool JSDCOPClient::connectDCOPSignal (const TQString &sender, const TQString &senderObj, const TQString &signal, const TQString &receiverObj, const TQString &slot, bool Volatile)
{
	return tdeApp->dcopClient()->connectDCOPSignal(sender.latin1(), senderObj.latin1(), signal.latin1(), receiverObj.latin1(), slot.latin1(), Volatile);
}

bool JSDCOPClient::disconnectDCOPSignal (const TQString &sender, const TQString &senderObj, const TQString &signal, const TQString &receiverObj, const TQString &slot)
{
	return tdeApp->dcopClient()->disconnectDCOPSignal(sender.latin1(), senderObj.latin1(), signal.latin1(), receiverObj.latin1(), slot.latin1());
}

KJS::Object JSDCOPInterfacerLoader::createBinding(KJSEmbedPart *jspart, KJS::ExecState *exec, const KJS::List &args) const
{
    TQObject *parent = extractTQObject(exec, args, 0);
    TQString name = extractTQString(exec, args, 1);
    TQObject *obj = new JSDCOPInterface(jspart->interpreter(),parent, name.latin1() );
    JSObjectProxy *prxy = new JSObjectProxy(jspart, obj);
    KJS::Object object(prxy);
    addBindings(jspart,exec,object);
    return object;
}

void JSDCOPInterfacerLoader::addBindings( KJSEmbedPart *jspart, KJS::ExecState *exec, KJS::Object &proxy ) const
{
    JSObjectProxy *prx = JSProxy::toObjectProxy( proxy.imp() );
    if( prx )
        prx->addBindings( exec, proxy );
}

void JSDCOPInterface::publish( const TQString & signature )
{
	if( m_Members.find(signature.latin1() ) == m_Members.end())
		m_Members.append(signature.latin1() );
}

JSDCOPInterface::~ JSDCOPInterface( )
{
}

JSDCOPInterface::JSDCOPInterface( KJS::Interpreter *js, TQObject * parent, const char * name )
	: BindingObject( parent, name ),DCOPObject(name), m_js(js)
{
	m_Members.clear();
}

QCStringList JSDCOPInterface::functionsDynamic( )
{
	return m_Members;
}

bool JSDCOPInterface::processDynamic( const TQCString & rawFunction, const TQByteArray & data, TQCString & replyType, TQByteArray & replyData )
{
	bool isOkay = false;

	TQRegExp reg = TQRegExp("([_\\d\\w]+)(\\()(.*)(\\))");
	reg.search(rawFunction);

	kdDebug() << "Raw function: " << rawFunction << endl;
	kdDebug() << "Reply type: " << replyType << endl;
	kdDebug() << "Signature: " << reg.cap(1) << endl;
	kdDebug() << "Args: " << reg.cap(3) << endl;

	TQString signature = reg.cap(1);

	TQStringList argStrings = TQStringList::split(',', reg.cap(3), false);
	kdDebug() << argStrings.count() << " args..." << endl;

	KJS::ExecState *exec = m_js->globalExec();
	KJS::Object obj = m_js->globalObject();
	KJS::Identifier id( KJS::UString( signature.latin1() ) );
	KJS::Object fun = obj.get(exec, id ).toObject( exec );
	KJS::Value retValue;


	if ( fun.implementsCall() )
	{
		TQDataStream ds( data, IO_ReadOnly );
		KJS::List args;
		for( uint idx = 0; idx < argStrings.count(); ++idx)
		{
			kdDebug() << "Get arg: " << argStrings[idx] << endl;
			args.append( JSDCOPClient::demarshall( exec, argStrings[idx].latin1(), ds));
		}

		retValue = fun.call(exec, obj, args);

		if( exec->hadException() )
		{
			kdWarning() << "Got error: " << exec->exception().toString(exec).qstring() << endl;
		}
		else
		{
			kdDebug() << "Returned type is a " << retValue.type() << endl;
      if( retValue.isA(KJS::UndefinedType) )
			{
				replyType = "void";
				isOkay = true;
			}
      else if( retValue.isA(KJS::ObjectType) )
			{
          JSOpaqueProxy *oprx = JSProxy::toOpaqueProxy( retValue.imp() );
          if( oprx )
          {
            replyType = "DCOPRef";
            TQDataStream refStream( replyData, IO_WriteOnly );
            if( oprx->typeName() == "DCOPRef" )
            {
                DCOPRef ref(*oprx->toNative<DCOPRef>());
            refStream << ref;
            isOkay = true;
            }
          }
			}
			else
			{
				TQVariant returnVariant = convertToVariant(exec, retValue);
				JSDCOPClient::marshall(returnVariant,returnVariant.typeName(), replyData);
				replyType = returnVariant.typeName();
				isOkay = true;
			}
		}
	}
	return isOkay;
}

TQVariant JSDCOPClient::demarshall( const TQCString & type, TQDataStream & reply )
{
	kdDebug() << "Type: '" << type << "'"<< endl;
	/*if ( type == "TQMap" )  // ? dont handle?
	{
		TQMap<TQVariant, TQVariant> result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQValueList") // ? dont handle?
	{
		TQValueList<TQVariant> result;
		reply >> result;
		return TQVariant(result);
	}else if ( type == "TQVariantList")
	{
		TQVariantList result;
		reply >> result;
		return TQVariant(result);
	}
	else */
	if ( type == "TQString")
	{
		TQString result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "int")
	{
		int result;
		reply >> result;
		kdDebug() << "Result: " << result << endl;
		return TQVariant(result);
	}
	else if ( type == "uint")
	{
		uint result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "bool")
	{
		bool result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "double")
	{
		double result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQCString")
	{
		TQCString result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQVariant")
	{
		TQVariant result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQFont")
	{
		TQFont result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQPixmap")
	{
		TQPixmap result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQBrush")
	{
		TQBrush result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQRect")
	{
		TQRect result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQSize")
	{
		TQSize result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQColor")
	{
		TQColor result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQPalette")
	{
		TQPalette result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQColorGroup")
	{
		TQColorGroup result;
		reply >> result;
		return TQVariant(result);
	}
	/*else if ( type == "TQIconSet")
	{
		TQIconSet result;
		reply >> result;
		return TQVariant(result);
	}*/
	else if ( type == "TQPoint")
	{
		TQPoint result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQImage")
	{
		TQImage result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQPointArray")
	{
		TQPointArray result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQRegion")
	{
		TQRegion result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQBitmap")
	{
		TQBitmap result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQCursor")
	{
		TQCursor result;
		reply >> result;
		return TQVariant(result);
	}
	/*else if ( type == "TQSizePolicy")
	{
		TQSizePolicy result;
		reply >> result;
		return TQVariant(result);
	}*/
	else if ( type == "TQDate")
	{
		TQDate result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQTime")
	{
		TQTime result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQDateTime")
	{
		TQDateTime result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQByteArray")
	{
		TQByteArray result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQBitArray")
	{
		TQBitArray result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQKeySequence")
	{
		TQKeySequence result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "TQStringList")
	{
		TQStringList result;
		reply >> result;
		return TQVariant(result);
	}
	else if ( type == "QCStringList")
	{
		TQStringList result;
		reply >> result;
		return TQVariant(result);
	}
	else
		return TQVariant();

}
} // namespace Bindings
} // namespace KJSEmbed




