/*
 *  Copyright (C) 2001-2003, Richard J. Moore <rich@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 <tqobject.h>
#include <tqobjectlist.h>
#include <tqdialog.h>
#include <tqlistbox.h>
#include <tqlistview.h>
#include <tqmetaobject.h>
#include <tqregexp.h>
#include <tqsignal.h>
#include <tqstrlist.h>
#include <tqtimer.h>
#include <tqvariant.h>
#include <tqdatetime.h>
#include <tqstringlist.h>

#include <private/qucom_p.h>
#include <private/qucomextra_p.h>

#ifndef QT_ONLY
#include <tdelistview.h>
#include <kurl.h>
#else // QT_ONLY
#include "qtstubs.h"
#endif // QT_ONLY

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

#include "kjsembedpart.h"
#include "jssecuritypolicy.h"

#include "global.h"
#include "jsfactory.h"
#include "slotproxy.h"
#include "jsvalueproxy.h"
#include "jsopaqueproxy.h"

#include "jsobjectproxy_imp.h"

#include "slotutils.h"

namespace KJSEmbed {
namespace Bindings {

JSSlotUtils::JSSlotUtils()
{
}

JSSlotUtils::~JSSlotUtils()
{
}

bool JSSlotUtils::connect( TQObject *sender, const char *sig, TQObject *recv, const char *dest )
{
    if ( (!sender) || (!recv) )
	return false;

    // Source
    TQString si = TQString("2%1").arg(sig);
    const char *sigc = si.ascii();

    // Connect to slot
    if ( recv->metaObject()->findSlot(dest, true) >= 0 ) {
	TQString sl = TQString("1%1").arg(dest);
	const char *slotc = sl.ascii();

	//kdDebug(80001) << "connect: "<<sender->name()<<" "<<sigc<<", slot "<<recv->name()<<" "<<slotc<< endl;
	bool ok = TQObject::connect( sender, sigc, recv, slotc );
	if (ok)
	    return true;
    }

    // Connect to signal
    if ( recv->metaObject()->findSignal(dest, true) >= 0 ) {
	TQString si2 = TQString("2%1").arg(dest);
	const char *sig2c = si2.ascii();

	kdDebug(80001) << "connect: "<<sender->name()<<" "<<sigc<<", sig "<<recv->name()<<" "<<sig2c<< endl;
	bool ok = TQObject::connect( sender, sigc, recv, sig2c );
	if (ok)
	    return true;
    }

    return false;
}

KJS::Boolean JSSlotUtils::disconnect( KJS::ExecState */*exec*/, KJS::Object &/*self*/,
				    TQObject *sender, const char *sig,
				    TQObject *recv, const char *dest )
{
    if ( (!sender) || (!recv) )
	return KJS::Boolean(false);

    bool ok;

    // Source
    TQString si = TQString("2%1").arg(sig);
    const char *sigc = si.ascii();

    // Disconnect from slot
    if ( recv->metaObject()->findSlot(dest, true) >= 0 ) {
	TQString sl = TQString("1%1").arg(dest);
	const char *slotc = sl.ascii();

	//kdDebug(80001) << "disconnect: "<<sender->name()<<" "<<sigc<<", slot "<<recv->name()<<" "<<slotc<< endl;
	ok = TQObject::disconnect( sender, sigc, recv, slotc );
	if (ok)
	    return KJS::Boolean(ok);
    }

    // Disonnect to signal
    if ( recv->metaObject()->findSignal(dest, true) >= 0 ) {
	TQString si2("2");
	si2 = si2 + dest;
	const char *sig2c = si2.ascii();

	//kdDebug(80001)<< "disconnect: "<<sender->name()<<" "<<sigc<<", sig "<<recv->name()<<" "<<sig2c<< endl;
	ok = TQObject::disconnect( sender, sigc, recv, sig2c );
	if (ok)
	    return KJS::Boolean(ok);
    }

    return KJS::Boolean(false);
}

KJS::Value JSSlotUtils::extractValue( KJS::ExecState *exec, TQUObject *uo, JSObjectProxy *parent )
{
    TQCString typenm( uo->type->desc() );
    kdDebug(80001) << "JSSlotUtils:extractValue() " << typenm << endl;

    if ( typenm == "null" )
	return KJS::Null();
    else if ( typenm == "bool" )
	return KJS::Boolean( static_QUType_bool.get(uo) );
    else if ( typenm == "int" )
	return KJS::Number( static_QUType_int.get(uo) );
    else if ( typenm == "double" )
	return KJS::Number( static_QUType_double.get(uo) );
    else if ( typenm == "charstar" )
	return KJS::String( static_QUType_charstar.get(uo) );
    else if ( typenm == "TQString" )
	return KJS::String( static_QUType_TQString.get(uo) );
    else if ( typenm == "TQVariant" )
	return convertToValue( exec, static_QUType_TQVariant.get(uo) );
    else if ( typenm == "ptr" ) {
	void *ptr = static_QUType_ptr.get(uo);

	// If it's a TQObject and we know the parent
	if ( ptr && parent ) {
	    TQObject *qobj = (TQObject *)(ptr); // Crash in kst
	    return parent->part()->factory()->createProxy( exec, qobj, parent);
	}
    }

    kdWarning(80001) << "JSSlotUtils:extractValue() Failed (" << typenm << ")" << endl;
    TQString msg = i18n( "Value of type (%1) is not supported." ).arg( typenm );
    throwError(exec, msg,KJS::TypeError);
    return KJS::Null();
}

//
// Add a value to a TQUObject.
//

void JSSlotUtils::implantInt( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v )
{
    static_QUType_int.set( uo, v.toInteger( exec ) );
}

void JSSlotUtils::implantCharStar( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v )
{
    static_QUType_charstar.set( uo, v.toString( exec ).ascii() );
}

void JSSlotUtils::implantBool( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v )
{
    static_QUType_bool.set( uo, v.toBoolean( exec ) );
}

void JSSlotUtils::implantDouble( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v )
{
    static_QUType_double.set( uo, v.toNumber( exec ) );
}

void JSSlotUtils::implantTQString( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v )
{
    static_QUType_TQString.set( uo, v.toString(exec).qstring() );
}

void JSSlotUtils::implantCString( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v )
{
    static_QUType_charstar.set( uo, v.toString(exec).ascii() );
}

void JSSlotUtils::implantURL( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v,KURL *url )
{
    *url = TQString( v.toString(exec).qstring() );
    static_QUType_ptr.set( uo, url );
}

void JSSlotUtils::implantColor( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQColor *color )
{
    bool ok;
    TQString s( v.toString(exec).qstring() );

    if ( s.startsWith("#") ) {

	TQRegExp re("#([0-9a-f][0-9a-f]){3,4}");
	re.setCaseSensitive( false );

	if ( re.search(s) != -1 ) {
	    uint r = re.cap(1).toUInt(&ok, 16);
	    uint g = re.cap(2).toUInt(&ok, 16);
	    uint b = re.cap(3).toUInt(&ok, 16);

	    if ( re.numCaptures() == 3 )
		*color = TQColor(r,g,b);
	    else if ( re.numCaptures() == 4 ) {
		uint a = re.cap(4).toUInt(&ok, 16);
		uint pix = r;
		pix = pix << 8;
		pix = pix | g;
		pix = pix << 8;
		pix = pix | b;
		pix = pix << 8;
		pix = pix | a;

		*color = TQColor( tqRgba(r,g,b,a), pix );
	    }
	}

    }
    else {
	// Try for a named color
	*color = TQColor( s );
    }

    static_QUType_ptr.set( uo, color );
}

void JSSlotUtils::implantPoint( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQPoint *point )
{
    KJS::Object o = v.toObject( exec );
    if ( !o.isValid() )
	return;

    int x, y;
    KJS::Identifier zero("0"), one("1"), ex("x"), wi("y");

    if ( o.hasProperty(exec, zero) && o.hasProperty(exec, one) ) {
	x = o.get( exec, zero ).toInteger(exec);
	y = o.get( exec, one ).toInteger(exec);
    }
    else if ( o.hasProperty(exec, ex) && o.hasProperty(exec, wi) ) {
	x = o.get( exec, ex ).toInteger(exec);
	y = o.get( exec, wi ).toInteger(exec);
    }
    else
	return;

    *point = TQPoint( x, y );
    static_QUType_ptr.set( uo, point );
}

void JSSlotUtils::implantSize( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQSize *size )
{
    KJS::Object o = v.toObject( exec );
    if ( !o.isValid() )
	return;

    int w, h;
    KJS::Identifier zero("0"), one("1"), wid("width"), hih("height");

    if ( o.hasProperty(exec, zero) && o.hasProperty(exec, one) ) {
	w = o.get( exec, zero ).toInteger(exec);
	h = o.get( exec, one ).toInteger(exec);
    }
    else if ( o.hasProperty(exec, wid) && o.hasProperty(exec, hih) ) {
	w = o.get( exec, wid ).toInteger(exec);
	h = o.get( exec, hih ).toInteger(exec);
    }
    else
	return;

    *size = TQSize( w, h );
    static_QUType_ptr.set( uo, size );
}

void JSSlotUtils::implantRect( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQRect *rect )
{
    KJS::Object o = v.toObject( exec );
    if ( !o.isValid() )
	return;

    int x, y, w, h;
    KJS::Identifier zero("0"), one("1"), two("2"), three("3");
    KJS::Identifier ex("x"), wi("y"), wid("width"), hih("height");

    if ( o.hasProperty(exec, zero) && o.hasProperty(exec, one)
	 && o.hasProperty(exec, two) && o.hasProperty(exec, three) ) {
	x = o.get( exec, zero ).toInteger(exec);
	y = o.get( exec, one ).toInteger(exec);
	w = o.get( exec, two ).toInteger(exec);
	h = o.get( exec, three ).toInteger(exec);
    }
    else if ( o.hasProperty(exec, ex) && o.hasProperty(exec, wi)
	      && o.hasProperty(exec, wid) && o.hasProperty(exec, hih) ) {
	x = o.get( exec, ex ).toInteger(exec);
	y = o.get( exec, wi ).toInteger(exec);
	w = o.get( exec, wid ).toInteger(exec);
	h = o.get( exec, hih ).toInteger(exec);
    }
    else
	return;

    *rect = TQRect( x, y, w, h );
    static_QUType_ptr.set( uo, rect );
}

void JSSlotUtils::implantDate(  KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQDate *date )
{
	TQDateTime jsDate = convertDateToDateTime(exec, v);
	date->setYMD( jsDate.date().year(), jsDate.date().month(), jsDate.date().day() );
	static_QUType_ptr.set( uo, date );
}

void JSSlotUtils::implantStringList(KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQStringList *lst )
{
  *lst = convertArrayToStringList(exec,v);
  static_QUType_ptr.set(uo,lst);
}

void JSSlotUtils::implantTime( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQTime *time )
{
	TQDateTime jsDate = convertDateToDateTime(exec, v);
	time->setHMS( jsDate.time().hour(), jsDate.time().minute(), jsDate.time().second() );
	static_QUType_ptr.set( uo, time );
}

void JSSlotUtils::implantDateTime( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQDateTime *datetime  )
{
	TQDateTime jsDate = convertDateToDateTime(exec, v);
	datetime->setDate( jsDate.date() );
	datetime->setTime( jsDate.time() );
	static_QUType_ptr.set( uo, datetime );
}

void JSSlotUtils::implantPixmap( KJS::ExecState *exec, TQUObject *uo, const KJS::Value &v, TQPixmap *pix )
{
    *pix = convertToVariant(exec, v).toPixmap() ;
    static_QUType_ptr.set( uo, pix );
}

bool JSSlotUtils::implantTQVariant( KJS::ExecState *, TQUObject *uo, const KJS::Value &v)
{
    JSValueProxy *prx = JSProxy::toValueProxy( v.imp() );
    if ( !prx )
	return false;
    kdDebug(80001) << "We got a " << prx->typeName() << endl;

    static_QUType_TQVariant.set( uo, prx->toVariant() );
    return true;
}

bool JSSlotUtils::implantValueProxy( KJS::ExecState *, TQUObject *uo,
				     const KJS::Value &val, const TQString &clazz )
{
    JSValueProxy *prx = JSProxy::toValueProxy( val.imp() );
    if ( !prx )
	return false;
    if ( prx->typeName() != clazz )
	return false;

    kdDebug(80001) << "We got a " << prx->typeName() << " and is valid " << prx->toVariant().isValid() << endl;
    TQVariant var = prx->toVariant();
    kdDebug(80001) << "We got a " << var.typeName()<< " and is valid " << var.isValid() << endl;
    static_QUType_TQVariant.set( uo, var );
    return var.isValid();
}

bool JSSlotUtils::implantOpaqueProxy( KJS::ExecState *, TQUObject *uo,
				      const KJS::Value &v, const TQString &clazz )
{
    JSOpaqueProxy *prx = JSProxy::toOpaqueProxy( v.imp() );
    if ( !prx )
	return false;
    if ( prx->typeName() != clazz )
	return false;

    static_QUType_ptr.set( uo, prx->toNative<void>() );
    return true;
}

bool JSSlotUtils::implantObjectProxy( KJS::ExecState *, TQUObject *uo,
				      const KJS::Value &v, const TQString &clazz )
{
    JSObjectProxy *prx = JSProxy::toObjectProxy( v.imp() );
    if ( !prx )
	return false;

    if ( !prx->object()->inherits( clazz.latin1() ) )
	return false;

    static_QUType_ptr.set( uo, prx->toObjectProxy()->object() );
    return true;
}

int JSSlotUtils::findSignature( const TQString &sig )
{
    // No args
    if ( sig.contains("()") )
	return SignatureNone;

    // One arg
    if ( sig.contains("(int)") )
	return SignatureInt;
    else if ( sig.contains("(uint)") )
	return SignatureUInt;
    else if ( sig.contains("(long)") )
	return SignatureLong;
    else if ( sig.contains("(ulong)") )
	return SignatureULong;
    else if ( sig.contains("(bool)") )
	return SignatureBool;
    else if ( sig.contains("(double)") )
	return SignatureDouble;

    else if ( sig.contains("(const TQString&)") )
	return SignatureString;
    else if ( sig.contains("(const TQCString&)") )
	return SignatureCString;
    else if ( sig.contains("(const char*)") )
	return SignatureCString;
    else if ( sig.contains("(const KURL&)") )
	return SignatureURL;
    else if ( sig.contains("(const TQColor&)") )
	return SignatureColor;
    else if ( sig.contains("(const TQPoint&)") )
	return SignaturePoint;
    else if ( sig.contains("(const TQRect&)") )
	return SignatureRect;
    else if ( sig.contains("(const TQSize&)") )
	return SignatureSize;
    else if ( sig.contains("(const TQPixmap&)") )
	return SignaturePixmap;
    else if ( sig.contains("(const TQFont&)") )
	return SignatureFont;
    else if ( sig.contains("(const TQDate&)") )
	return SignatureDate;
    else if ( sig.contains("(const TQTime&)") )
	return SignatureTime;
    else if ( sig.contains("(const TQDateTime&)") )
	return SignatureDateTime;
    else if ( sig.contains("(const TQImage&)") )
	return SignatureImage;
    else if ( sig.contains("(TQWidget*)") )
	return SignatureTQWidget;
    // Two args
    else if ( sig.contains("(const TQDate&, const TQDate&)") )
	return SignatureDateDate;
    else if ( sig.contains("(const TQColor&, const TQString&)") )
	return SignatureColorString;

    else if ( sig.contains("(const TQString&,const TQString&,const TQString&)") )
	return SignatureStringStringString;

    else if ( sig.contains("(const TQString&,const TQString&)") )
	return SignatureStringString;
    else if ( sig.contains("(int,int)") )
	return SignatureIntInt;
    else if ( sig.contains("(int,int,int,int)") )
	return SignatureIntIntIntInt;
    else if ( sig.contains("(int,int,int,int,int)") )
	return SignatureIntIntIntIntInt;
    else if ( sig.contains("(int,int,int,int,bool)") )
	return SignatureIntIntIntIntBool;

    else if ( sig.contains("(const TQString&,int)") )
	return SignatureStringInt;
    else if ( sig.contains("(const TQString&,uint)") )
	return SignatureStringInt;

    else if ( sig.contains("(const KURL&,const KURL&)") )
	return SignatureURLURL;
    else if ( sig.contains("(const KURL&,const TQString&)") )
	return SignatureURLString;
    else if ( sig.contains("(const TQString&,const KURL&)") )
	return SignatureStringURL;
    else if ( sig.contains("(const TQRect&,bool)") )
	return SignatureRectBool;
    else if ( sig.contains("(const TQString&,bool)") )
	return SignatureStringBool;
    else if ( sig.contains("(int,bool)") )
	return SignatureIntBool;
    else if ( sig.contains("(int,int,bool)") )
	return SignatureIntIntBool;
    else if ( sig.contains("(int,int,const TQString&)") )
	return SignatureIntIntString;
    else if ( sig.contains("(const TQString&,bool,int)") )
	return SignatureStringBoolInt;
    else if ( sig.contains("(const TQString&,bool,bool)") )
	return SignatureStringBoolBool;
    else if ( sig.contains("(const TQString&,int,int)") )
	return SignatureStringIntInt;
    else if ( sig.contains("(int,const TQColor&,bool)") )
	return SignatureIntColorBool;
    else if ( sig.contains("(int,const TQColor&)") )
	return SignatureIntColor;

    else if ( sig.contains("(int,int,float,float)") )
	return SignatureIntIntFloatFloat;
    else if ( sig.contains("(const TQString&,bool,bool,bool)") )
	return SignatureStringBoolBoolBool;
    else if ( sig.contains("(int,int,int,int,int,int)") )
	return SignatureIntIntIntIntIntInt;

    // Handle anything that falls through
    if ( sig.contains("TQString") || sig.contains("TQColor") ||
	sig.contains("int") || sig.contains("bool") ||
        sig.contains("float") || sig.contains("KURL") ||
        sig.contains("TQVariant") || sig.contains("TQSize") ||
        sig.contains("TQRect") || sig.contains("TQPixmap") ||
        sig.contains("TQCString") || sig.contains("TQPoint") ||
	sig.contains("double") || sig.contains("TQFont") ||
	sig.contains("TQDate") || sig.contains("TQTime") ||
	sig.contains("TQDateTime") || sig.contains("TQStringList") ||
	sig.contains("TQWidget") || sig.contains("TQObject") ||
	sig.contains("TQPen") || sig.contains("TQImage") )
	   return SignatureCustom;

    kdWarning(80001) << "findSignature: not supported type " << sig << endl;
    return SignatureNotSupported;
}

#define MAX_SUPPORTED_ARGS (12)

KJS::Value JSSlotUtils::invokeSlot( KJS::ExecState *exec, KJS::Object &, const KJS::List &args,
				    JSObjectProxyImp *proxyimp )
{
    TQUObject uo[ MAX_SUPPORTED_ARGS ] = { TQUObject(), TQUObject(), TQUObject(),
					  TQUObject(), TQUObject(), TQUObject(),
					  TQUObject(), TQUObject(), TQUObject(),
					  TQUObject(), TQUObject(), TQUObject() };

    KJS::Value retValue;
    JSObjectProxy *proxy = proxyimp->objectProxy();
    TQCString slotname( proxyimp->slotName() );
    int sigid = proxyimp->signature();
    TQPtrList<uint> uintlist;
    uintlist.setAutoDelete(true);
    TQObject *obj = proxy->object();
    int slotid = obj->metaObject()->findSlot( slotname, true );
    if ( slotid == -1 )
    {
	TQString msg = i18n( "Slot %1 was not found." ).arg( slotname );
  return throwError(exec, msg,KJS::ReferenceError);
    }

    if ( args.size() > MAX_SUPPORTED_ARGS )
    {
	TQString msg = i18n( "Slots with more than %1 arguments are not supported." ).arg( MAX_SUPPORTED_ARGS );
  return throwError(exec, msg,KJS::ReferenceError);
    }
    // Keep args in scope for duration of the method.
    KURL url[MAX_SUPPORTED_ARGS];
    TQColor color[MAX_SUPPORTED_ARGS];
    TQPoint point[MAX_SUPPORTED_ARGS];
    TQSize size[MAX_SUPPORTED_ARGS];
    TQRect rect[MAX_SUPPORTED_ARGS];
    TQDate date[MAX_SUPPORTED_ARGS];
    TQDateTime datetime[MAX_SUPPORTED_ARGS];
    TQTime time[MAX_SUPPORTED_ARGS];
    TQPixmap pix[MAX_SUPPORTED_ARGS];
    TQStringList slst[MAX_SUPPORTED_ARGS];
    
    bool notsupported = true;

    if ( args.size() == 1 ) {
	//kdDebug( 80001 ) << "One Arg" << endl;
	switch (sigid) {
	    case SignatureInt:
		implantInt( exec, uo+1, args[0] );
		break;
	    case SignatureBool:
		implantBool( exec, uo+1, args[0] );
		break;
	    case SignatureString:
		implantTQString( exec, uo+1, args[0] );
		break;
	    case SignatureCString:
		implantCString( exec, uo+1, args[0] );
		break;
	    case SignatureDouble:
		implantDouble( exec, uo+1, args[0] );
		break;
	    case SignatureURL:
		implantURL( exec, uo+1, args[0], &url[0] );
		break;
	    case SignatureColor:
		implantColor( exec, uo+1, args[0], &color[0] );
		break;
	    case SignaturePoint:
		implantPoint( exec, uo+1, args[0], &point[0] );
		break;
	    case SignatureSize:
		implantSize( exec, uo+1, args[0], &size[0] );
		break;
	    case SignatureRect:
		implantRect( exec, uo+1, args[0], &rect[0] );
		break;
	    default:
		notsupported = true;
		break;
	}

    } else if ( args.size() == 2 ) {
	//kdDebug( 80001 ) << "Two Args" << endl;
	switch (sigid) {
	    case SignatureIntInt:
		implantInt( exec, uo+1, args[0] );
		implantInt( exec, uo+2, args[1] );
		break;
	    case SignatureStringInt:
		implantTQString( exec, uo+1, args[0] );
		implantInt( exec, uo+2, args[1] );
		break;
	    case SignatureRectBool:
		implantRect( exec, uo+1, args[0], &rect[0] );
		implantBool( exec, uo+2, args[1] );
		break;
	    case SignatureStringString:
		implantTQString( exec, uo+1, args[0] );
		implantTQString( exec, uo+2, args[1] );
		break;
	    case SignatureStringBool:
		implantTQString( exec, uo+1, args[0] );
		implantBool( exec, uo+2, args[1] );
		break;
	    case SignatureIntColor:
		implantInt( exec, uo+1, args[0] );
		implantColor( exec, uo+2, args[1], &color[0] );
		break;
	    case SignatureURLURL:
		implantURL( exec, uo+1, args[0], &url[0] );
		implantURL( exec, uo+2, args[1], &url[1] );
		break;
	    case SignatureURLString:
		implantURL( exec, uo+1, args[0], &url[0] );
		implantTQString( exec, uo+2, args[1] );
		break;
	    case SignatureStringURL:
		implantTQString( exec, uo+1, args[0] );
		implantURL( exec, uo+2, args[1], &url[0] );
		break;

	    default:
		notsupported = true;
		break;
	}

    } else  {
	//kdDebug( 80001 ) << args.size() << " Args" << endl;
	notsupported = false;
	switch (sigid) {
	    case SignatureNone:
		break;
	    case SignatureStringStringString:
		if ( args.size() != 3 )
		    return KJS::Null();
		implantTQString( exec, uo+1, args[0] );
		implantTQString( exec, uo+2, args[1] );
		implantTQString( exec, uo+3, args[2] );
		break;
	    case SignatureIntIntString:
		if ( args.size() != 3 )
		    return KJS::Null();
		implantInt( exec, uo+1, args[0] );
		implantInt( exec, uo+2, args[1] );
		implantTQString( exec, uo+3, args[2] );
		break;
	    case SignatureIntIntIntInt:
		if ( args.size() != 4 )
		    return KJS::Null();
		implantInt( exec, uo+1, args[0] );
		implantInt( exec, uo+2, args[1] );
		implantInt( exec, uo+3, args[2] );
		implantInt( exec, uo+4, args[3] );
		break;
	    case SignatureIntIntIntIntBool:
		if ( args.size() != 5 )
		    return KJS::Null();
		implantInt( exec, uo+1, args[0] );
		implantInt( exec, uo+2, args[1] );
		implantInt( exec, uo+3, args[2] );
		implantInt( exec, uo+4, args[3] );
		implantBool( exec, uo+5, args[4] );
		break;
	    case SignatureIntIntIntIntIntInt:
		if ( args.size() != 6 )
		    return KJS::Null();
		implantInt( exec, uo+1, args[0] );
		implantInt( exec, uo+2, args[1] );
		implantInt( exec, uo+3, args[2] );
		implantInt( exec, uo+4, args[3] );
		implantInt( exec, uo+5, args[4] );
		implantInt( exec, uo+6, args[5] );
		break;
	    default:
		notsupported = true;
	}
    }

    if ( notsupported ) {
	//kdDebug( 80001 ) << "Trying method 2" << endl;
        // Rip apart the call signature to get the args slow but effective.
	notsupported = false;
	int argsStart = slotname.find('(');
	int argsEnd = slotname.find(')');
        TQString fargs = slotname.mid( argsStart+1, argsEnd-argsStart-1 );

	// Iterate over the parameters
        TQStringList argList = TQStringList::split(',', fargs, true);
	uint count = TQMIN( argList.count(), MAX_SUPPORTED_ARGS );

	kdDebug( 80001 ) << "======== arg count " << count << endl;
        for( uint idx = 0; idx < count; idx++ ) {
	    kdDebug( 80001 ) << "======== Handling arg " << idx << endl;

	    TQString arg = argList[idx];
	    arg = arg.replace("const", "");
	    arg = arg.replace("&", "");
	    arg = arg.simplifyWhiteSpace();
	    kdDebug( 80001 ) << "Testing " << arg.latin1() << endl;

	    if(arg.contains("uint") == 1) {
		unsigned int *unsignedint=new uint;
		*unsignedint=args[idx].toUInt32(exec);
		uintlist.append(unsignedint);
		static_QUType_ptr.set( uo+1+idx, unsignedint) ;
	    }
	    else if( arg.contains("int") == 1 )
		implantInt( exec, uo+1+idx, args[idx] );
	    else if ( arg.contains("double") == 1 )
		implantDouble(exec,  uo+1+idx, args[idx]);
	    else if ( arg.contains("TQStringList") == 1 )
		implantStringList( exec, uo+1+idx, args[idx], &slst[idx] );
	    else if ( arg.contains("TQString") == 1 )
		implantTQString(exec,  uo+1+idx, args[idx] );
	    else if ( arg.contains("TQCString") == 1 )
		implantCString(exec,  uo+1+idx, args[idx] );
	    else if ( arg.contains("bool") == 1 )
		implantBool( exec, uo+1+idx, args[idx] );
	    else if ( arg.contains("KURL") == 1 )
		implantURL( exec, uo+1+idx, args[idx], &url[idx] );
	    else if ( arg.contains("TQColor") == 1 )
	        implantColor( exec, uo+1+idx, args[idx], &color[idx] );
	    else if ( arg.contains("TQPoint") == 1 )
		implantPoint( exec, uo+1+idx, args[idx], &point[idx] );
	   else if ( arg.contains("TQSize") == 1 )
		implantSize( exec, uo+1+idx, args[idx], &size[idx] );
	   else if ( arg.contains("TQRect") == 1 )
		implantRect( exec, uo+1+idx, args[idx], &rect[idx] );
	   else if ( arg.contains("TQDate") == 1 )
		implantDate( exec, uo+1+idx, args[idx], &date[idx] );
	   else if ( arg.contains("TQTime") == 1 )
		implantTime( exec, uo+1+idx, args[idx], &time[idx] );
	   else if ( arg.contains("TQDateTime") == 1 )
		implantDateTime( exec, uo+1+idx, args[idx], &datetime[idx] );
	   else if ( arg.contains("TQPixmap") == 1 )
		implantPixmap( exec, uo+1+idx, args[idx], &pix[idx] );
	   else if ( arg.contains("char") == 1)
	        implantCharStar( exec, uo+1+idx, args[idx] );
	    else if ( ( arg.contains("TQObject") == 1 ) || ( arg.contains("TQWidget") == 1 ) )
	   {
	   	kdDebug( 80001 ) << "Doing a TQObject" << endl;
		notsupported = !implantObjectProxy( exec, uo+1+idx, args[idx], "TQObject" );
	   }
	    else if ( TQVariant::nameToType(arg.latin1()) != TQVariant::Invalid ) {
		bool ok = implantValueProxy( exec, uo+1+idx, args[idx], arg );
		if ( !ok ) {
		    notsupported = true;
		    break;
		}
		else
		{
			kdDebug( 80001 ) << "Implanted the variant " << static_QUType_TQVariant.get(uo+1+idx).isValid() << endl;
		}
	    }
	    /* else if ( ( arg.contains("TQVariant") == 1 ) ||
	        ( arg.contains("TQPen") == 1 ) || (arg.contains("TQFont") == 1 )  ||
		( arg.contains("TQBrush") == 1 ))
		if(!implantTQVariant(exec,  uo+1+idx, args[idx] )){
		    notsupported = true;
		    break;
		} */
	    else if ( arg.contains("*") == 1 ) {
		TQRegExp re("(\\w+)\\*");
		if ( re.search(arg) >= 0 ) {
		    bool ok = implantObjectProxy( exec, uo+1+idx, args[idx], re.cap(1) );
		    if ( !ok ) {
			ok = implantOpaqueProxy( exec, uo+1+idx, args[idx], re.cap(1) );
			if ( !ok ) {
			    notsupported = true;
			    break;
			}
		    }
		}
		else {
		    notsupported = true;
		    break;
		}
	    }  else {
		notsupported = true;
		break; // Abort on the first unsupported parameter
	    }
        }
    }

    if ( notsupported ) {
	kdWarning(80001) << "Signature " << slotname << " has not been implemented" << endl;
	return KJS::Null();
    } else {
        kdDebug(80001) << "Call Signature: " << slotname << endl;

	obj->tqt_invoke( slotid, uo );
    }
    // Handle return types
    TQCString ret( proxyimp->returnType() );
    if ( ret.isEmpty() ) {
	// Basic type (void, int etc.)
	return extractValue( exec, uo );
    }

    // Object type
    kdDebug(80001) << "Handling a pointer return of type " << ret << endl;

    if ( proxy->part()->factory()->isTQObject(ret) ) {
	kdDebug(80001) << "Return type is TQObject " << ret << endl;
	return extractValue( exec, uo, proxy );
    }

    // Opaque type
    kdDebug(80001) << "Return type is opaque " << ret << endl;

    JSOpaqueProxy *opaque = new JSOpaqueProxy(static_QUType_ptr.get(uo), ret.data());
    //opaque->setValue(  );

    KJS::Object opaqueObj( opaque );
    opaque->addBindings( exec, opaqueObj );

    return opaqueObj;
}

} // namespace KJSEmbed::Bindings
} // namespace KJSEmbed
