/****************************************************************************
** $Id: qsclass.h  beta1   edited Dec 17 19:00 $
**
** Copyright (C) 2001-2002 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 QSA Beta Evaluation Version license may use
** this file in accordance with the QSA Beta Evaluation Version 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 QSCLASS_H
#define QSCLASS_H

#include "qsvalues.h"
#include "qstypes.h"
#include "qsenv.h"
#include "qsmember.h"
#include "qsobjectlist.h"

class QSClassClass;
class QSInstanceData;
class QSFunctionBodyNode;
class QSNode;
class QSNodeList;

#if defined(Q_CC_MSVC_NET)  || defined(Q_CC_MSVC)
Q_TEMPLATE_EXTERN template class QUICKCORE_EXPORT QValueList<int>;
#endif

/*! Abstract base class for all objects.
 */
class QUICKCORE_EXPORT QSClass {
    friend class QSObject;
public:
    QSClass( QSEnv *e, int a = AttributeNone );
    QSClass( QSClass *b, int a = AttributeNone );
    virtual ~QSClass();
    virtual void clear();

    QSEnv *env() const { return en; }
    QSClass *base() const { return bclass; }
    virtual QString name() const = 0;
    virtual QString identifier() const { return name(); }
    QSClassClass *asClass() const;
    bool inherits( const QSClass *c ) const;

    QSClass * enclosingClass() const { return encClass; }
    void setEnclosingClass( QSClass * cl ) { encClass = cl; }

    bool isFinal() const { return attrs & AttributeFinal; }
    bool isExecutable() const { return attrs&AttributeExecutable; }

    virtual QSCompareResult compare( const QSObject &a, const QSObject &b ) const;

    virtual void ref( QSObject *o ) const;
    virtual void deref( QSObject *o ) const;
    virtual void mark( QSObject *o ) const;

    virtual bool toBoolean( const QSObject *obj ) const;
    virtual double toNumber( const QSObject *obj ) const;
    virtual QString toString( const QSObject *obj ) const;
    virtual QSObject toPrimitive( const QSObject *obj,
				  Type preferred = UndefinedType ) const;

    virtual QString debugString( const QSObject *obj ) const;

    bool hasProperty( const QSObject *obj, const QString &prop ) const;
    QSObject get( const QSObject *obj, const QString &prop ) const;
    void put( QSObject *obj, const QString &prop,
	      const QSObject &v, int attrs = None ) const;

    virtual bool deleteProperty( QSObject *obj, const QSMember &mem ) const;
    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;
    void write( QSObject * objPtr, int index, const QSObject &val ) const;
    virtual QSObject invoke( QSObject * objPtr, const QSMember &mem,
			     const QSList &args ) const;

    void addFunctionMember( const QString &n, QSFunctionBodyNode *f,
			    int attributes );
    int addVariableMember( const QString &n, int attributes );
    void addStaticVariableMember( const QString &n, const QSObject &v,
				  int attr );
    virtual void addMember( const QString &n, const QSMember &m,
			    const QSObject &stVal=QSUndefined() );
    virtual bool deleteMember( const QString &n );
    virtual void replaceMember( const QString &n, QSMember *m,
				const QSObject &stVal=QSUndefined() );
    void setNumberOfVariables( int count ) { numVariables = count; }
    int numberOfVariables() const { return numVariables; }
    int numberOfStaticVariables() const { return numStaticVars; }

    virtual QSObject construct( const QSList &args ) const;
    virtual QSObject execute( const QSObject *o, QSObject *thisValue, const QSList &args ) const;
    virtual QSObject cast( const QSList &args ) const;

    virtual QSMemberMap * definedMembers() const { return mmap; }
    virtual QSMemberMap members( const QSObject *obj ) const;

    void setStaticMember( int idx, const QSObject &val );
    QSObject staticMember( int idx ) const;

    int attributes() const { return attrs; }

    void throwError( ErrorType e, const QString &msg ) const;

protected:
    virtual int isEqual( const QSObject &a, const QSObject &b ) const;

private:
    void init();
    void removeStaticVar( const QSMember &old );
    void fillMemberVarIndex( QSMember * member );

private:
    QSEnv *en;
    QSClass *bclass;
    QSClass *encClass;
    int attrs;
    QSMemberMap *mmap;
    QSObjectList staticMembers;
    QValueList<int> replacedVars;
    int numVariables;
    int numStaticVars;
};

/*! Object class. Has no parents and is the base for Number etc.
 */

class QUICKCORE_EXPORT QSObjectClass : public QSClass {
public:
    QSObjectClass( QSEnv *e );
    QSObjectClass( QSClass *c ) : QSClass( c ) { }
    void init();
    QString name() const { return "Object"; }

    bool toBoolean( const QSObject * ) const { return TRUE; } // ####
    double toNumber( const QSObject * ) const { return NaN; } // ####
    QString toString( const QSObject *obj ) const;

    QSObject construct() const;
    QSObject construct( const QSList &args ) const;
    virtual QSObject cast( const QSList &args ) const;

    static QSObject toStringScript( QSObject *o, const QSList & );
    static QSObject valueOf( QSObject *o, const QSList & );
};

class QUICKCORE_EXPORT QSUndefinedClass : public QSClass {
public:
    QSUndefinedClass( QSClass *b ) : QSClass( b ) { }
    QString name() const { return "Undefined"; }

    bool toBoolean( const QSObject *obj ) const;
    double toNumber( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;
    QSObject toPrimitive( const QSObject *obj, Type preferred ) const;

protected:
    virtual int isEqual( const QSObject &a, const QSObject &b ) const;
};

class QUICKCORE_EXPORT QSNullClass : public QSClass {
public:
    QSNullClass( QSClass *b ) : QSClass( b ) { }
    QString name() const { return "Null"; }

    bool toBoolean( const QSObject *obj ) const;
    double toNumber( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;
    QSObject toPrimitive( const QSObject *obj, Type preferred ) const;

protected:
    virtual int isEqual( const QSObject &a, const QSObject &b ) const;
};

class QUICKCORE_EXPORT QSBooleanClass : public QSClass {
public:
    QSBooleanClass( QSClass *b );
    void init();
    QString name() const { return "Boolean"; }

    bool toBoolean( const QSObject *obj ) const;
    double toNumber( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;
    QSObject toPrimitive( const QSObject *obj, Type preferred ) const;

    QSObject construct( bool b ) const;
    QSObject construct( const QSList &args ) const;
    virtual QSObject cast( const QSList &args ) const;

protected:
    virtual int isEqual( const QSObject &a, const QSObject &b ) const;
};

class QUICKCORE_EXPORT QSNumberClass : public QSClass {
    friend class QSBooleanClass;
public:
    QSNumberClass( QSClass *b );
    void init();
    QString name() const { return "Number"; }

    bool toBoolean( const QSObject *obj ) const;
    double toNumber( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;
    QSObject toPrimitive( const QSObject *obj, Type preferred ) const;

    QSObject construct( const QSList &args ) const;
    virtual QSObject cast( const QSList &args ) const;

    static QSObject toStringScript( QSObject *o, const QSList & );
    static QSObject valueOf( QSObject *o, const QSList & );

protected:
    virtual int isEqual( const QSObject &a, const QSObject &b ) const;
};

class QUICKCORE_EXPORT QSStringClass : public QSClass {
public:
    QSStringClass( QSClass *b );
    void init();
    QString name() const { return "String"; }
    virtual void ref( QSObject *o ) const;
    virtual void deref( QSObject *o ) const;

    virtual QSObject fetchValue( const QSObject *objPtr,
				 const QSMember &mem ) const;

    bool toBoolean( const QSObject *obj ) const;
    double toNumber( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;
    QSObject toPrimitive( const QSObject *obj, Type preferred ) const;

    QSObject construct( const QSList &args ) const;
    virtual QSObject cast( const QSList &args ) const;

    static QSObject fromCharCode( const QSList & );

    static QSObject toStringScript( QSObject *o, const QSList & );
    static QSObject charAt( QSObject *o, const QSList & );
    static QSObject charCodeAt( QSObject *o, const QSList & );
    static QSObject indexOf( QSObject *o, const QSList & );
    static QSObject lastIndexOf( QSObject *o, const QSList & );
    static QSObject match( QSObject *o, const QSList & );
    static QSObject search( QSObject *o, const QSList & );
    static QSObject replace( QSObject *o, const QSList & );
    static QSObject split( QSObject *o, const QSList & );
    static QSObject substr( QSObject *o, const QSList & );
    static QSObject substring( QSObject *o, const QSList & );
    static QSObject toLowerCase( QSObject *o, const QSList & );
    static QSObject toUpperCase( QSObject *o, const QSList & );
    // QString API
    static QSObject isEmpty( QSObject *o, const QSList & );
    static QSObject left( QSObject *o, const QSList & );
    static QSObject mid( QSObject *o, const QSList & );
    static QSObject right( QSObject *o, const QSList & );
    static QSObject find( QSObject *o, const QSList & );
    static QSObject findRev( QSObject *o, const QSList & );
    static QSObject startsWith( QSObject *o, const QSList & );
    static QSObject endsWith( QSObject *o, const QSList & );

protected:
    virtual int isEqual( const QSObject &a, const QSObject &b ) const;
};

class QUICKCORE_EXPORT QSCharacterClass : public QSClass {
public:
    QSCharacterClass( QSClass *b ) : QSClass( b ) { }
    QString name() const { return "Character"; }

    bool toBoolean( const QSObject *obj ) const;
    double toNumber( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;
};

class QSSharedClass : public QSClass {
public:
    QSSharedClass( QSClass *b, int attr = AttributeNone )
	: QSClass( b, attr ) { }

    virtual void ref( QSObject *o ) const;
    virtual void deref( QSObject *o ) const;
};

class QSClassClass : public QSSharedClass {
public:
    QSClassClass( QSClass *b, int a, const QString &n );
    ~QSClassClass();
    QString name() const { return "Class"; }
    QString identifier() const { return cname; }

    bool toBoolean( const QSObject *obj ) const;
    double toNumber( const QSObject *obj ) const;
    QString toString( const QSObject * ) const;

    QSObject construct( const QSList &args ) const;

    virtual int isEqual( const QSObject &a, const QSObject &b ) const;

    static QSInstanceData* data( QSObject *obj );
    static const QSInstanceData* data( const QSObject *obj );

    bool hasDefaultConstructor() const { return defaultCtor; }
    void setHasDefaultConstructor( bool d ) { defaultCtor = d; }

    void addMemberInitializer( QSNode * node );
    void addStaticInitializer( QSNode * node );
    void setClassBodyNode( QSFunctionBodyNode *node );

    void executeBlock( QSEnv *env );

private:
    int initVariables( QSInstanceData *data ) const;

private:
    QString cname;
    uint defaultCtor:1;
    QSNodeList *memberInit;
    QSNodeList *staticInit;
    QSFunctionBodyNode * bodyNode;
};

class QUICKCORE_EXPORT QSWritableClass : public QSSharedClass {
public:
    QSWritableClass( QSClass *b ) : QSSharedClass( b ) { }
    void mark( QSObject *o ) const;
    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 bool deleteProperty( QSObject *obj, const QSMember &mem ) const;

    virtual QSObject invoke( QSObject * objPtr, const QSMember &mem,
			     const QSList &args ) const;
    virtual QSMemberMap members( const QSObject *obj ) const;

    virtual int isEqual( const QSObject &a, const QSObject &b ) const;

    QSObject createWritable() const;

    QSPropertyMap *properties( const QSObject *obj ) const;
protected:
    static QSWritable *data( QSObject *obj );
    static const QSWritable *data( const QSObject *obj );
};

class QSFuncDeclNode;

class QUICKCORE_EXPORT QSFunctionScopeClass : public QSWritableClass
{
public:
    QSFunctionScopeClass( QSClass *b, QSFuncDeclNode * func );

    QSFunctionScopeClass( QSClass *b )
	: QSWritableClass( b ), numArgs( 0 ) { }

    virtual QString name() const { return QString( "FunctionScope" ); }
    virtual QString identifier() const;
    virtual QSObject construct( const QSList & ) const;
    void setNumberOfArguments( int num ) { numArgs = num; }
    int numberOfArguments() const { return numArgs; }

private:
    QString ident;
    int numArgs;
};

class QUICKCORE_EXPORT QSEvalScopeClass: public QSWritableClass
{
public:
    QSEvalScopeClass( QSClass *b ) : QSWritableClass( b ) { }
    virtual QString name() const { return QString( "EvalScope" ); }
    virtual QSObject construct( const QSList & ) const;
};

class QUICKCORE_EXPORT QSBlockScopeClass: public QSClass
{
public:
    QSBlockScopeClass( QSEnv *e ) : QSClass( e ) { }
    void activateScope() const;
    void deactivateScope() const;
    virtual QString name() const { return QString( "BlockScope" ); }
    virtual QSMemberMap members( const QSObject *obj ) const;


};

// doesn't add much value. just a concrete class for anonymous
// objects.
class QUICKCORE_EXPORT QSDynamicClass : public QSWritableClass {
public:
    QSDynamicClass( QSClass *b ) : QSWritableClass( b ) { }
    QString name() const { return "Object"; }
};

class QUICKCORE_EXPORT QSTypeClass : public QSClass {
public:
    QSTypeClass( QSClass *b ) : QSClass( b, AttributeExecutable ) { }
    QString name() const { return "Type"; }

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

    virtual int isEqual( const QSObject &a, const QSObject &b ) const;


};

class QSGlobalClass : public QSWritableClass {
public:
    QSGlobalClass( QSClass *b );
    QString name() const { return "Global"; } // invisible to the user
};

class QSInstanceData : public QSWritable {
public:
    QSInstanceData( int count );
    ~QSInstanceData()
    {
	delete [] vals;
    }

    int size() const { return sz; }
    void resize( int count );
    void ensureSize( int count );

    QSObject * value( int index ) const
    {
	Q_ASSERT( index>=0 && index<sz );
	return &vals[index];
    }

    void setValue( int index, const QSObject &value )
    {
	Q_ASSERT( index>=0 && index<sz );
	vals[index] = value;
    }

private:
    // disabled
    QSInstanceData( const QSInstanceData & );
    QSInstanceData& operator=( const QSInstanceData & );

    int sz;
    QSObject *vals;
};

#endif
