/***************************************************************************
*   Copyright (C) 2003 by Roberto Raggi                                   *
*   roberto@kdevelop.org                                                  *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/

#include "store_walker.h"
#include "ast_utils.h"
#include "urlutil.h"
#include "driver.h"

#include <kdebug.h>
#include <tqfileinfo.h>
#include <tqdir.h>

StoreWalker::StoreWalker( const TQString& fileName, CodeModel* store )
: m_store( store ), m_anon( 0 )
{
	m_fileName = URLUtil::canonicalPath( fileName );
    m_hashedFileName = HashedString( m_fileName );
	
	//kdDebug(9007) << "StoreWalker::StoreWalker(" << m_fileName << ")" << endl;
}

StoreWalker::~StoreWalker()
{}


void StoreWalker::parseTranslationUnit( const ParsedFile& ast )
{
	m_file = m_store->create<FileModel>();
	m_file->setName( m_fileName ); /// @todo ?!?

	m_currentScope.clear();
	m_currentNamespace.clear();
	m_currentClass.clear();

	ParsedFilePointer p = new ParsedFile( ast );
	p->setTranslationUnit( 0 ); //Necessary so the memory is not bloated after the first parse
	m_file->setParseResult( p.data() ); ///@todo beautify
	
	m_currentAccess = CodeModelItem::Public;
	m_inSlots = false;
	m_inSignals = false;
	m_inStorageSpec = false;
	m_inTypedef = false;
	m_currentDeclarator = 0;
	m_anon = 0;
	m_imports.clear();
	
	m_imports << TQPair<TQMap<TQString, ClassDom>, TQStringList>(TQMap<TQString, ClassDom>(), TQStringList());
	TreeParser::parseTranslationUnit( ast );
	m_imports.pop_back();
}

void StoreWalker::parseDeclaration( DeclarationAST* ast )
{
	TreeParser::parseDeclaration( ast );
}

void StoreWalker::parseLinkageSpecification( LinkageSpecificationAST* ast )
{
	int inStorageSpec = m_inStorageSpec;
	m_inStorageSpec = true;
	TreeParser::parseLinkageSpecification( ast );
	m_inStorageSpec = inStorageSpec;
}

void StoreWalker::parseNamespace( NamespaceAST* ast )
{
	if ( !m_currentClass.isEmpty() )
	{
		kdDebug( 9007 ) << "!!!!!!!!!!!!!!!!!!!!!!!!!! **error** !!!!!!!!!!!!!!!!!!!!" << endl;
		return ;
	}
	
	int startLine, startColumn;
	int endLine, endColumn;
	ast->getStartPosition( &startLine, &startColumn );
	ast->getEndPosition( &endLine, &endColumn );

	TQString nsName;
	if ( !ast->namespaceName() || ast->namespaceName()->text().isEmpty() )
	{
		TQFileInfo fileInfo( m_fileName );
		TQString shortFileName = fileInfo.baseName();
		
		nsName.sprintf( "(%s_%d)", shortFileName.local8Bit().data(), m_anon++ );
	}
	else
	{
		nsName = ast->namespaceName() ->text();
	}
	
	NamespaceDom ns = findOrInsertNamespace( ast, nsName );

	m_currentScope.push_back( nsName );
	m_currentNamespace.push( ns );
	
	TreeParser::parseNamespace( ast );
	
	m_currentNamespace.pop();
	m_currentScope.pop_back();
}

void StoreWalker::parseNamespaceAlias( NamespaceAliasAST* ast )
{
  TQString nsName; 
  TQString aliasName;
  
  if( !ast->namespaceName() || ast->namespaceName()->text().isEmpty() )
  {
        // anonymous namespace
  }
  else
    nsName = ast->namespaceName()->text();
  
  if( ast->aliasName() )
    aliasName = ast->aliasName()->text();

  
  if( !nsName.isNull() ) {
    NamespaceAliasModel m;
    m.setName( nsName );
    m.setAliasName( aliasName );
    m.setFileName( m_hashedFileName );
    if( m_currentNamespace.empty() )
      m_file->addNamespaceAlias( m );
    else
      m_currentNamespace.top() ->addNamespaceAlias( m );
  }
  
  TreeParser::parseNamespaceAlias( ast );
}

void StoreWalker::parseUsing( UsingAST* ast )
{
  TreeParser::parseUsing( ast );
}

void StoreWalker::parseUsingDirective( UsingDirectiveAST* ast )
{
  TQString name;
  if( ast->name() )
    name = ast->name()->text();
  
  if( !name.isNull() ) {
    NamespaceImportModel m;
    m.setName( name );
    m.setFileName( m_hashedFileName );
    if( m_currentNamespace.empty() )
      m_file->addNamespaceImport( m );
    else
      m_currentNamespace.top() ->addNamespaceImport( m );
  }
  
  m_imports.back().second.push_back( name );
}

void StoreWalker::parseTypedef( TypedefAST* ast )
{
#if 0
	DeclaratorAST * oldDeclarator = m_currentDeclarator;
	
	if ( ast && ast->initDeclaratorList() && ast->initDeclaratorList() ->initDeclaratorList().count() > 0 )
	{
		TQPtrList<InitDeclaratorAST> lst( ast->initDeclaratorList() ->initDeclaratorList() );
		m_currentDeclarator = lst.at( 0 ) ->declarator();
	}
	
	m_inTypedef = true;
	
	TreeParser::parseTypedef( ast );
	
	m_inTypedef = false;
	m_currentDeclarator = oldDeclarator;
#else
	
	TypeSpecifierAST* typeSpec = ast->typeSpec();
	InitDeclaratorListAST* declarators = ast->initDeclaratorList();
	
	if ( typeSpec && declarators )
	{
		TQString typeId;
		
		if ( typeSpec->name() )
			typeId = typeSpec->name() ->text();
		
		TQPtrList<InitDeclaratorAST> l( declarators->initDeclaratorList() );
		TQPtrListIterator<InitDeclaratorAST> it( l );
		
		InitDeclaratorAST* initDecl = 0;
		while ( 0 != ( initDecl = it.current() ) )
		{
			
			TQString type, id;
			if ( initDecl->declarator() )
			{
				type = typeOfDeclaration( typeSpec, initDecl->declarator() );
				
				DeclaratorAST* d = initDecl->declarator();
				while ( d->subDeclarator() )
				{
					d = d->subDeclarator();
				}
				
				if ( d->declaratorId() )
					id = d->declaratorId() ->text();
			}
			
			TypeAliasDom typeAlias = m_store->create<TypeAliasModel>();
			typeAlias->setFileName( m_fileName );
			typeAlias->setName( id );
			typeAlias->setType( type );
			typeAlias->setComment( ast->comment() );
			
			int line, col;
			initDecl->getStartPosition( &line, &col );
			typeAlias->setStartPosition( line, col );
			
			initDecl->getEndPosition( &line, &col );
			typeAlias->setEndPosition( line, col );
			
			if ( m_currentClass.top() )
				m_currentClass.top() ->addTypeAlias( typeAlias );
			else if ( m_currentNamespace.top() )
				m_currentNamespace.top() ->addTypeAlias( typeAlias );
			else
				m_file->addTypeAlias( typeAlias );
			
#if 0
			
			Tag tag;
			tag.setKind( Tag::Kind_Typedef );
			tag.setFileName( m_fileName );
			tag.setName( id );
			tag.setScope( m_currentScope );
			tag.setAttribute( "t", type );
			int line, col;
			initDecl->getStartPosition( &line, &col );
			
			tag.setStartPosition( line, col );
			
			initDecl->getEndPosition( &line, &col );
			tag.setEndPosition( line, col );
			
			m_catalog->addItem( tag );
#endif
			
			++it;
		}
		
	}
#endif
}

void StoreWalker::parseTemplateDeclaration( TemplateDeclarationAST* ast )
{
	m_currentTemplateDeclarator.push( ast );
	if ( ast->declaration() )
		parseDeclaration( ast->declaration() );
	
	
	
	TreeParser::parseTemplateDeclaration( ast );
	
	m_currentTemplateDeclarator.pop();
}

void StoreWalker::parseSimpleDeclaration( SimpleDeclarationAST* ast )
{
	TypeSpecifierAST * typeSpec = ast->typeSpec();
	InitDeclaratorListAST* declarators = ast->initDeclaratorList();
	CommentPusher push( *this, ast->comment() );
	
	if ( typeSpec )
		parseTypeSpecifier( typeSpec );
	
	if ( declarators )
	{
		TQPtrList<InitDeclaratorAST> l = declarators->initDeclaratorList();
		
		TQPtrListIterator<InitDeclaratorAST> it( l );
		while ( it.current() )
		{
			parseDeclaration( ast->functionSpecifier(), ast->storageSpecifier(),
			                  typeSpec, it.current() );
			++it;
		}
	}
}


TQStringList StoreWalker::findScope( const TQStringList& scope ) {
	ClassDom d = findClassFromScope( scope );
	
	if( d ) {
		TQStringList ret = d->scope();
		ret << d->name();
		return ret;
	}
	
	return scope;
}


void StoreWalker::parseFunctionDefinition( FunctionDefinitionAST* ast )
{
	TypeSpecifierAST * typeSpec = ast->typeSpec();
	GroupAST* funSpec = ast->functionSpecifier();
	GroupAST* storageSpec = ast->storageSpecifier();
	
	if ( !ast->initDeclarator() )
		return ;
	
	DeclaratorAST* d = ast->initDeclarator() ->declarator();
	
	if ( !d->declaratorId() )
		return ;
	
	bool isFriend = false;
	bool isVirtual = false;
	bool isStatic = false;
	bool isInline = false;
	
	if ( funSpec )
	{
		TQPtrList<AST> l = funSpec->nodeList();
		TQPtrListIterator<AST> it( l );
		while ( it.current() )
		{
			TQString text = it.current() ->text();
			if ( text == "virtual" )
				isVirtual = true;
			else if ( text == "inline" )
				isInline = true;
			++it;
		}
	}
	
	if ( storageSpec )
	{
		TQPtrList<AST> l = storageSpec->nodeList();
		TQPtrListIterator<AST> it( l );
		while ( it.current() )
		{
			TQString text = it.current() ->text();
			if ( text == "friend" )
				isFriend = true;
			else if ( text == "static" )
				isStatic = true;
			++it;
		}
	}
	
	int startLine, startColumn;
	int endLine, endColumn;
	ast->getStartPosition( &startLine, &startColumn );
	ast->getEndPosition( &endLine, &endColumn );
	
	TQString id = d->declaratorId() ->unqualifiedName() ->text().stripWhiteSpace();
	
	TQStringList scope = scopeOfDeclarator( d, m_currentScope );
	ClassDom c; ///c should be nonzero if it is a function-definition for a function within another class
	if( !m_currentClass.top() ) {
		///It is not a local definition within a class, so search the scope so it can be corrected using imports
		c = findClassFromScope( scope );
	}
	
	if( c ) {
		scope = c->scope();
		scope << c->name();
	}
	
	FunctionDefinitionDom method = m_store->create<FunctionDefinitionModel>();
	method->setScope( scope );
	method->setName( id );
	
	parseFunctionArguments( d, model_cast<FunctionDom>( method ) );
	
	TQString text = typeOfDeclaration( typeSpec, d );
	if ( !text.isEmpty() )
		method->setResultType( text );
	
	method->setFileName( m_fileName );
	method->setStartPosition( startLine, startColumn );
	method->setEndPosition( endLine, endColumn );
	if( !ast->comment().isEmpty() )
		method->setComment( ast->comment() );
	
	checkTemplateDeclarator( & (*method) );
	
	if ( m_inSignals )
		method->setSignal( true );
	
	if ( m_inSlots )
		method->setSlot( true );
	
	if( c && c->isClass() )
		method->setConstant( d->constant() != 0 );
	else if ( m_currentClass.top() || ( method->name() == "main" && scope.isEmpty() ) )
	{
		method->setConstant( d->constant() != 0 );
		method->setAccess( m_currentAccess );
		method->setStatic( isStatic );
		method->setVirtual( isVirtual );
		
		if ( m_currentClass.top() )
			m_currentClass.top() ->addFunction( model_cast<FunctionDom>( method ) ); 
		else
			m_file->addFunction( model_cast<FunctionDom>( method ) );
	}
	
	if ( m_currentClass.top() )
		m_currentClass.top() ->addFunctionDefinition( method );
	else if ( m_currentNamespace.top() )
		m_currentNamespace.top() ->addFunctionDefinition( method );
	else
		m_file->addFunctionDefinition( method );
}

void StoreWalker::parseLinkageBody( LinkageBodyAST* ast )
{
	TreeParser::parseLinkageBody( ast );
}

void StoreWalker::parseTypeSpecifier( TypeSpecifierAST* ast )
{
	TreeParser::parseTypeSpecifier( ast );
}

void StoreWalker::takeTemplateParams( TemplateModelItem& target, TemplateDeclarationAST* ast) {
	TemplateParameterListAST* pl = ast->templateParameterList();
	if( pl ) {
		TQPtrList<TemplateParameterAST> list = pl->templateParameterList();
		
		TemplateParameterAST* curr = list.first();
		while( curr != 0 ) {
			TQString a, b;
			if( curr->typeParameter() && curr->typeParameter()->name() ) {
				a = curr->typeParameter()->name()->text();
				if( curr->typeParameter()->typeId() ) 
					b =  curr->typeParameter()->typeId()->text();
			}
			
			target.addTemplateParam( a, b );
			CodeModelItem* cmi = dynamic_cast<CodeModelItem*>(&target);
			TQString nm = "0";
			if(cmi) nm = cmi->name();
		kdDebug() << "item " << nm << " taking template-parameters " << a << ", default=" << b << "\n";
			curr = list.next();
		}
	}
}

void StoreWalker::checkTemplateDeclarator( TemplateModelItem* item ) {
	if( !m_currentTemplateDeclarator.empty() && m_currentTemplateDeclarator.top() != 0) {
		TemplateDeclarationAST* a = m_currentTemplateDeclarator.top();
		
		m_currentTemplateDeclarator.pop();
		m_currentTemplateDeclarator.push(0);
		
		takeTemplateParams( *item, a );
	}
}

int StoreWalker::mergeGroups( int g1, int g2 ) {
	int ng = m_store->mergeGroups( g1, g2 );
	for( TQMap<TQString, FileDom>::iterator it = m_overrides.begin(); it != m_overrides.end(); ++it ) {
		int g =(*it)->groupId();
		if( g == g1 || g == g2 )
			(*it)->setGroupId( ng );
	}
	return ng;
}

void StoreWalker::parseClassSpecifier( ClassSpecifierAST* ast )
{
	int startLine, startColumn;
	int endLine, endColumn;
	ast->getStartPosition( &startLine, &startColumn );
	ast->getEndPosition( &endLine, &endColumn );
	
	int oldAccess = m_currentAccess;
	bool oldInSlots = m_inSlots;
	bool oldInSignals = m_inSignals;
	
	TQString kind = ast->classKey() ->text();
	if ( kind == "class" )
		m_currentAccess = CodeModelItem::Private;
	else
		m_currentAccess = CodeModelItem::Public;
	m_inSlots = false;
	m_inSignals = false;
	
	TQString className;
	if ( !ast->name() && m_currentDeclarator && m_currentDeclarator->declaratorId() )
	{
		className = m_currentDeclarator->declaratorId() ->text().stripWhiteSpace();
	}
	else if ( !ast->name() )
	{
		TQFileInfo fileInfo( m_fileName );
		TQString shortFileName = fileInfo.baseName();
		className.sprintf( "(%s_%d)", shortFileName.local8Bit().data(), m_anon++ );
	}
	else
	{
		className = ast->name() ->unqualifiedName() ->text().stripWhiteSpace();
	}
	
	ClassDom klass = m_store->create<ClassModel>();
	klass->setStartPosition( startLine, startColumn );
	klass->setEndPosition( endLine, endColumn );
	klass->setFileName( m_fileName );
	
	int i = className.find( '<' );
	if( i != -1 ) {
		klass->setSpecializationDeclaration( className.mid( i ) );
		className = className.left( i );
	}
	
	klass->setName( className );
	klass->setComment( ast->comment() );
	
	checkTemplateDeclarator( &(*klass) );
	
	bool embed = !scopeOfName( ast->name(), TQStringList() ).isEmpty();
	
	TQStringList oldScope;
	
	
	if( embed ) {
		ClassDom embedderClass = findClassFromScope( m_currentScope + scopeOfName( ast->name(), TQStringList() ));
		
		if(embedderClass) {
			if(embedderClass->fileName() != klass->fileName()) {
				///since we are creating a link between both files, put them into the same parsing-group
				FileDom dm = embedderClass->file();
				if( dm ) {
					m_file->setGroupId( mergeGroups( dm->groupId(), m_file->groupId() ) );
				}else{
					kdDebug() << "file " << embedderClass->fileName() << " missing in store \n";
				}
			}
				
			oldScope = m_currentScope;
			m_currentScope = embedderClass->scope();
			m_currentScope.push_back( embedderClass->name() );
			m_currentClass.push( embedderClass );
			
			//m_file->addClass( klass );//experiment
		}else{
			kdDebug( 9007 ) << "could not find embedding class " << TQStringList(m_currentScope + scopeOfName( ast->name(), TQStringList() )).join("::") << " for " << className << endl;
			embed = false;
		}
	}
	
	if ( m_currentClass.top() )
		m_currentClass.top() ->addClass( klass );
	else if ( m_currentNamespace.top() )
		m_currentNamespace.top() ->addClass( klass );
	else
		m_file->addClass( klass );
	
	klass->setScope( m_currentScope );
	
	
	if ( ast->baseClause() )
		parseBaseClause( ast->baseClause(), klass );
	
	m_currentScope.push_back( className );
	m_currentClass.push( klass );
	
	//m_imports.push_back( TQStringList() );
	
	TreeParser::parseClassSpecifier( ast );
	

	//m_imports.pop_back();
	m_currentClass.pop();
	
	m_currentScope.pop_back();
	
	if( embed ) {
		m_currentScope = oldScope;
		m_currentClass.pop();
	}
	
	m_currentAccess = oldAccess;
	m_inSlots = oldInSlots;
	m_inSignals = oldInSignals;
}

void StoreWalker::parseEnumSpecifier( EnumSpecifierAST* ast )
{
	if( ast->name() ) {
	TypeAliasDom typeAlias = m_store->create<TypeAliasModel>();
	typeAlias->setFileName( m_fileName );
	typeAlias->setName( ast->name()->text() );
	typeAlias->setType( "const int" );
	typeAlias->setComment( ast->comment() );
	
	int line, col;
	ast->getStartPosition( &line, &col );
	typeAlias->setStartPosition( line, col );
	
	ast->getEndPosition( &line, &col );
	typeAlias->setEndPosition( line, col );
	
	if ( m_currentClass.top() )
		m_currentClass.top() ->addTypeAlias( typeAlias );
	else if ( m_currentNamespace.top() )
		m_currentNamespace.top() ->addTypeAlias( typeAlias );
	else
		m_file->addTypeAlias( typeAlias );
	}

	TQPtrList<EnumeratorAST> l = ast->enumeratorList();
	TQPtrListIterator<EnumeratorAST> it( l );
	while ( it.current() )
	{
		VariableDom attr = m_store->create<VariableModel>();
		attr->setName( it.current() ->id() ->text() );
		attr->setFileName( m_fileName );
		attr->setAccess( m_currentAccess );
		
		if( !ast->name() ) {
			attr->setType( "const int" );
		} else {
			attr->setType( ast->name()->text() );
		}

		attr->setEnumeratorVariable( true );

		attr->setComment( (*it)->comment() );
		attr->setStatic( true );
		
		int startLine, startColumn;
		int endLine, endColumn;
		it.current() ->getStartPosition( &startLine, &startColumn );
		attr->setStartPosition( startLine, startColumn );
		
		it.current() ->getEndPosition( &endLine, &endColumn );
		attr->setEndPosition( endLine, endColumn );
		
		if ( m_currentClass.top() )
			m_currentClass.top() ->addVariable( attr );
		else if ( m_currentNamespace.top() )
			m_currentNamespace.top() ->addVariable( attr );
		else
			m_file->addVariable( attr );
		
		++it;
	}
}

void StoreWalker::parseElaboratedTypeSpecifier( ElaboratedTypeSpecifierAST* ast )
{
	TreeParser::parseElaboratedTypeSpecifier( ast );
}

void StoreWalker::parseTypeDeclaratation( TypeSpecifierAST* typeSpec )
{
	parseTypeSpecifier( typeSpec );
}

void StoreWalker::parseDeclaration( GroupAST* funSpec, GroupAST* storageSpec, 
                                    TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl )
{
	if ( m_inStorageSpec )
		return ;
	
	DeclaratorAST* d = decl->declarator();
	
	if ( !d )
		return ;
	
	if ( !d->subDeclarator() && d->parameterDeclarationClause() )
		return parseFunctionDeclaration( funSpec, storageSpec, typeSpec, decl );
	
	DeclaratorAST* t = d;
	while ( t && t->subDeclarator() )
		t = t->subDeclarator();
	
	TQString id;
	if ( t && t->declaratorId() && t->declaratorId() ->unqualifiedName() )
		id = t->declaratorId() ->unqualifiedName() ->text();
	
	if ( !scopeOfDeclarator( d, TQStringList() ).isEmpty() )
	{
		kdDebug( 9007 ) << "skip declaration of " << TQStringList(scopeOfDeclarator( d, TQStringList() )).join("::") << "::" << id << endl;
		return ;
	}

	VariableDom attr = m_store->create<VariableModel>();
	attr->setName( id );
	attr->setFileName( m_fileName );
	attr->setComment( comment() );
		
	if ( m_currentClass.top() )
		m_currentClass.top() ->addVariable( attr );
	else if ( m_currentNamespace.top() )
		m_currentNamespace.top() ->addVariable( attr );
	else
		m_file->addVariable( attr );
	
	attr->setAccess( m_currentAccess );
	
	TQString text = typeOfDeclaration( typeSpec, d );
  if ( !text.isEmpty() ) {
        attr->setType( text );
  }
	
	bool isFriend = false;
	//bool isVirtual = false;
	bool isStatic = false;
	//bool isInline = false;
	//bool isInitialized = decl->initializer() != 0;
	
	if ( storageSpec )
	{
		TQPtrList<AST> l = storageSpec->nodeList();
		TQPtrListIterator<AST> it( l );
		while ( it.current() )
		{
			TQString text = it.current() ->text();
			if ( text == "friend" )
				isFriend = true;
			else if ( text == "static" )
				isStatic = true;
			++it;
		}
	}
	
	int startLine, startColumn;
	int endLine, endColumn;
	decl->getStartPosition( &startLine, &startColumn );
	decl->getEndPosition( &endLine, &endColumn );
	
	attr->setStartPosition( startLine, startColumn );
	attr->setEndPosition( endLine, endColumn );
	attr->setStatic( isStatic );
}

void StoreWalker::parseAccessDeclaration( AccessDeclarationAST * access )
{
	TQPtrList<AST> l = access->accessList();
	
	TQString accessStr = l.at( 0 ) ->text();
	if ( accessStr == "public" )
		m_currentAccess = CodeModelItem::Public;
	else if ( accessStr == "protected" )
		m_currentAccess = CodeModelItem::Protected;
	else if ( accessStr == "private" )
		m_currentAccess = CodeModelItem::Private;
	else if ( accessStr == "signals" )
		m_currentAccess = CodeModelItem::Protected;
	else
		m_currentAccess = CodeModelItem::Public;
	
	m_inSlots = l.count() > 1 ? l.at( 1 ) ->text() == "slots" : false;
	m_inSignals = l.count() >= 1 ? l.at( 0 ) ->text() == "signals" : false;
}

NamespaceDom StoreWalker::findOrInsertNamespace( NamespaceAST* ast, const TQString & name )
{
	if ( m_currentNamespace.top() && m_currentNamespace.top() ->hasNamespace( name ) )
		return m_currentNamespace.top() ->namespaceByName( name );
	
	if ( m_file->hasNamespace( name ) )
		return m_file->namespaceByName( name );
	
	int startLine, startColumn;
	int endLine, endColumn;
	ast->getStartPosition( &startLine, &startColumn );
	ast->getEndPosition( &endLine, &endColumn );
	
	NamespaceDom ns = m_store->create<NamespaceModel>();
	ns->setFileName( m_fileName );
	ns->setName( name );
	ns->setStartPosition( startLine, startColumn );
	ns->setEndPosition( endLine, endColumn );
	ns->setComment( ast->comment() );
	
	ns->setScope( m_currentScope );
	
	if ( m_currentNamespace.top() )
		m_currentNamespace.top() ->addNamespace( ns );
	else
		m_file->addNamespace( ns );
	
	return ns;
}

void StoreWalker::parseFunctionDeclaration( GroupAST* funSpec, GroupAST* storageSpec,
                                            TypeSpecifierAST * typeSpec, InitDeclaratorAST * decl )
{
	bool isFriend = false;
	bool isVirtual = false;
	bool isStatic = false;
	bool isInline = false;
	bool isPure = decl->initializer() != 0;
	
	if ( funSpec )
	{
		TQPtrList<AST> l = funSpec->nodeList();
		TQPtrListIterator<AST> it( l );
		while ( it.current() )
		{
			TQString text = it.current() ->text();
			if ( text == "virtual" )
				isVirtual = true;
			else if ( text == "inline" )
				isInline = true;
			++it;
		}
	}
	
	if ( storageSpec )
	{
		TQPtrList<AST> l = storageSpec->nodeList();
		TQPtrListIterator<AST> it( l );
		while ( it.current() )
		{
			TQString text = it.current() ->text();
			if ( text == "friend" )
				isFriend = true;
			else if ( text == "static" )
				isStatic = true;
			++it;
		}
	}
	
	int startLine, startColumn;
	int endLine, endColumn;
	decl->getStartPosition( &startLine, &startColumn );
	decl->getEndPosition( &endLine, &endColumn );
	
	DeclaratorAST* d = decl->declarator();
	TQString id = d->declaratorId() ->unqualifiedName() ->text();
	
	FunctionDom method = m_store->create<FunctionModel>();
	method->setName( id );
	
	method->setComment( comment() );
	method->setFileName( m_fileName );
	method->setStartPosition( startLine, startColumn );
	method->setEndPosition( endLine, endColumn );
	method->setAccess( m_currentAccess );
	method->setStatic( isStatic );
	method->setVirtual( isVirtual );
	method->setAbstract( isPure );
	parseFunctionArguments( d, method );
	
	checkTemplateDeclarator( & (*method) );
		
	
	if ( m_inSignals )
		method->setSignal( true );
	
	if ( m_inSlots )
		method->setSlot( true );
	
	TQString text = typeOfDeclaration( typeSpec, d );
	if ( !text.isEmpty() )
		method->setResultType( text );
	
	method->setConstant( d->constant() != 0 );
	method->setScope( scopeOfDeclarator( d, m_currentScope ) );
	
	if ( m_currentClass.top() )
		m_currentClass.top() ->addFunction( method );
	else if ( m_currentNamespace.top() )
		m_currentNamespace.top() ->addFunction( method );
	else
		m_file->addFunction( method );
}

void StoreWalker::parseFunctionArguments( DeclaratorAST* declarator, FunctionDom method )
{
	ParameterDeclarationClauseAST * clause = declarator->parameterDeclarationClause();
	
	if ( clause && clause->parameterDeclarationList() )
	{
		ParameterDeclarationListAST * params = clause->parameterDeclarationList();
		TQPtrList<ParameterDeclarationAST> l( params->parameterList() );
		TQPtrListIterator<ParameterDeclarationAST> it( l );
		while ( it.current() )
		{
			ParameterDeclarationAST * param = it.current();
			++it;
			
			ArgumentDom arg = m_store->create<ArgumentModel>();
			
			if ( param->declarator() )
			{
				TQString text = declaratorToString( param->declarator(), TQString(), true );
				if ( !text.isEmpty() )
					arg->setName( text );
			}
			
			TQString tp = typeOfDeclaration( param->typeSpec(), param->declarator() );
			if ( !tp.isEmpty() )
				arg->setType( tp );
			
			method->addArgument( arg );
		}
	}
}

TQString StoreWalker::typeOfDeclaration( TypeSpecifierAST* typeSpec, DeclaratorAST* declarator )
{
	if ( !typeSpec || !declarator )
		return TQString();
	
	TQString text;
	
	text += typeSpec->text();
	
	TQPtrList<AST> ptrOpList = declarator->ptrOpList();
	for ( TQPtrListIterator<AST> it( ptrOpList ); it.current(); ++it )
	{
		text += it.current() ->text();
	}

    for( int a = 0; a < declarator->arrayDimensionList().count(); a++ )
        text += "*";

	
	return text;
}

void StoreWalker::parseBaseClause( BaseClauseAST * baseClause, ClassDom klass )
{
	TQPtrList<BaseSpecifierAST> l = baseClause->baseSpecifierList();
	TQPtrListIterator<BaseSpecifierAST> it( l );
	while ( it.current() )
	{
		BaseSpecifierAST * baseSpecifier = it.current();
		
		TQString baseName;
		if ( baseSpecifier->name() )
			baseName = baseSpecifier->name() ->text();
		
		klass->addBaseClass( baseName );
		
		++it;
	}
}

TQStringList StoreWalker::scopeOfName( NameAST* id, const TQStringList& startScope )
{
	TQStringList scope = startScope;
	if ( id && id->classOrNamespaceNameList().count() )
	{
		if ( id->isGlobal() )
			scope.clear();
		TQPtrList<ClassOrNamespaceNameAST> l = id->classOrNamespaceNameList();
		TQPtrListIterator<ClassOrNamespaceNameAST> it( l );
		while ( it.current() )
		{
			if ( it.current() ->name() )
			{
				scope << it.current() ->name() ->text();
			}
			++it;
		}
	}
	
	return scope;
}


///@todo respect the imports that result from the headers etc.
ClassDom StoreWalker::findClassFromScope( const TQStringList& scope ) 
{
	TQString scopeText = scope.join("::");
	if( !m_imports.isEmpty() ) {
		TQMapIterator<TQString, ClassDom> it = m_imports.back().first.find( scopeText );
		if( it != m_imports.back().first.end() ) {
			return *it;
		}
	}
	
	ClassDom c = classFromScope( scope );
	if( c ) {
		if( !m_imports.isEmpty() ) m_imports.back().first[ scopeText ] = c;
		return c;
	}

	if(!m_imports.isEmpty() && !m_imports.back().second.isEmpty()) {
			///try the same using one of the imports(performance-wise this is not good, but simple)
		
		TQStringList::iterator it = m_imports.back().second.begin();
		while(it != m_imports.back().second.end()) {
			TQStringList scp = TQStringList::split("::", *it) + m_currentScope + scope;
			c = classFromScope( scp );
			if( c ) {
				if( !m_imports.isEmpty() ) m_imports.back().first[ scopeText ] = c;
				return c;
			}
			++it;
		}
	}
	return c;
}

ClassDom  findScopeInFile( const TQStringList& scope, NamespaceModel* glob ) {
		if( !glob ) return ClassDom();
		
		ClassModel* curr =  glob ;
		
		TQStringList::const_iterator mit = scope.begin();
		
		while(curr->isNamespace() && mit != scope.end() && ((NamespaceModel*)curr)->hasNamespace( *mit )) {
			curr = &(*( ((NamespaceModel*)curr)->namespaceByName( *mit ) ));
			++mit;
		}
		
		while((curr->isNamespace() || curr->isClass()) && mit != scope.end() && curr->hasClass( *mit )) {
			ClassList cl = curr->classByName( *mit );
			curr = &(**cl.begin() );
			++mit;
		}
		
		if(mit == scope.end()) {
			return curr;
		} else {
			return ClassDom(0);
		}
}

ClassDom StoreWalker::classFromScope(const TQStringList& scope) {
	if(scope.isEmpty())return ClassDom(0);

	//Since another instance of the current file may still be in the code-model this must be testede BEFORE the code-model
	ClassDom c = findScopeInFile( scope, m_file.data() );
	if( c ) return c;

	NamespaceDom glob = m_store->globalNamespace();
	if( !glob ) return ClassDom();
	c = findScopeInFile( scope, glob );
	
	
	TQMap<TQString, FileDom>::const_iterator it;

	if( c ) {
		///Check the file that overrides the code-model file
		it = m_overrides.find( c->fileName() );
		
		//Find the class within the file that is overriding the one in code-model.
		if( it != m_overrides.end() ) {
			return findScopeInFile( scope, *it );
		} else {
			return c;
		}
	} else {
		///Search in all overrides, because they will be added later all at once
		for( TQMap<TQString, FileDom>::const_iterator it = m_overrides.begin(); it != m_overrides.end(); ++it ) {
			c = findScopeInFile( scope, *it );
			if( c )
				return c;
		}
	}

	return ClassDom(0);
}


TQStringList StoreWalker::scopeOfDeclarator( DeclaratorAST* d, const TQStringList& startScope )
{
	return scopeOfName( d->declaratorId(), startScope );
}
