/****************************************************************************
** $Id: quickobjects.h,v 1.2 2007/04/11 20:44:10 bilboq Exp $
**
** Copyright (C) 2001-2006 Trolltech AS.  All rights reserved.
**
** This file is part of the Qt Script for Applications framework (QSA).
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding a valid Qt Script for Applications license may use
** this file in accordance with the Qt Script for Applications License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
**   information about QSA Commercial License Agreements.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
*****************************************************************************/

#ifndef QUICKOBJECTS_H
#define QUICKOBJECTS_H

#include "quickenv.h"

#include <qvariant.h>
#include <qobject.h>
#include <qptrvector.h>
#include <qptrdict.h>
#include <qmetaobject.h>
#include "dlldefs.h"
#include <qintdict.h>
#include <qmap.h>

#include <qsclass.h>
#include <qstypes.h>
#include <qsfunction.h>

class QuickInterpreter;
class QuickScriptVariant;
class QuickScriptObjectFunc;
class QuickPtrDispatchObject;
class QSFactoryObjectProxy;


extern void stopAllTimers();

QSObject qsStartTimer( QSEnv * );
void qsKillTimer( QSEnv * );
void qsKillTimers( QSEnv * );

QUICKCORE_EXPORT QObjectList *extraChildren( QObject *o );
QUICKCORE_EXPORT QObject *objectChild( QObject *wid, const char *objName, const char *inheritsClass, bool recursiveSearch );
extern QUICKCORE_EXPORT QValueList<QString> *appArgs;

struct EventTarget {
public:
    QuickInterpreter *eng;
    struct Target {
	Target() : ctx( 0 ), qsctx( QSObject() ) {}
	Target( QObject *c, QSObject qs, const QString &f )
	    : ctx( c ), qsctx( qs ), func( f ) {}
	QObject *ctx;
	QSObject qsctx;
	QString func;
    };
    QValueList<Target> targets;

};

struct QuickMetaData : public QMetaData
{
    QuickMetaData():id(-1) {}
    QuickMetaData( const QMetaData* md, int funcid ):  QMetaData(*md), id( funcid ) {}
    int id;

    bool operator==( const QuickMetaData &md ) const {
	return ( md.id == id &&
		 md.name == name &&
		 md.method == method &&
		 md.access == access );
    }
};

typedef QMap<int, EventTarget> QuickScriptEventMap;

class QuickScriptReceiver : public QObject
{
public:
    QuickScriptReceiver( QObject *o );
    ~QuickScriptReceiver();

    void setEventHandler( QuickInterpreter *ip, int id, QObject *scope,
			  const QString &func, QSObject qsctx = QSObject() );
    void removeEventHandler( int id, QObject *scope, const QString &func, QSObject qsctx = QSObject() );
    bool qt_invoke( int id, QUObject *_o );
    void invalidate();

private:
    QObject *qobj;
    QuickScriptEventMap *handler;
};

class QUICKCORE_EXPORT QSOT
{
public:
    enum QuickScriptObjectType { Property, Object, Slot, Enum, Unknown };
};

class QUICKCORE_EXPORT QuickScriptProperty
{
public:
    QuickScriptProperty( QSOT::QuickScriptObjectType t, QuickScriptVariant *v, int on ) : type( t ), objNum( on ) { id.var = v; }
    QuickScriptProperty( QSOT::QuickScriptObjectType t, QuickScriptObjectFunc *f, int on ) : type( t ), objNum( on ) { id.func = f; }
    QuickScriptProperty( QSOT::QuickScriptObjectType t, int v, int on ) : type( t ), objNum( on ) { id.enumValue = v; }
    QuickScriptProperty() : type( QSOT::Unknown ) {}

    QSOT::QuickScriptObjectType type;
    union {
	QuickScriptVariant *var;
	QuickScriptObjectFunc *func;
	int enumValue;
    } id;
    int objNum;
};

#if defined(Q_TEMPLATEDLL)
// MOC_SKIP_BEGIN
template class QUICKCORE_EXPORT QPtrList<QuickScriptReceiver>;
template class QUICKCORE_EXPORT QMap<QObject*, QuickScriptReceiver*>;
template class QUICKCORE_EXPORT QMap<QString, QSOT::QuickScriptObjectType>;
template class QUICKCORE_EXPORT QPtrVector<QObject>;
template class QUICKCORE_EXPORT QMap<QString, QuickScriptProperty>;
template class QUICKCORE_EXPORT QValueList<QuickMetaData>;
template class QUICKCORE_EXPORT QIntDict<char>;
template class QUICKCORE_EXPORT QPtrList<QMetaProperty>;
//template class QUICKCORE_EXPORT QValueList<QVariant>;
// MOC_SKIP_END
#endif

struct QUICKCORE_EXPORT EventId
{
    EventId() : id( -1 ), obj( -1 ) {}
    EventId( int i, int o ) : id( i ), obj( o ) {}
    int id, obj;
};

class QSWrapperClass;
class QSUserData;

class QUICKCORE_EXPORT QSWrapperSharedWatcher: public QObject {
  friend class QSWrapperShared;
  Q_OBJECT
  class QSWrapperShared *parent;

public slots:
    void objectDestroyed(QObject *);
};

class QUICKCORE_EXPORT QSWrapperShared : public QSInstanceData
{
    friend class QSWrapperClass;

public:
    enum ObjectType { FactoryObject, GlobalObject };
    QSWrapperShared( const QSWrapperClass *cl );
    ~QSWrapperShared();

    void setUserData( QSUserData *d ) { udata = d; }
    bool setEventHandler( QuickInterpreter *ip, const QString &event, QObject *ctx,
			  const QString &func, QSObject qsctx = QSObject() );
    bool removeEventHandler( const QString &event, QObject *ctx,
			     const QString &func, QSObject qsctx = QSObject() );
    const QPtrVector<QObject> *interfaceObjects() const { return &objects; }

    QPtrVector<QObject> objects; // interfaces
    QMap<QObject*, QuickScriptReceiver*> receivers; // event receivers
    QMap<QString, QSOT::QuickScriptObjectType> hasPropCache; // caches
    QMap<QString, QuickScriptProperty> propertyCache;
    const QSWrapperClass* wrapperClass() const { return cls; }
    virtual void invalidate(); // overriding QSShared::invalidate()
    void invalidateWrapper();

    ObjectType objectType() const { return objTyp; }
    void setObjectType( ObjectType type ) { objTyp = type; }

    QSFactoryObjectProxy *creator;

private:
    EventId findEventId( const QString &event );
    const QSWrapperClass *cls;
    QSUserData *udata;
    ObjectType objTyp;
    QSWrapperSharedWatcher watcher;
};

class QUICKCORE_EXPORT QSUserData : public QObjectUserData {
public:
    QSUserData( QSWrapperShared *d ) : dat( d ) { }
    ~QSUserData();
    QSWrapperShared* data() const { return dat; }
    void setData( QSWrapperShared *d ) { dat = d; }
    void invalidate() { /* dat->deref(); */ dat = 0; }
private:
    QSWrapperShared *dat;
};


class QUICKCORE_EXPORT QSWrapperClass : public QSWritableClass,
					public QuickEnvClass {
    friend class QSFactoryObjectProxy;
public:
    QSWrapperClass( QSClass *b );
    ~QSWrapperClass();
    QString name() const { return QString::fromLatin1("QObject"); }

    virtual bool member( const QSObject *o, const QString &n,
			 QSMember *m ) const;
    virtual QSObject fetchValue( const QSObject *objPtr,
				 const QSMember &mem ) const;
    virtual void write( QSObject *objPtr, const QSMember &mem,
			const QSObject &val ) const;

    virtual void deref( QSObject *o ) const;

    bool toBoolean( const QSObject * ) const;
    QString toString( const QSObject * ) const;
    QVariant toVariant( const QSObject *obj, QVariant::Type ) const;
    QString debugString( const QSObject *obj ) const;
    QSEqualsResult isEqual( const QSObject &a, const QSObject &b ) const;

    QSObject wrap( const QPtrVector<QObject> &objs );
    QSWrapperShared* createShared( QObject *o ) const;

    QSWrapperShared* shared( const QSObject *obj ) const;
    QPtrVector<QObject>& objectVector( const QSObject *obj ) const;

    static QObject *object(const QSObject *obj);

    void invalidate();

protected:
    virtual QSObject invoke( QSObject *objPtr, const QSMember &mem ) const;

private:
};

class QUICKCORE_EXPORT QSPointerClass : public QSWrapperClass {
public:
    QSPointerClass( QSClass *b ) : QSWrapperClass( b ) { }
    QString name() const { return QString::fromLatin1("Pointer"); }

    double toNumber( const QSObject * ) const;
    bool toBoolean( const QSObject * ) const;
    QString debugString( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;
    QVariant toVariant( const QSObject *obj, QVariant::Type ) const;

    QSObject wrapPointer( const char *name, void *p );
    QSObject wrapPointer( QuickPtrDispatchObject *ptr );

    void *pointer( const QSObject *obj ) const;
    const char *pointerType( const QSObject *obj ) const;
};

class QSObjectConstructor;

class QSFactoryObjectProxy : public QSTypeClass, public QuickEnvClass
{
public:
    QSFactoryObjectProxy( QSClass *base, const QSObject &inst,
			  QSObjectConstructor *ctor )
	: QSTypeClass( base ),
	  QuickEnvClass( base->env() ),
	  sinst( inst ),
	  constr( ctor ) { }
    QString name() const { return QString::fromLatin1("FactoryObject"); }
    QSObject staticInstance() const { return sinst; }

    virtual bool member( const QSObject *o, const QString &n,
			 QSMember *m ) const;
    virtual QSMemberMap members( const QSObject *obj ) const;
    virtual QSObject fetchValue( const QSObject *o,
				 const QSMember &mem ) const;
    virtual void write( QSObject *objPtr, const QSMember &mem,
			const QSObject &val ) const;

    virtual ValueType valueType() const { return TypeClass; }

protected:
    virtual QSObject invoke( QSObject * objPtr, const QSMember &mem ) const;

    virtual void finalize();
private:
    QSObject sinst;
    QSObjectConstructor *constr;
};

class QSObjectConstructor : public QSClass, public QuickEnvClass
{
public:
    enum Type { Class, Form };
    QSObjectConstructor( QSClass *b, const QString &className, Type t=Class );
    QString name() const { return QString::fromLatin1("ObjectConstructor"); }
    QString identifier() const { return cname; }
    QSObject construct( const QSList &args ) const;
    QSObject cast( const QSList &args ) const;
    bool member( const QSObject *objPtr, const QString &name, QSMember *m ) const;
    QSObject fetchValue( const QSObject *o, const QSMember &mem ) const;

    QSFactoryObjectProxy *proxy() const { return m_proxy; }
    void setFactoryObjectProxy(QSFactoryObjectProxy *proxy) { m_proxy = proxy; }

private:
    QString cname;
    Type type;
    QSFactoryObjectProxy *m_proxy;
};

class QSVariantShared;

class QUICKCORE_EXPORT QSVariantClass : public QSSharedClass,
					public QuickEnvClass {
public:
    QSVariantClass( QSClass *b ) : QSSharedClass( b ), QuickEnvClass( b->env() ) { }
    QString name() const { return QString::fromLatin1("Variant"); }

    virtual bool member( const QSObject *objPtr, const QString &n,
			 QSMember *m ) const;
    virtual QSObject fetchValue( const QSObject *objPtr,
				 const QSMember &mem ) const;
    virtual void write( QSObject *objPtr, const QSMember &mem,
			const QSObject &val ) const;

    bool toBoolean( const QSObject * ) const;
    double toNumber( const QSObject * ) const;

    QString toString( const QSObject * ) const;
    QSObject toPrimitive( const QSObject *obj,
			  const QSClass *preferred ) const;
    QVariant toVariant( const QSObject *obj, QVariant::Type ) const;
    QString debugString( const QSObject *obj ) const;

    QSObject construct( const QVariant &v, const QMetaProperty *m ) const;
    QSObject construct( const QSList &args ) const;

    QVariant *variant( const QSObject * ) const;
    QSVariantShared *shared( const QSObject *obj ) const;

protected:
    virtual QSObject invoke( QSObject * objPtr, const QSMember &mem ) const;
};

class QUICKCORE_EXPORT QuickScriptVariant : public QSObject {
public:
    QuickScriptVariant( QuickInterpreter *ip,
			const QVariant &v, const QMetaProperty *m = 0 );

    QVariant value() const;

    const QMetaProperty *metaProperty() const;

    bool isNative() const;
    QSObject toNative() const;

private:
    QSVariantShared *shared() const;
};

class QSApplicationClass : public QSWritableClass, public QuickEnvClass
{
public:
    QSApplicationClass( QSClass *b );
    QString name() const { return QString::fromLatin1("Application"); }

    virtual bool member( const QSObject *o, const QString &n,
			 QSMember *m ) const;
    virtual QSObject fetchValue( const QSObject *objPtr,
				 const QSMember &mem ) const;

    static void exit( QSEnv * );
    static QSObject startTimer( QSEnv * );
    static QSObject killTimer( QSEnv * );
    static QSObject killTimers( QSEnv * );
};

#endif
