/*
*  Copyright (C) 2001-2004, 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 <stdio.h>
#include <string.h>
#include <errno.h>

#include <tqobject.h>
#include <tqcombobox.h>
#include <tqdialog.h>
#include <tqdir.h>
#include <tqfile.h>
#include <tqimage.h>
#include <tqlistview.h>
#include <tqmainwindow.h>
//#include <tqpainter.h>
#include <tqprogressdialog.h>
#include <tqtextstream.h>
#include <tqtimer.h>
#include <tqwidget.h>
#include <tqwidgetfactory.h>
#include <tqsplitter.h>
#include <tqscrollview.h>
#include <tqcanvas.h>
#include <tqlayout.h>
#include <tqsplashscreen.h>

#ifndef QT_ONLY

#include <tdeapplication.h>
#include <dcopref.h>
#include <dcopclient.h>
#include <tdeaction.h>
#include <klibloader.h>
#include <tdelocale.h>
#include <tdemainwindow.h>
#include <kservice.h>
#include <ksystemtray.h>
#include <ktrader.h>

#include <tdeparts/part.h>
#include <tdeparts/mainwindow.h>
#include <tdeparts/componentfactory.h>

#endif // QT_ONLY

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

#include "jsbinding.h"
#include "jsbindingbase.h"
#include "jsobjectproxy.h"
#include "jsopaqueproxy.h"
#include "jsvalueproxy.h"
#include "jsconsolewidget.h"
#include "jseventmapper.h"
#include "jseventutils.h"
#include "kjsembedpart.h"
#include "customobject_imp.h"

#include "builtins/stddialog_imp.h"
#include "builtins/textstream_imp.h"
#include "builtins/qdir_imp.h"

#include "qtbindings/qcombobox_imp.h"
#include "qtbindings/qpopupmenu_imp.h"
#include "qtbindings/qlistviewitem_imp.h"
#include "qtbindings/qchecklistitem_imp.h"
#include "qtbindings/qcanvasellipse_imp.h"
#include "qtbindings/qcanvas_imp.h"
#include "qtbindings/qcanvasitem_imp.h"
#include "qtbindings/qcanvasitemlist_imp.h"
#include "qtbindings/qcanvasline_imp.h"
#include "qtbindings/qcanvaspixmaparray_imp.h"
#include "qtbindings/qcanvaspixmap_imp.h"
#include "qtbindings/qcanvaspolygonalitem_imp.h"
#include "qtbindings/qcanvaspolygon_imp.h"
#include "qtbindings/qcanvasrectangle_imp.h"
#include "qtbindings/qcanvasspline_imp.h"
#include "qtbindings/qcanvassprite_imp.h"
#include "qtbindings/qcanvastext_imp.h"
#include "qtbindings/qcanvasview_imp.h"


#ifndef QT_ONLY

#include "builtins/stdaction_imp.h"

#include "bindings/dcop_imp.h"
#include "bindings/netaccess_imp.h"
#endif // QT_ONLY

#include "bindings/image_imp.h"
#include "bindings/pen_imp.h"
#include "bindings/pixmap_imp.h"
#include "bindings/painter_imp.h"
#include "bindings/movie_imp.h"
#include "bindings/sql_imp.h"
#include "bindings/tdeconfig_imp.h"
#include "bindings/brush_imp.h"
#include "bindings/size_imp.h"
#include "bindings/rect_imp.h"
#include "bindings/point_imp.h"


#include "global.h"
#include "jsbindingplugin.h"
#include "jsfactory_imp.h"
#include "jsfactory.h"

//
// KPart Implementation
//
namespace KJSEmbed {

    typedef Bindings::JSFactoryImp JSFactoryImp;
    typedef Bindings::CustomObjectImp CustomObjectImp;
    typedef BuiltIns::StdDialogImp StdDialogImp;
    typedef BuiltIns::TextStreamImp TextStreamImp;

    class JSFactoryPrivate {
    public:
        TQDict<KJSEmbed::Bindings::JSBindingPlugin> plugins;
        TQDict<KJSEmbed::Bindings::JSBindingBase> opaqueTypes;
        TQDict<KJSEmbed::Bindings::JSBindingBase> objectTypes;
    };


    JSFactory::JSFactory( KJSEmbedPart *part )
            : jspart( part ) {
        evmapper = new JSEventMapper();
        d = new JSFactoryPrivate;
        registerOpaqueType("TQDir", new Bindings::TQDirLoader());
        registerOpaqueType("TQCheckListItem", new Bindings::TQCheckListItemLoader());
        registerOpaqueType("TQListViewItem", new Bindings::TQListViewItemLoader());
        registerOpaqueType("Painter", new Bindings::PainterLoader());

#ifndef QT_ONLY
        registerOpaqueType("DCOPClient", new Bindings::JSDCOPClientLoader());
        registerObjectType("DCOPInterface", new Bindings::JSDCOPInterfacerLoader());
        registerOpaqueType("DCOPRef", new Bindings::JSDCOPRefLoader());
#endif

    }

    JSFactory::~JSFactory() {
        delete evmapper;
    }

    void JSFactory::addBindingPluginTypes( KJS::ExecState *exec, KJS::Object &parent ) {
#ifndef QT_ONLY

        // Get list of valid plugin types
        TDETrader::OfferList offers = TDETrader::self() ->query( "JSBindingPlugin/Binding" );
        if ( !offers.count() )
            return ;

        TDETrader::OfferListIterator itr = offers.begin();
        while ( itr != offers.end() ) {
            TQString classname = ( *itr ) ->name();
            JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classname );
            parent.put( exec, KJS::Identifier( cons->parameter() ), KJS::Object( cons ) );
            addType( classname, TypePlugin );
            ++itr;
        }
#else
        Q_UNUSED( exec );
        Q_UNUSED( parent );
#endif // QT_ONLY

    }

    bool JSFactory::isBindingPlugin( const TQString &classname ) const {
        if ( !isSupported( classname ) )
            return false;
        return ( objtypes[ classname ] & TypePlugin );
    }

    KJS::Object JSFactory::createBindingPlugin( KJS::ExecState *exec, const TQString &classname, const KJS::List &args ) {
#ifndef QT_ONLY

        Bindings::JSBindingPlugin * plugin = d->plugins[ classname ];
        if ( plugin == 0L ) {
            TQString query = "JSBindingPlugin/Binding";
            TQString constraint = "[Name] == '" + classname + "'";
            plugin = KParts::ComponentFactory::createInstanceFromQuery<Bindings::JSBindingPlugin>( query, constraint );
            if ( plugin != 0L )
                d->plugins.insert( classname, plugin );
        }

        if ( plugin != 0L )
            return plugin->createBinding( jspart, exec, args );

#else

        Q_UNUSED( exec );
        Q_UNUSED( args );
#endif // QT_ONLY

        kdWarning( 80001 ) << "Unable to load binding " << classname << "." << endl;

        return KJS::Object();
    }

    KJS::Object JSFactory::create( KJS::ExecState *exec, const TQString &classname, const KJS::List &args ) {
        KJS::Object returnObject;
        if ( !isSupported( classname ) ) {
            TQString msg = i18n( "Object of type '%1' is not supported." ).arg( classname );
            return throwError(exec, msg,KJS::TypeError);
        }
        if ( isTQObject( classname ) ) {
            // create via widget factory...
            Bindings::JSBindingBase *factory =  d->objectTypes.find(classname);
            if( factory ) {
                returnObject = factory->createBinding( jspart, exec, args );
                JSProxy::toProxy( returnObject.imp() ) ->setOwner( JSProxy::JavaScript );
            } else {
                TQObject *parent = extractTQObject(exec, args, 0);
                TQString name = extractTQString(exec, args, 1);
    
                TQObject *obj = create( classname, parent, name.latin1() );
                if ( obj ) {
                    returnObject = createProxy( exec, obj );
                    JSProxy::toProxy( returnObject.imp() ) ->setOwner( JSProxy::JavaScript );
                } else {
                    TQString msg = i18n( "TQObject of type '%1' could not be created." ).arg( classname );
                    returnObject = throwError(exec, msg,KJS::TypeError);
                }
            }
        } else if ( isOpaque( classname ) ) {
            // Try to create from the registry
            Bindings::JSBindingBase *factory =  d->opaqueTypes.find(classname);
            if( factory )
                returnObject = factory->createBinding( jspart, exec, args );
            else
                returnObject = createOpaque( exec, classname, args );

            if ( !returnObject.isValid() ) {
                TQString msg = i18n( "Opaque object of type '%1' could not be created." ).arg( classname );
                returnObject = throwError(exec, msg,KJS::TypeError);
            }
        } else if ( isValue( classname ) ) {
            returnObject = createValue( exec, classname, args );
            if ( !returnObject.isValid() ) {
                TQString msg = i18n( "Value object of type '%1' could not be created." ).arg( classname );
                returnObject = throwError(exec, msg,KJS::TypeError);
            }
        } else if ( isBindingPlugin( classname ) ) {
            returnObject = createBindingPlugin( exec, classname, args );
            if ( !returnObject.isValid() ) {
                TQString msg = i18n( "Plugin object of type '%1' could not be created." ).arg( classname );
                returnObject = throwError(exec, msg,KJS::TypeError);
            } else
                JSProxy::toProxy( returnObject.imp() ) ->setOwner( JSProxy::JavaScript );
        } else {
            TQString msg = i18n( "Could not create object of type '%1'." ).arg( classname );
            returnObject = throwError(exec, msg,KJS::TypeError);
        }
        return returnObject;
    }

    KJS::Object JSFactory::createProxy( KJS::ExecState *exec, TQObject *target,
                                        const JSObjectProxy *ctx ) const {
        kdDebug( 80001 ) << "JSFactory::createProxy: Target '" << target->name()
        << "' type " << target->className() << endl;

        JSObjectProxy *prx;
        if ( ctx )
            prx = new JSObjectProxy( jspart, target, ctx->rootObject(), ctx->securityPolicy() );
        else {
            prx = new JSObjectProxy( jspart, target );

        }
        kdDebug( 80001 ) << "Proxy created" << endl;

        KJS::Object proxyObj( prx );
        prx->addBindings( exec, proxyObj );
        extendProxy( exec, proxyObj );
        prx->setOwner(JSProxy::Native);
        
        kdDebug( 80001 ) << "Returning object" << endl;

        return proxyObj;
    }

    KJS::Object JSFactory::createProxy( KJS::ExecState *exec,
                                        TQTextStream *target, const JSObjectProxy *context ) const {
        Q_UNUSED( context )
        kdDebug( 80001 ) << "TextStream proxy created" << endl;

        JSOpaqueProxy *prx = new JSOpaqueProxy( target );
        KJS::Object proxyObj( prx );
        prx->addBindings( exec, proxyObj );
        TextStreamImp::addBindings( exec, proxyObj );

        return proxyObj;
    }

    KJS::Object JSFactory::createProxy( KJS::ExecState *exec,
                                        TQEvent *target, const JSObjectProxy *context ) const {
        switch ( target->type() ) {
            case TQEvent::MouseButtonPress:
            case TQEvent::MouseButtonRelease:
            case TQEvent::MouseMove:
            case TQEvent::MouseButtonDblClick:
                return JSEventUtils::convertEvent( exec, ( TQMouseEvent * ) target, context );
                break;
            case TQEvent::KeyPress:
            case TQEvent::KeyRelease:
            case TQEvent::Accel:
            case TQEvent::AccelOverride:
                return JSEventUtils::convertEvent( exec, ( TQKeyEvent * ) target, context );
                break;
            case TQEvent::IMStart:
            case TQEvent::IMCompose:
            case TQEvent::IMEnd:
                return JSEventUtils::convertEvent( exec, ( TQIMEvent * ) target, context );
                break;
            case TQEvent::Paint:
                return JSEventUtils::convertEvent( exec, ( TQPaintEvent * ) target, context );
                break;
            case TQEvent::Resize:
                return JSEventUtils::convertEvent( exec, ( TQResizeEvent * ) target, context );
                break;
            case TQEvent::FocusIn:
            case TQEvent::FocusOut:
                return JSEventUtils::convertEvent( exec, ( TQFocusEvent * ) target, context );
                break;
            case TQEvent::Close:
                return JSEventUtils::convertEvent( exec, ( TQCloseEvent * ) target, context );
                break;
            case TQEvent::ChildInserted:
            case TQEvent::ChildRemoved:
                return JSEventUtils::convertEvent( exec, ( TQChildEvent * ) target, context );
                break;
            case TQEvent::Move:
                return JSEventUtils::convertEvent( exec, ( TQMoveEvent * ) target, context );
                break;
            case TQEvent::Wheel:
                return JSEventUtils::convertEvent( exec, ( TQWheelEvent * ) target, context );
                break;
            case TQEvent::Timer:
                return JSEventUtils::convertEvent( exec, ( TQTimerEvent * ) target, context );
                break;
            case TQEvent::ContextMenu:
                return JSEventUtils::convertEvent( exec, ( TQContextMenuEvent * ) target, context );
                break;
            case TQEvent::DragMove:
            case TQEvent::DragEnter:
                return JSEventUtils::convertEvent( exec, ( TQDragMoveEvent * ) target, context );
                break;
            case TQEvent::Drop:
                return JSEventUtils::convertEvent( exec, ( TQDropEvent * ) target, context );
                break;
            case TQEvent::Enter:
            case TQEvent::Leave:
            case TQEvent::Clipboard:
            case TQEvent::DragLeave:
            case TQEvent::Show:
            case TQEvent::Hide:
                return JSEventUtils::convertEvent( exec, ( TQEvent * ) target, context );
                break;
            default:
                break;
        }

        return JSEventUtils::convertEvent( exec, ( TQEvent * ) target, context );
    }

    KJS::Object JSFactory::extendProxy( KJS::ExecState *exec, KJS::Object &target ) const {
        CustomObjectImp::addBindings( exec, target );
        addBindingsPlugin( exec, target );
        return target;
    }

    void JSFactory::addBindingsPlugin( KJS::ExecState *exec, KJS::Object &target ) const {
        kdDebug( 800001 ) << "JSFactory::addBindingsPlugin" << endl;
        JSObjectProxy *proxy = JSProxy::toObjectProxy( target.imp() );
        if ( !proxy )
            return ;
        if ( !isBindingPlugin( proxy->object() ->className() ) )
            return ;

#ifndef QT_ONLY

        Bindings::JSBindingPlugin *plugin = d->plugins[ proxy->object() ->className() ];
        if ( plugin == 0L ) {
            TQString query = "JSBindingPlugin/Binding";
            TQString constraint = "[Name] == '" + TQString::fromUtf8( proxy->object() ->className() ) + "'";
            plugin = KParts::ComponentFactory::createInstanceFromQuery<Bindings::JSBindingPlugin>( query, constraint );
            if ( plugin != 0L )
                d->plugins.insert( proxy->object() ->className(), plugin );
        }

        if ( plugin != 0L ) {
            kdDebug( 800001 ) << "JSFactory::addBindingsPlugin: calling plugin function" << endl;
            plugin->addBindings( exec, target );
            return ;
        }
#else
        Q_UNUSED( exec );
#endif // QT_ONLY

        kdWarning( 80001 ) << "Unable to add bindings to " << proxy->object() ->className() << "." << endl;
        return ;

    }


    TQObject *JSFactory::createBinding( const TQString &cname, TQObject *parent, const char *name ) {
#ifndef QT_ONLY

        // Bindings
        /*if ( cname == "DCOPInterface" )
            return new Bindings::JSDCOPInterface( jspart->interpreter(), parent, name );
        else */if ( cname == "NetAccess" )
            return new Bindings::NetAccess( parent, name );
        else
#endif // QT_ONLY
            if ( cname == "Movie" )
                return new Bindings::Movie( parent, name );
            else if ( cname == "SqlDatabase" )
                return new Bindings::SqlDatabase( parent, name );
            else if ( cname == "SqlQuery" )
                return new Bindings::SqlQuery( parent, name );
            else if ( cname == "Config" )
                return new Bindings::Config( parent, name );

        return 0;
    }

    TQObject *JSFactory::createObject( const TQString &cname, TQObject *parent, const char *name ) {

        // TQObjects defined by Qt
        if ( cname == "TQObject" )
            return new TQObject( parent, name );
        else if ( cname == "TQTimer" )
            return new TQTimer( parent, name );
        else if ( cname == "TQCanvas" )
            return new TQCanvas( parent, name );

#ifndef QT_ONLY
        // TQObjects defined by KDE
        else if ( cname == "TDEAction" )
            return new TDEAction( parent, name );
        else if ( cname == "TDEToggleAction" )
            return new TDEToggleAction( parent, name );
#endif // QT_ONLY

        TQWidget *w = dynamic_cast<TQWidget *>( parent );
        if ( !w )
            return 0;

        if ( cname == "TQHBoxLayout" )
            return new TQHBoxLayout( w, 0, -1, name );
        else if ( cname == "TQVBoxLayout" )
            return new TQVBoxLayout( w, 0, -1, name );
        return 0;
    }

    KJS::Object JSFactory::createOpaque( KJS::ExecState *exec, const TQString &cname, const KJS::List &args ) {

        if ( cname == "TQCanvasText" ) {
                    kdDebug( 80001 ) << "Creating canvas item, type is " << cname << endl;

                    JSOpaqueProxy *prx = 0;

                    if ( args.size() == 0 ) {
                        // FALL THRU
                    } else if ( args.size() == 1 ) {

                        JSObjectProxy * arg0 = JSProxy::toObjectProxy( args[ 0 ].imp() );

                        if ( arg0 ) {

                            TQObject * obj0 = arg0->object();

                            if ( obj0->inherits( "TQCanvas" ) ) {
                                TQCanvas * parent = ( TQCanvas * ) ( obj0 );
                                prx = new JSOpaqueProxy( new TQCanvasText( parent ), "TQCanvasText" );

                                KJS::Object proxyObj( prx );
                                TQCanvasItemImp::addBindings( exec, proxyObj );
                                TQCanvasTextImp::addBindings( exec, proxyObj );
                                return proxyObj;
                            } else {
                                kdDebug( 80001 ) << " canvas item create failed, arg0 is " << obj0->className() << endl;
                                return KJS::Object();
                            }
                        } else {
                            kdDebug( 80001 ) << " canvas item create failed, arg0 is not an object" << endl;
                            return KJS::Object();
                        }

                    } else if ( args.size() == 2 ) {

                        TQString arg0 = args[ 0 ].toString( exec ).qstring();
                        JSObjectProxy *arg1 = JSProxy::toObjectProxy( args[ 1 ].imp() );

                        if ( arg1 ) {

                            TQString arg0 = args[ 0 ].toString( exec ).qstring();
                            TQObject *obj1 = arg1->object();

                            if ( obj1->inherits( "TQCanvas" ) ) {
                                TQCanvas * parent = ( TQCanvas * ) ( obj1 );
                                prx = new JSOpaqueProxy( new TQCanvasText( parent ), "TQCanvasText" );

                                KJS::Object proxyObj( prx );
                                TQCanvasItemImp::addBindings( exec, proxyObj );
                                TQCanvasTextImp::addBindings( exec, proxyObj );
                                return proxyObj;
                            } else {
                                kdDebug( 80001 ) << " canvas item create failed, arg0 is " << obj1->className() << endl;
                                return KJS::Object();
                            }
                        } else {
                            kdDebug( 80001 ) << " canvas item create failed, arg1 is not an object" << endl;
                            return KJS::Object();
                        }
                    }
                }


        return KJS::Object();
    }

    KJS::Object JSFactory::createValue( KJS::ExecState *exec, const TQString &cname, const KJS::List & args ) {
        if ( cname == "Image" ) {
            TQImage img = TQImage();
            JSValueProxy *prx = new JSValueProxy( );
            prx->setValue( img );
            KJS::Object proxyObj( prx );
            Bindings::ImageImp::addBindings( exec, proxyObj );
            return proxyObj;
        }
        if ( cname == "Pixmap" ) {
            TQPixmap pix = TQPixmap();
            JSValueProxy *prx = new JSValueProxy( );
            prx->setValue( pix );
            KJS::Object proxyObj( prx );
            Bindings::Pixmap::addBindings( exec, proxyObj );
            return proxyObj;
        }
        if ( cname == "Brush" ) {
            TQBrush brsh;
            JSValueProxy *prx = new JSValueProxy( );
            prx->setValue( brsh );
            KJS::Object proxyObj( prx );
            Bindings::BrushImp::addBindings( exec, proxyObj );
            return proxyObj;
        }
        if ( cname == "Pen" ) {
            TQPen pen;
            JSValueProxy *prx = new JSValueProxy( );
            prx->setValue( pen );
            KJS::Object proxyObj( prx );
            Bindings::Pen::addBindings( exec, proxyObj );
            return proxyObj;
        }
        if ( cname == "Rect" ) {
            TQRect rect;
            if ( args.size() == 4 ) {
                rect.setX( extractInt( exec, args, 0 ) );
                rect.setY( extractInt( exec, args, 1 ) );
                rect.setWidth( extractInt( exec, args, 2 ) );
                rect.setHeight( extractInt( exec, args, 3 ) );
            }
            JSValueProxy *prx = new JSValueProxy( );
            prx->setValue( rect );
            KJS::Object proxyObj( prx );
            Bindings::Rect::addBindings( exec, proxyObj );
            return proxyObj;
        }
        if ( cname == "Point" ) {
            TQPoint point;
            if ( args.size() == 2 ) {
                point.setX( extractInt( exec, args, 0 ) );
                point.setY( extractInt( exec, args, 1 ) );
            }
            JSValueProxy *prx = new JSValueProxy( );
            prx->setValue( point );
            KJS::Object proxyObj( prx );
            Bindings::Point::addBindings( exec, proxyObj );
            return proxyObj;
        }
        if ( cname == "Size" ) {
            TQSize size;
            if ( args.size() == 2 ) {
                size.setWidth( extractInt( exec, args, 0 ) );
                size.setHeight( extractInt( exec, args, 1 ) );
            }
            JSValueProxy *prx = new JSValueProxy( );
            prx->setValue( size );
            KJS::Object proxyObj( prx );
            Bindings::Size::addBindings( exec, proxyObj );
            return proxyObj;
        }


        return KJS::Object();
    }

    TQWidget *JSFactory::createWidget( const TQString &cname, TQWidget *pw, const char *name ) {
        if ( cname == "TQSplitter" )
            return new TQSplitter( pw, name );
        else if ( cname == "TQMainWindow" )
            return new TQMainWindow( pw, name );
        else if ( cname == "TQProgressDialog" )
            return new TQProgressDialog( pw, name );
        else if ( cname == "TQScrollView" )
            return new TQScrollView( pw, name );
        else if ( cname == "TQCanvasView" )
            return new TQCanvasView( pw, name );
        else if ( cname == "TQSplashScreen" ) {
            TQPixmap pix( 16, 16 );
            pix.fill();
            return new TQSplashScreen( pix );
        }
#ifndef QT_ONLY
        else if ( cname == "TDEMainWindow" )
            return new TDEMainWindow( pw, name );
        else if ( cname == "KParts_MainWindow" )
            return new KParts::MainWindow( pw, name );
        else if ( cname == "KSystemTray" )
            return new KSystemTray( pw, name );
#endif // QT_ONLY

        return 0;
    }

    TQObject *JSFactory::create( const TQString &cname, TQObject *parent, const char *name ) {
        kdDebug( 80001 ) << "KJSEmbedPart::create() name " << name << " class " << cname << endl;

        // Factory widgets
        TQWidgetFactory wf;
        TQWidget *pw = ( parent && parent->isWidgetType() ) ? static_cast<TQWidget *>( parent ) : 0;
        TQWidget *w = wf.createWidget( cname, pw, name );
        if ( w ) {
            kdDebug( 80001 ) << "Created from factory" << endl;
            return w;
        }
        // Custom widgets
        TQObject *obj;
        obj = createWidget( cname, pw, name );
        if ( obj ) {
            if ( !isTQObject( obj->className() ) )
                addType( obj->className() );
            kdDebug( 80001 ) << "Created from createWidget" << endl;
            return obj;
        }

        // Custom objects
        obj = JSFactory::createObject( cname, parent, name );
        if ( obj ) {
            if ( !isTQObject( obj->className() ) )
                addType( obj->className() );
            kdDebug( 80001 ) << "Created from createObject" << endl;
            return obj;
        }

        // Binding objects
        obj = JSFactory::createBinding( cname, parent, name );
        if ( obj ) {
            if ( !isTQObject( obj->className() ) )
                addType( obj->className() );
            kdDebug( 80001 ) << "Created from bindings" << endl;
            return obj;
        }

        kdDebug( 80001 ) << "Found nothing in :" << cname << ":" << endl;
        return 0;
    }

    KParts::ReadOnlyPart *JSFactory::createROPart( const TQString &svc, TQObject *parent, const char *name ) {
        kdDebug( 80001 ) << "JSFactory::createROPart svc " << svc << " parent " << ( long ) parent << endl;
        return createROPart( svc, "'KParts/ReadOnlyPart' in ServiceTypes", parent, name );
    }

    KParts::ReadOnlyPart *JSFactory::createROPart( const TQString &svc, const TQString &con,
            TQObject *parent, const char *name ) {
        kdDebug( 80001 ) << "JSFactory::createROPart svc " << svc << " constraint " << con
        << " parent " << ( long ) parent << endl;

        return createROPart( svc, con, parent, name, TQStringList() );
    }

    KParts::ReadOnlyPart *JSFactory::createROPart( const TQString &svc, const TQString &con,
            TQObject *parent, const char *name,
            const TQStringList &args ) {
#ifndef QT_ONLY
        kdDebug( 80001 ) << "JSFactory::createROPart svc " << svc << " constraint " << con
        << " parent " << ( long ) parent
        << " args: " << args << endl;

        TDETrader::OfferList offers = TDETrader::self() ->query( svc, con );
        if ( !offers.count() )
            return 0;

        KService::Ptr ptr = offers.first();
        KLibFactory *fact = KLibLoader::self() ->factory( ptr->library().ascii() );
        if ( !fact ) {
            kdDebug( 80001 ) << "Unable to find a matching part" << endl;
            return 0;
        }

        TQObject *obj = fact->create( parent, name, "KParts::ReadOnlyPart", args );
        addType( obj->className() );
        return static_cast<KParts::ReadOnlyPart *>( obj );
#else // QT_ONLY

        Q_UNUSED( svc );
        Q_UNUSED( con );
        Q_UNUSED( parent );
        Q_UNUSED( name );
        Q_UNUSED( args );
        return 0;
#endif // QT_ONLY

    }

    KParts::ReadWritePart *JSFactory::createRWPart( const TQString &svc, TQObject *parent, const char *name ) {
        kdDebug( 80001 ) << "JSFactory::createRWPart svc " << svc << " parent " << ( long ) parent << endl;
        return createRWPart( svc, "'KParts/ReadWritePart' in ServiceTypes", parent, name );
    }

    KParts::ReadWritePart *JSFactory::createRWPart( const TQString &svc, const TQString &con,
            TQObject *parent, const char *name ) {
        kdDebug( 80001 ) << "JSFactory::createRWPart svc " << svc << " constraint " << con
        << " parent " << ( long ) parent << endl;

        return createRWPart( svc, con, parent, name, TQStringList() );
    }

    KParts::ReadWritePart *JSFactory::createRWPart( const TQString &svc, const TQString &con,
            TQObject *parent, const char *name,
            const TQStringList &args ) {
#ifndef QT_ONLY
        kdDebug( 80001 ) << "JSFactory::createRWPart svc " << svc << " constraint " << con
        << " parent " << ( long ) parent
        << " args: " << args << endl;

        TDETrader::OfferList offers = TDETrader::self() ->query( svc, con );
        if ( !offers.count() )
            return 0;

        KService::Ptr ptr = offers.first();
        KLibFactory *fact = KLibLoader::self() ->factory( ptr->library().ascii() );
        if ( !fact ) {
            kdDebug( 80001 ) << "Unable to find a matching part" << endl;
            return 0;
        }

        TQObject *obj = fact->create( parent, name, "KParts::ReadWritePart", args );
        addType( obj->className() );
        return static_cast<KParts::ReadWritePart *>( obj );
#else // QT_ONLY

        Q_UNUSED( svc );
        Q_UNUSED( con );
        Q_UNUSED( parent );
        Q_UNUSED( name );
        Q_UNUSED( args );
        return 0;
#endif // QT_ONLY

    }

    TQWidget *JSFactory::loadUI( const TQString &uiFile, TQObject *connector, TQWidget *parent, const char *name ) {
        return TQWidgetFactory::create( uiFile, connector, parent, name );
    }

    TQStringList JSFactory::listBindingPlugins( KJS::ExecState *exec, KJS::Object &self ) {
        Q_UNUSED( exec )
        Q_UNUSED( self )
        TQStringList pluginList;
        TQStringList allTypes = objtypes.keys();
        for ( uint idx = 0; idx < allTypes.count(); ++idx ) {
            if ( objtypes[ allTypes[ idx ] ] & TypePlugin )
                pluginList.append( allTypes[ idx ] );
        }
        return pluginList;
    }

    bool JSFactory::isTQObject( const TQString &clazz ) const {
        if ( !isSupported( clazz ) )
            return false;

        return ( objtypes[ clazz ] & TypeTQObject );
    }

    bool JSFactory::isValue( const TQString &clazz ) const {
        if ( !isSupported( clazz ) )
            return false;

        return objtypes[ clazz ] == TypeValue;
    }

    bool JSFactory::isOpaque( const TQString &clazz ) const {
        if ( !isSupported( clazz ) )
            return false;
        return objtypes[ clazz ] == TypeOpaque;
    }

    void JSFactory::addTQObjectPlugin( const TQString &classname, KJSEmbed::Bindings::JSBindingPlugin* plugin ) {
        if ( plugin ) {
            addType( classname, TypeTQObjectPlugin );
            d->plugins.insert( classname, plugin );
        }
    }

    void JSFactory::addType( const TQString &clazz, uint prxtype ) {
        if ( prxtype == TypeInvalid ) {
            objtypes.remove( clazz );
            return ;
        }
        kdDebug() << "Add type " << clazz << endl;
        objtypes[ clazz ] = prxtype;
    }

    bool JSFactory::isSupported( const TQString &clazz ) const {
        kdDebug() << "Checking " << clazz << endl;
        return objtypes.contains( clazz );
    }

    uint JSFactory::proxyType( const TQString &clazz ) const {
        if ( !isSupported( clazz ) )
            return TypeInvalid;
        return objtypes[ clazz ];
    }

    void JSFactory::addTypes( KJS::ExecState *exec, KJS::Object &parent ) {
        addWidgetFactoryTypes( exec, parent );
        addCustomTypes( exec, parent );
        addBindingTypes( exec, parent );
        addObjectTypes( exec, parent );
        addOpaqueTypes( exec, parent );
        addValueTypes( exec, parent );
        addBindingPluginTypes( exec, parent );
    }

    TQStringList JSFactory::types() const {
        return objtypes.keys();
    }

    void JSFactory::addWidgetFactoryTypes( KJS::ExecState *exec, KJS::Object &parent ) {
        TQStringList sl = TQWidgetFactory::widgets();

        for ( TQStringList::Iterator it = sl.begin(); it != sl.end(); ++it ) {
            JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, *it );
            parent.put( exec, KJS::Identifier( KJS::UString( cons->parameter() ) ), KJS::Object( cons ) );
            addType( *it );
        }
    }

    void JSFactory::addCustomTypes( KJS::ExecState *exec, KJS::Object &parent ) {
        const char * classes[] = {

                                     "TQSplitter", "TQScrollView", "TQCanvasView", "TQCanvas",
                                     "TQObject", "TQTimer", "TQSplashScreen", "TQProgressDialog",
                                     "TQLayout", "TQBoxLayout", "TQHBoxLayout", "TQVBoxLayout",
#ifndef QT_ONLY
                                     "TDEMainWindow", "KXMLGUIClient", "KSystemTray",
                                     "TDEAction", "TDEToggleAction",
                                     "KParts_MainWindow",
#endif // QT_ONLY
                                     0
                                 };

        for ( int i = 0 ; classes[ i ] ; i++ ) {
            JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classes[ i ] );
            parent.put( exec, KJS::Identifier( KJS::UString( cons->parameter() ) ), KJS::Object( cons ) );
            addType( classes[ i ] );
        }
    }

    void JSFactory::addBindingTypes( KJS::ExecState *exec, KJS::Object &parent ) {


        const char * bindings[] = {
                                      "Pixmap", "KJSEmbed::Bindings::Pixmap",
                                      "SqlDatabase", "KJSEmbed::Bindings::SqlDatabase",
                                      "Movie", "KJSEmbed::Bindings::Movie",
                                      "SqlQuery", "KJSEmbed::Bindings::SqlQuery",
#ifndef QT_ONLY
                                      "NetAccess", "KJSEmbed::Bindings::NetAccess",
                                      /*"DCOPInterface", "KJSEmbed::Bindings::JSDCOPInterface",*/
#endif
                                      "Config", "KJSEmbed::Bindings::Config",
                                      0, 0
                                  };

        for ( int i = 0 ; bindings[ i ] ; i += 2 ) {
            JSFactoryImp * cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, bindings[ i ] );
            parent.put( exec, KJS::Identifier( KJS::UString( cons->parameter() ) ), KJS::Object( cons ) );
            addType( bindings[ i ] );
            addType( bindings[ i + 1 ] );
        }

       

    }

    void JSFactory::addOpaqueTypes( KJS::ExecState *exec, KJS::Object &parent ) {
        const char * classes[] = {
                                     "TQTextStream",
                                     "TextStream",
                                     "TQCanvasItem",
                                     "TQCanvasText",
                                     0
                                 };

        for ( int i = 0 ; classes[ i ] ; i++ ) {
            JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classes[ i ] );
            parent.put( exec, KJS::Identifier( KJS::UString( cons->parameter() ) ), KJS::Object( cons ) );
            addType( classes[ i ], TypeOpaque );
        }

        // Create the custom added types.
        TQDictIterator<KJSEmbed::Bindings::JSBindingBase> idx( d->opaqueTypes );
        for( ; idx.current(); ++idx){
            JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, idx.currentKey() );
            parent.put( exec, KJS::Identifier( KJS::UString( cons->parameter() ) ), KJS::Object( cons ) );
            addType( idx.currentKey(), TypeOpaque );
        }

    }
    void JSFactory::addValueTypes( KJS::ExecState *exec, KJS::Object &parent ) {
        const char * classes[] = {
                                     "Image",
                                     "Brush",
                                     "Pixmap",
                                     "Pen",
                                     "Rect",
                                     "Size",
                                     "Point",
                                     0
                                 };

        for ( int i = 0 ; classes[ i ] ; i++ ) {
            JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, classes[ i ] );
            parent.put( exec, KJS::Identifier( KJS::UString( cons->parameter() ) ), KJS::Object( cons ) );
            addType( classes[ i ], TypeValue );
        }
    }


    void JSFactory::addObjectTypes( KJS::ExecState *exec, KJS::Object & parent ) {
        const char * classes[] = {
                                     "TQAccel",
                                     "TQAccessibleObject",
                                     "TQAction",
                                     "TQActionGroup",
                                     "TQApplication",
                                     "TQAquaStyle",
                                     "TQAssistantClient",
                                     "TQAxObject",
                                     "TQAxWidget",
                                     "TQButton",
                                     "TQCDEStyle",
                                     "TQClipboard",
                                     "TQColorDialog",
                                     "TQColorDrag",
                                     "TQComboBox",
                                     "TQCommonStyle",
                                     "TQCopChannel",
                                     "TQDataPump",
                                     "TQDateTimeEditBase",
                                     "TQDesktopWidget",
                                     "TQDns",
                                     "TQDockArea",
                                     "TQDockWindow",
                                     "TQDoubleValidator",
                                     "TQDragObject",
                                     "TQEditorFactory",
                                     "TQErrorMessage",
                                     "TQEventLoop",
                                     "TQFileDialog",
                                     "TQFileIconProvider",
                                     "TQFontDialog",
                                     "TQFtp",
                                     "TQGLWidget",
                                     "TQGridLayout",
                                     "TQGridView",
                                     "TQHButtonGroup",
                                     "TQHGroupBox",
                                     "TQHeader",
                                     "TQHttp",
                                     "TQIconDrag",
                                     "TQImageDrag",
                                     "TQInputDialog",
                                     "TQIntValidator",
                                     "TQLocalFs",
                                     "TQMacStyle",
                                     "TQMenuBar",
                                     "TQMessageBox",
                                     "TQMotif",
                                     "TQMotifDialog",
                                     "TQMotifPlusStyle",
                                     "TQMotifStyle",
                                     "TQMotifWidget",
                                     "TQNPInstance",
                                     "TQNPWidget",
                                     "TQNetworkOperation",
                                     "TQNetworkProtocol",
                                     "TQObjectCleanupHandler",
                                     "TQPlatinumStyle",
                                     "TQProcess",
                                     "TQPopupMenu",
                                     "TQProgressDialog",
                                     "TQRegExpValidator",
                                     "TQSGIStyle",
                                     "TQServerSocket",
                                     "TQSessionManager",
                                     "TQSignal",
                                     "TQSignalMapper",
                                     "TQSizeGrip",
                                     "TQSocket",
                                     "TQSocketNotifier",
                                     "TQSound",
                                     "TQSqlDatabase",
                                     "TQSqlDriver",
                                     "TQSqlEditorFactory",
                                     "TQSqlForm",
                                     "TQStatusBar",
                                     "TQStoredDrag",
                                     "TQStyle",
                                     "TQStyleSheet",
                                     "TQTabBar",
                                     "TQTabDialog",
                                     "TQTextDrag",
                                     "TQToolBar",
                                     "TQToolTipGroup",
                                     "TQTranslator",
                                     "TQUriDrag",
                                     "TQUrlOperator",
                                     "TQVButtonGroup",
                                     "TQVGroupBox",
                                     "TQValidator",
                                     "TQWSKeyboardHandler",
                                     "TQWindowsStyle",
                                     "TQWindowsXPStyle",
                                     "TQWorkspace",
                                     "TQXtWidget",

                                     0
                                 };

        for ( int i = 0 ; classes[ i ] ; i++ ) {
            if ( !isSupported( classes[ i ] ) )
                addType( classes[ i ] );
        }
                // Create the custom added types.
        TQDictIterator<KJSEmbed::Bindings::JSBindingBase> idx( d->objectTypes );
        for( ; idx.current(); ++idx){
            JSFactoryImp *cons = new JSFactoryImp( exec, this, JSFactoryImp::NewInstance, idx.currentKey() );
            parent.put( exec, KJS::Identifier( KJS::UString( cons->parameter() ) ), KJS::Object( cons ) );
            addType( idx.currentKey(), TypeTQObject );
        }
    }

    void JSFactory::registerOpaqueType( const TQString & className, KJSEmbed::Bindings::JSBindingBase * bindingFactory )
    {
        d->opaqueTypes.insert(className,bindingFactory);
    } 

    void JSFactory::unregisterOpaqueType( const TQString & className )
    {
        d->opaqueTypes.remove(className);
    }

    void JSFactory::extendOpaqueProxy( KJS::ExecState * exec, KJS::Object &proxy ) const
    {
	JSOpaqueProxy *prx = JSProxy::toOpaqueProxy( proxy.imp() );
	if( prx )
	{
	   kdDebug() << "Looking for " << prx->typeName() << endl;
           Bindings::JSBindingBase *bindingFactory = d->opaqueTypes.find( prx->typeName() );
           if( bindingFactory )
	   {
               kdDebug() << "Extending proxy" << endl;
               bindingFactory->addBindings(jspart, exec, proxy );
	   }
	}
    }
    void JSFactory::registerObjectType( const TQString & className, KJSEmbed::Bindings::JSBindingBase * bindingFactory )
    {
        d->objectTypes.insert(className,bindingFactory);
    } 

    void JSFactory::unregisterObjectType( const TQString & className )
    {
        d->objectTypes.remove(className);
    }

    void JSFactory::extendObjectProxy( KJS::ExecState * exec, KJS::Object &proxy ) const
    {
	JSObjectProxy *prx = JSProxy::toObjectProxy( proxy.imp() );
	if( prx )
	{
	   kdDebug() << "Looking for " << prx->typeName() << endl;
           Bindings::JSBindingBase *bindingFactory = d->objectTypes.find( prx->typeName() );
           if( bindingFactory )
	   {
               kdDebug() << "Extending proxy" << endl;
               bindingFactory->addBindings(jspart, exec, proxy );
	   }
	}
    }
    
}// namespace KJSEmbed

// Local Variables:
// c-basic-offset: 4
// End:
