/****************************************************************************
** $Id: qsinterfacefactory.cpp  beta1   edited Dec 12 12:04 $
**
** 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.
**
*****************************************************************************/

#include "qsinterfacefactory_p.h"
#include "qsa.h"
#include <quickinterpreter.h>
#include <qsobject.h>
#include <qsenv.h>
#include <quickobjects.h>

QSInterfaceFactory *QSInterfaceFactory::factory = 0;

QSInterfaceFactory::QSInterfaceFactory()
    : dirty( FALSE )
{
    QuickInterpreter::self()->addDispatchObjectFactory( this );
}

QStringList QSInterfaceFactory::featureList() const
{
    ( (QSInterfaceFactory*)this )->createClassList();
    return classes;
}

bool QSInterfaceFactory::createInterface( const QCString &className, void *ptr,
					  QPtrVector<QObject> &result )
{
    QMap<QString, QSWrapperFactory* >::ConstIterator it = wrapperFactoryCache.find( className );
    QSWrapperFactory *f = 0;
    if ( it != wrapperFactoryCache.end() ) {
	f = *it;
    } else {
	for ( QSWrapperFactory *w = wrappers.first(); w; w = wrappers.next() ) {
	    QStringList wrps = w->classes();
	    if ( wrps.find( className ) != wrps.end() ) {
		f = w;
		wrapperFactoryCache.replace( className, f );
		break;
	    }
	}
    }

    if ( f ) {
	QObject *o = f->create( className, ptr );
	if ( o ) {
	    int idx = result.size();
	    result.resize( idx + 1 );
	    result.insert( idx, o );
	    return TRUE;
	}
    }

    return FALSE;
}

bool QSInterfaceFactory::isGlobal( const QCString & ) const
{
    return FALSE;
}

bool QSInterfaceFactory::isConstructor( const QString &className ) const
{
    QStringList lst;
    for ( QSObjectFactory *c = ( (QSInterfaceFactory*)this)->ctors.first(); c;
	  c = ( (QSInterfaceFactory*)this)->ctors.next() )
	lst += c->classes();

    return lst.find( className ) != lst.end();
}

bool QSInterfaceFactory::construct( const QString & className,
					 const QValueList<QVariant> &args,
					 QPtrVector<QObject> &result ) const
{
    QValueList<QSArgument> qsArgs;
    for ( QValueList<QVariant>::ConstIterator it = args.begin(); it != args.end(); ++it ) {
	if ( (*it).type() == QVariant::String ) {
		static int length_of_Pointer = 7;
		static QString pointer_header = "Pointer";
		QString s = (*it).toString();
		if ( s.left( length_of_Pointer ) == pointer_header ) {
		    QStringList l = QStringList::split( ':', s );
		    if ( l.count() == 3 ) {
			if ( l[2] != "QObject" ) {
			    ulong lng = l[1].toULong();
			    void *ptr = (void*)lng;
			    qsArgs.append( QSArgument( ptr ) );
			} else {
			    ulong lng = l[1].toULong();
			    QObject *o = (QObject*)lng;
			    qsArgs.append( QSArgument( o ) );
			}
			continue;
		    }
		}
	}
	qsArgs.append( QSArgument( *it ) );
    }

    QMap<QString, QSObjectFactory* >::ConstIterator mit = objectFactoryCache.find( className );
    QSObjectFactory *f = 0;
    if ( mit != objectFactoryCache.end() ) {
	f = *mit;
    } else {
	for ( QSObjectFactory *c = ( (QSInterfaceFactory*)this )->ctors.first(); c;
	      c = ( (QSInterfaceFactory*)this )->ctors.next() ) {
	    QStringList cls = c->classes();
	    if ( cls.find( className ) != cls.end() ) {
		f = c;
		( (QSInterfaceFactory*)this )->objectFactoryCache.replace( className, f );
		break;
	    }
	}
    }

    if ( f ) {
	QObject *ctx = 0;
	QSObject obj = QuickInterpreter::self()->env()->currentScope();
	if ( obj.isA( QuickInterpreter::self()->wrapperClass() ) )
	    ctx = QuickInterpreter::self()->wrapperClass()->shared( &obj )->objects[0];
	QObject *o = f->create( className, qsArgs, ctx );
	if ( o ) {
	    int idx = result.size();
	    result.resize( idx + 1 );
	    result.insert( idx, o );
	    return TRUE;
	}
    }

    return FALSE;
}

void QSInterfaceFactory::createClassList()
{
    if ( !dirty )
	return;
    classes.clear();
    for ( QSObjectFactory *c = ctors.first(); c; c = ctors.next() )
	classes += c->classes();
    for ( QSWrapperFactory *w = wrappers.first(); w; w = wrappers.next() )
	classes += w->classes();
}

void QSInterfaceFactory::addConstructor( QSObjectFactory *ctor )
{
    ctors.append( ctor );
    dirty = TRUE;
    objectFactoryCache.clear();
    QtApplicationScript::self()->needRerun = TRUE;
}

void QSInterfaceFactory::addWrapper( QSWrapperFactory *w )
{
    wrappers.append( w );
    dirty = TRUE;
    wrapperFactoryCache.clear();
    QtApplicationScript::self()->needRerun = TRUE;
}
