/*
 *  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., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 */

#include <qapplication.h>
#include <qobject.h>
#include <qobjectlist.h>
#include <qdialog.h>
#include <qhbox.h>
#include <qlayout.h>
#include <qlistbox.h>
#include <qlistview.h>
#include <qmetaobject.h>
#include <qpainter.h>
#include <qregexp.h>
#include <qsignal.h>
#include <qstrlist.h>
#include <qtabwidget.h>
#include <qtimer.h>
#include <qvariant.h>

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

#ifndef QT_ONLY

#include <kaction.h>
#include "global.h"
#include <klistview.h>
#include <kurl.h>
#include <kmainwindow.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 "customobject_imp.h"

#ifndef QT_ONLY
#include "bindings/qcombobox_imp.h"
#endif // QT_ONLY

#include "jsbinding.h"

namespace KJSEmbed {
namespace Bindings {

void CustomObjectImp::addBindings( KJS::ExecState *exec, KJS::Object &object )
{
    CustomObjectImp *obj = 0;

    JSObjectProxy *proxy = JSProxy::toObjectProxy( object.imp() );
    if ( !proxy )
	return;

    QObject *qobj = proxy->object();
    QWidget *widget = proxy->widget();

#ifndef QT_ONLY    
    if ( qobj ) {
	KXMLGUIClient *gc = dynamic_cast<KXMLGUIClient *>( qobj );
	if ( gc ) {
	    obj = new CustomObjectImp( exec, KXMLGUIClientActionCollection, proxy );
	    object.put( exec, "actionCollection", KJS::Object(obj) );
	}
    }
#endif // QT_ONLY

    if ( widget ) {
	obj = new CustomObjectImp( exec, WidgetGrabWidget, proxy );
	object.put(exec, "grabWidget", KJS::Object(obj));
	obj = new CustomObjectImp( exec, WidgetDrawLine, proxy );
	object.put( exec, "drawLine", KJS::Object(obj) );
	obj = new CustomObjectImp( exec, WidgetDrawText, proxy );
	object.put( exec, "drawText", KJS::Object(obj) );

	QListBox *listbox = dynamic_cast<QListBox *>( widget );
	if ( listbox ) {
	    obj = new CustomObjectImp( exec, ListBoxInsertItem, proxy );
	    object.put( exec, "insertItem", KJS::Object(obj) );
	}

	QListView *listview = dynamic_cast<QListView *>( widget );
	if ( listview ) {
	    obj = new CustomObjectImp( exec, ListViewAddColumn, proxy );
	    object.put( exec, "addColumn", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, ListViewInsertItem, proxy );
	    object.put( exec, "insertItem", KJS::Object(obj) );
	}

#ifndef QT_ONLY	
	KMainWindow *mw = dynamic_cast<KMainWindow *>( widget );
	if ( mw ) {
	    obj = new CustomObjectImp( exec, MainWindowSetCentralWidget, proxy );
	    object.put( exec, "setCentralWidget", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, MainWindowCreateGUI, proxy );
	    object.put( exec, "createGUI", KJS::Object(obj) );
	}
#endif // QT_ONLY

	QTabWidget *tw = dynamic_cast<QTabWidget *>( widget );
	if ( tw ) {
	    obj = new CustomObjectImp( exec, TabWidgetAddTab, proxy );
	    object.put( exec, "addTab", KJS::Object(obj) );
	}

	QScrollView *sv = dynamic_cast<QScrollView *>( widget );
	if ( sv ) {
	    obj = new CustomObjectImp( exec, ScrollViewViewport, proxy );
	    object.put( exec, "viewport", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, ScrollViewAddChild, proxy );
	    object.put( exec, "addChild", KJS::Object(obj) );
	}

#ifndef QT_ONLY
	QComboBox *cb = dynamic_cast<QComboBox *>( widget );
	if ( cb ) {
	    QComboBoxImp::addBindings( exec, object );
	}
#endif // QT_ONLY

	QHBox *hbox = dynamic_cast<QHBox *>( widget );
	if ( hbox ) {
	    obj = new CustomObjectImp( exec, HBoxSpacing, proxy );
	    object.put( exec, "setSpacing", KJS::Object(obj) );
	}

	return;
    }

    if ( qobj ) {
	QApplication *app = dynamic_cast<QApplication *>( qobj );
	if ( app ) {
	    obj = new CustomObjectImp( exec, ApplicationExec, proxy );
	    object.put( exec, "exec", KJS::Object(obj) );
	}

#ifndef QT_ONLY	
	
	KParts::ReadOnlyPart *ropart = dynamic_cast<KParts::ReadOnlyPart *>( qobj );
	if ( ropart ) {
	    obj = new CustomObjectImp( exec, KReadOnlyPartOpenStream, proxy );
	    object.put( exec, "openStream", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, KReadOnlyPartWriteStream, proxy );
	    object.put( exec, "writeStream", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, KReadOnlyPartCloseStream, proxy );
	    object.put( exec, "closeStream", KJS::Object(obj) );
	}
#endif // QT_ONLY	

	QTimer *timer = dynamic_cast<QTimer *>( qobj );
	if ( timer ) {
	    obj = new CustomObjectImp( exec, TimerIsActive, proxy );
	    object.put( exec, "isActive", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, TimerStart, proxy );
	    object.put( exec, "start", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, TimerStop, proxy );
	    object.put( exec, "stop", KJS::Object(obj) );
	}

	QBoxLayout *box = dynamic_cast<QBoxLayout *>( qobj );
	if ( box ) {
	    obj = new CustomObjectImp( exec, BoxLayoutAddWidget, proxy );
	    object.put( exec, "addWidget", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, BoxLayoutAddSpacing, proxy );
	    object.put( exec, "addSpacing", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, BoxLayoutAddStretch, proxy );
	    object.put( exec, "addStretch", KJS::Object(obj) );
	    obj = new CustomObjectImp( exec, BoxLayoutAddLayout, proxy );
	    object.put( exec, "addLayout", KJS::Object(obj) );
    	}

    }
}

CustomObjectImp::CustomObjectImp( KJS::ExecState *exec, int mid, JSObjectProxy *parent )
    : JSProxyImp(exec), id(mid), proxy(parent)
{
}

KJS::Value CustomObjectImp::call( KJS::ExecState *exec, KJS::Object &self, const KJS::List &args )
{
    switch( id ) {
	case WidgetGrabWidget:
	    return widgetGrabWidget( exec, self, args );
	case WidgetDrawLine:
	    widgetDrawLine( exec, self, args );
	    return KJS::Value();
	case WidgetDrawText:
	    widgetDrawText( exec, self, args );
	    return KJS::Value();
	case ListBoxInsertItem:
	    listBoxInsertItem( exec, self, args );
	    return KJS::Value();
	case ListViewAddColumn:
	    listViewAddColumn( exec, self, args );
	    return KJS::Value();
	case ListViewInsertItem:
	    listViewInsertItem( exec, self, args );
	    return KJS::Value();
	case MainWindowSetCentralWidget:
	    mainWinSetCentralWidget( exec, self, args );
	    return KJS::Value();
	case MainWindowCreateGUI:
	    mainWinCreateGUI( exec, self, args );
	    return KJS::Value();
	case TabWidgetAddTab:
	    tabWidgetAddTab( exec, self, args );
	    return KJS::Value();
	case ScrollViewViewport:
	    return scrollViewViewport( exec, self, args );
	case ScrollViewAddChild:
	    scrollViewAddChild( exec, self, args );
	    return KJS::Value();
	case ApplicationExec:
	    return applicationExec( exec, self, args );
	case TimerIsActive:
	    return timerIsActive( exec, self, args );
	case TimerStart:
	    return timerStart( exec, self, args );
	case TimerStop:
	    return timerStop( exec, self, args );
	case BoxLayoutAddWidget:
	    boxLayoutAddWidget( exec, self, args );
	    return KJS::Value();
	case BoxLayoutAddSpacing:
	    boxLayoutAddSpacing( exec, self, args );
	    return KJS::Value();
	case BoxLayoutAddStretch:
	    boxLayoutAddStretch( exec, self, args );
	    return KJS::Value();
	case BoxLayoutAddLayout:
	    boxLayoutAddLayout( exec, self, args );
	    return KJS::Value();
	case URLRequesterSetMode:
	case URLRequesterSetFilter:
	case URLRequesterUrl:
	case URLRequesterSetLocalProtocol:
	case URLRequesterLocalProtocol:
	    kdWarning() << "CustomObjectImp unsupported method call " << id << endl;
	    break;
	case KXMLGUIClientActionCollection:
	    return xmlguiClientActionCollection( exec, self, args );
	case KReadOnlyPartOpenStream:
	    return kroPartOpenStream( exec, self, args );
	case KReadOnlyPartWriteStream:
	    return kroPartWriteStream( exec, self, args );
	case KReadOnlyPartCloseStream:
	    return kroPartCloseStream( exec, self, args );
	case HBoxSpacing:
	    hboxSpacing( exec, self, args );
	    return KJS::Value();
	default:
	    break;
    }

    return KJS::ObjectImp::call( exec, self, args );
}

KJS::Value CustomObjectImp::widgetGrabWidget(KJS::ExecState *exec, KJS::Object &, const KJS::List & )
{
	QWidget *w = proxy->widget();
	if ( !w )
		return KJS::Value();
	QVariant pix(QPixmap::grabWidget(w) );
	return convertToValue( exec, pix );

}
void CustomObjectImp::widgetDrawLine( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( args.size() != 4 )
	return;

    QWidget *w = proxy->widget();
    if ( !w )
	return;

    int x = args[0].toInteger( exec );
    int y = args[1].toInteger( exec );
    int x1 = args[2].toInteger( exec );
    int y1 = args[3].toInteger( exec );

    QPainter p(w);
    p.drawLine(x,y,x1,y1);
}

void CustomObjectImp::widgetDrawText( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( args.size() != 3 )
	return;

    QWidget *w = proxy->widget();
    if ( !w )
	return;

    int x = args[0].toInteger( exec );
    int y = args[1].toInteger( exec );
    QString s = args[2].toString(exec).qstring();
    w->drawText( x, y, s );
}

void CustomObjectImp::listBoxInsertItem( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( args.size() != 1 )
	return;

    QListBox *lb = dynamic_cast<QListBox *>( proxy->object() );
    if ( !lb )
	return;

    QString s = args[0].toString(exec).qstring();
    lb->insertItem( s );
}

void CustomObjectImp::listViewAddColumn( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( args.size() != 1 )
	return;

    QListView *lv = dynamic_cast<QListView *>( proxy->object() );
    if ( !lv )
	return;

    QString s = args[0].toString(exec).qstring();
    lv->addColumn( s );
}

void CustomObjectImp::listViewInsertItem( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( !args.size() )
	return;

#ifndef QT_ONLY
    
    KListView *klv = dynamic_cast<KListView *>( proxy->object() );
    if ( klv ) {
	KListViewItem *lvm = new KListViewItem(klv);

	for( int idx = 0; idx < args.size(); ++idx){
		QVariant arg = convertToVariant(exec, args[idx]);
		if( arg.canCast(QVariant::String) )
			lvm->setText(idx, arg.toString());
		else if ( arg.canCast(QVariant::Pixmap) )
			lvm->setPixmap(idx, arg.toPixmap());
	}
	return;
    }

#endif // QT_ONLY

    QListView *lv = dynamic_cast<QListView *>( proxy->object() );
    if ( lv ) {
	QListViewItem *lvm = new QListViewItem(lv);

	for( int idx = 0; idx < args.size(); ++idx){
		QVariant arg = convertToVariant(exec, args[idx]);
		if( arg.canCast(QVariant::String) )
			lvm->setText(idx, arg.toString());
		else if ( arg.canCast(QVariant::Pixmap) )
			lvm->setPixmap(idx, arg.toPixmap());
	}

    }
}

void CustomObjectImp::mainWinSetCentralWidget( KJS::ExecState *exec,
						KJS::Object &, const KJS::List &args )
{
#ifndef QT_ONLY	

    if ( args.size() != 1 )
	return;

    KJS::Object jsobj = args[0].toObject(exec);
    JSObjectProxy *cwproxy = JSProxy::toObjectProxy( jsobj.imp() );
    QWidget *cw = cwproxy ? cwproxy->widget() : 0;
    if ( !cw )
	return;
    KMainWindow *mw = dynamic_cast<KMainWindow *>( proxy->object() );
    if ( !mw )
	return;

    mw->setCentralWidget( cw );

#else // QT_ONLY
    Q_UNUSED( exec );	
    Q_UNUSED( args );	
    return;
#endif // QT_ONLY	
}

void CustomObjectImp::mainWinCreateGUI( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
#ifndef QT_ONLY	
    kdDebug(80001) << "mainWinCreateGUI() called" << endl;
    KMainWindow *mw = dynamic_cast<KMainWindow *>( proxy->object() );
    if ( !mw ) {
	kdWarning() << "mainWinCreateGUI() called on non-KMainWindow" << endl;
	return;
    }

    mw->createGUI( args[0].toString(exec).qstring() );
#else // QT_ONLY	
    Q_UNUSED( exec );	
    Q_UNUSED( args );	
    return;
#endif // QT_ONLY	
}

KJS::Value CustomObjectImp::xmlguiClientActionCollection( KJS::ExecState *exec, KJS::Object&, const KJS::List& )
{
#ifndef QT_ONLY	
    KXMLGUIClient *gc = dynamic_cast<KXMLGUIClient *>( proxy->object() );
    if ( !gc ) {
	kdDebug(80001) << "Unable to cast to XMLGUIClient" << endl;
	return KJS::Value();
    }

    KActionCollection *ac = gc->actionCollection();
    if (!ac) {
	kdDebug(80001) << "XMLGUIClient action collection is null" << endl;
	return KJS::Null();
    }

    return proxy->part()->factory()->createProxy( exec, ac, proxy );
#else // QT_ONLY	
    Q_UNUSED( exec );		
    return KJS::Value();
#endif // QT_ONLY	
}

void CustomObjectImp::tabWidgetAddTab( KJS::ExecState *exec, KJS::Object&, const KJS::List &args )
{
    if ( args.size() < 2 )
	return;

    QTabWidget *tw = dynamic_cast<QTabWidget *>( proxy->object() );
    if ( !tw )
	return;

    KJS::Object jsobj = args[0].toObject(exec);
    JSObjectProxy *tproxy = JSProxy::toObjectProxy( jsobj.imp() );
    QWidget *w = tproxy ? tproxy->widget() : 0;
    if ( !w )
	return;

    tw->addTab( w, args[1].toString(exec).qstring() );
}

KJS::Value CustomObjectImp::scrollViewViewport( KJS::ExecState *exec, KJS::Object&, const KJS::List &args )
{
    QScrollView *sv = dynamic_cast<QScrollView *>( proxy->object() );
    if ( !sv )
	return KJS::Value();

    KJS::Object jsobj = args[0].toObject(exec);
    JSObjectProxy *sproxy = JSProxy::toObjectProxy( jsobj.imp() );
    QWidget *w = sproxy ? sproxy->widget() : 0;
    if ( !w )
	return KJS::Value();

    return proxy->part()->factory()->createProxy( exec, w, proxy );
}

void CustomObjectImp::scrollViewAddChild( KJS::ExecState *exec, KJS::Object&, const KJS::List &args )
{
    if ( args.size() < 1 )
	return;

    QScrollView *sv = dynamic_cast<QScrollView *>( proxy->object() );
    if ( !sv )
	return;

    KJS::Object jsobj = args[0].toObject(exec);
    JSObjectProxy *sproxy = JSProxy::toObjectProxy( jsobj.imp() );
    QWidget *w = sproxy ? sproxy->widget() : 0;
    if ( !w )
	return;

    int x = args.size() >= 2 ? args[1].toInteger( exec ) : 0;
    int y = args.size() >= 3 ? args[2].toInteger( exec ) : 0;

    sv->addChild( w, x, y );
}

KJS::Value CustomObjectImp::applicationExec( KJS::ExecState *, KJS::Object&, const KJS::List& )
{
    QApplication *app = dynamic_cast<QApplication *>( proxy->object() );
    if ( !app )
	return KJS::Value();

    return KJS::Number( app->exec() );
}

KJS::Value CustomObjectImp::timerIsActive( KJS::ExecState *, KJS::Object &, const KJS::List & )
{
    QTimer *timer = dynamic_cast<QTimer *>( proxy->object() );
    if ( !timer )
	return KJS::Value();

    return KJS::Boolean( timer->isActive() );
}

KJS::Value CustomObjectImp::timerStart( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    QTimer *timer = dynamic_cast<QTimer *>( proxy->object() );
    if ( !timer )
	return KJS::Value();

    int timerid;
    if ( args.size() == 1 )
	timerid = timer->start( args[0].toInteger(exec) );
    else if ( args.size() == 2 )
	timerid = timer->start( args[0].toInteger(exec), args[1].toBoolean(exec) );
    else
	return KJS::Value();

    return KJS::Number( timerid );
}

KJS::Value CustomObjectImp::timerStop( KJS::ExecState *, KJS::Object &, const KJS::List & )
{
    QTimer *timer = dynamic_cast<QTimer *>( proxy->object() );
    if ( !timer )
	return KJS::Value();

    timer->stop();
    return KJS::Value();
}

void CustomObjectImp::boxLayoutAddWidget( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( (args.size() < 1) || (args.size() > 3) )
	return;

    QBoxLayout *box = dynamic_cast<QBoxLayout *>( proxy->object() );
    if ( !box )
	return;

    KJS::Object jsobj = args[0].toObject(exec);
    JSObjectProxy *proxy = JSProxy::toObjectProxy( jsobj.imp() );
    QWidget *w = proxy ? proxy->widget() : 0;
    if ( !w )
	return;

    if ( args.size() == 1 )
	box->addWidget( w );
    else if ( args.size() == 2 )
	box->addWidget( w, args[1].toInteger(exec) );
    else if ( args.size() == 3 )
	box->addWidget( w, args[1].toInteger(exec), args[2].toInteger(exec) );
}

void CustomObjectImp::boxLayoutAddSpacing( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( args.size() != 1 )
	return;

    QBoxLayout *box = dynamic_cast<QBoxLayout *>( proxy->object() );
    if ( !box )
	return;

    box->addSpacing( args[0].toInteger(exec) );
}

void CustomObjectImp::boxLayoutAddStretch( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( args.size() > 1 )
	return;

    QBoxLayout *box = dynamic_cast<QBoxLayout *>( proxy->object() );
    if ( !box )
	return;

    if ( args.size() == 0 )
	box->addStretch();
    else
	box->addStretch( args[0].toInteger(exec) );
}

void CustomObjectImp::boxLayoutAddLayout( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( (args.size() < 1) || (args.size() > 2) )
	return;

    QBoxLayout *box = dynamic_cast<QBoxLayout *>( proxy->object() );
    if ( !box )
	return;

    KJS::Object jsobj = args[0].toObject(exec);
    JSObjectProxy *proxy = JSProxy::toObjectProxy( jsobj.imp() );
    QLayout *l = proxy ? (dynamic_cast<QLayout *>(proxy->object())) : 0;
    if ( !l )
	return;

    if ( args.size() == 1 )
	box->addLayout( l );
    else if ( args.size() == 2 )
	box->addLayout( l, args[1].toInteger(exec) );
}

KJS::Value CustomObjectImp::kroPartOpenStream( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
#ifndef QT_ONLY

    if ( args.size() != 2 )
	return KJS::Boolean( false );

    KParts::ReadOnlyPart *ro = dynamic_cast<KParts::ReadOnlyPart *>( proxy->object() );
    if ( !ro )
	return KJS::Boolean( false );

    bool ok = ro->openStream( args[0].toString(exec).qstring(), KURL(args[1].toString(exec).qstring()) );
    return KJS::Boolean( ok );

#else // QT_ONLY
    Q_UNUSED( exec );	
    Q_UNUSED( args );	
    return KJS::Boolean( false );
#endif // QT_ONLY
}

KJS::Value CustomObjectImp::kroPartWriteStream( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
#ifndef QT_ONLY

    if ( args.size() != 1 )
	return KJS::Boolean( false );

    KParts::ReadOnlyPart *ro = dynamic_cast<KParts::ReadOnlyPart *>( proxy->object() );
    if ( !ro )
	return KJS::Boolean( false );

    QCString s = args[0].toString(exec).ascii();
    bool ok = ro->writeStream( s );
    return KJS::Boolean( ok );

#else // QT_ONLY
    Q_UNUSED( exec );	
    Q_UNUSED( args );	
    return KJS::Boolean( false );
#endif // QT_ONLY
}

KJS::Value CustomObjectImp::kroPartCloseStream( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
#ifndef QT_ONLY

    if ( args.size() != 0 )
	return KJS::Boolean( false );

    KParts::ReadOnlyPart *ro = dynamic_cast<KParts::ReadOnlyPart *>( proxy->object() );
    if ( !ro )
	return KJS::Boolean( false );

    bool ok = ro->closeStream();
    return KJS::Boolean( ok );

#else // QT_ONLY
    Q_UNUSED( exec );	
    Q_UNUSED( args );	
    return KJS::Boolean( false );
#endif // QT_ONLY
}

void CustomObjectImp::hboxSpacing( KJS::ExecState *exec, KJS::Object &, const KJS::List &args )
{
    if ( args.size() != 1 )
	return;

    QHBox *box = dynamic_cast<QHBox *>( proxy->object() );
    if ( !box )
	return;

    box->setSpacing( args[0].toInteger(exec) );
}


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

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

