/***************************************************************************
*   Copyright (C) 2002 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 "ast_utils.h"
#include "ast.h"

#include <tqstringlist.h>
#include <tqregexp.h>

#include <tdelocale.h>
#include <kdebug.h>
#include <tdeapplication.h>

#include <tdetexteditor/editinterface.h>

#include "cppsupport_utils.h"

AST* findNodeAt( AST* node, int line, int column )
{
	// kdDebug(9007) << "findNodeAt(" << node << ")" << endl;
	
	if ( !node )
		return 0;
	
	int startLine, startColumn;
	int endLine, endColumn;
	
	node->getStartPosition( &startLine, &startColumn );
	node->getEndPosition( &endLine, &endColumn );
	
	if ( ( line > startLine || ( line == startLine && column >= startColumn ) ) &&
	     ( line < endLine || ( line == endLine && column < endColumn ) ) )
	{
		
		TQPtrList<AST> children = node->children();
		TQPtrListIterator<AST> it( children );
		while ( it.current() )
		{
			AST * a = it.current();
			++it;
			
			AST* r = findNodeAt( a, line, column );
			if ( r )
				return r;
		}
		
		return node;
	}
	
	return 0;
}

void scopeOfNode( AST* ast, TQStringList& scope )
{
	if ( !ast )
		return ;
	
	if ( ast->parent() )
		scopeOfNode( ast->parent(), scope );
	
	TQString s;
	switch ( ast->nodeType() )
	{
	case NodeType_ClassSpecifier:
		if ( ( ( ClassSpecifierAST* ) ast ) ->name() )
		{
			s = ( ( ClassSpecifierAST* ) ast ) ->name() ->text();
			s = s.isEmpty() ? TQString::fromLatin1( "<unnamed>" ) : s;
			scope.push_back( s );
		}
		break;
		
	case NodeType_Namespace:
		{
			AST* namespaceName = ( ( NamespaceAST* ) ast ) ->namespaceName();
			s = namespaceName ? namespaceName->text() : TQString::fromLatin1( "<unnamed>" );
			scope.push_back( s );
		}
		break;
		
	case NodeType_FunctionDefinition:
		{
			FunctionDefinitionAST* funDef = static_cast<FunctionDefinitionAST*>( ast );
			DeclaratorAST* d = funDef->initDeclarator() ->declarator();
			
			// hotfix for bug #68726
			if ( !d->declaratorId() )
				break;
			
			TQPtrList<ClassOrNamespaceNameAST> l = d->declaratorId() ->classOrNamespaceNameList();
			TQPtrListIterator<ClassOrNamespaceNameAST> nameIt( l );
			while ( nameIt.current() )
			{
				AST * name = nameIt.current() ->name();
				scope.push_back( name->text() );
				
				++nameIt;
			}
		}
		break;
		
	default:
		break;
	}
}


TQString typeSpecToString( TypeSpecifierAST* typeSpec )   /// @todo remove
{
	if ( !typeSpec )
		return TQString();
	
	return typeSpec->text().replace( TQRegExp( " :: " ), "::" );
}

TQString declaratorToString( DeclaratorAST* declarator, const TQString& scope, bool skipPtrOp )
{
	if ( !declarator )
		return TQString();
	
	TQString text;
	
	if ( !skipPtrOp )
	{
		TQPtrList<AST> ptrOpList = declarator->ptrOpList();
		for ( TQPtrListIterator<AST> it( ptrOpList ); it.current(); ++it )
		{
			text += it.current() ->text();
		}
		text += " ";
	}
	
	text += scope;
	
	if ( declarator->subDeclarator() )
		text += TQString::fromLatin1( "(" ) + declaratorToString( declarator->subDeclarator() ) + TQString::fromLatin1( ")" );
	
	if ( declarator->declaratorId() )
		text += declarator->declaratorId() ->text();
	
	TQPtrList<AST> arrays = declarator->arrayDimensionList();
	TQPtrListIterator<AST> it( arrays );
	while ( it.current() )
	{
		text += "[]";
		++it;
	}
	
	if ( declarator->parameterDeclarationClause() )
	{
		text += formattedOpeningParenthesis();
		
		ParameterDeclarationListAST* l = declarator->parameterDeclarationClause() ->parameterDeclarationList();
		if ( l != 0 )
		{
			TQPtrList<ParameterDeclarationAST> params = l->parameterList();
			TQPtrListIterator<ParameterDeclarationAST> it( params );
			
			while ( it.current() )
			{
				TQString type = typeSpecToString( it.current() ->typeSpec() );
				text += type;
				if ( !type.isEmpty() )
					text += " ";
				text += declaratorToString( it.current() ->declarator() );
				
				++it;
				
				if ( it.current() )
					text += ", ";
			}
		}
		
		text += formattedClosingParenthesis();
		
		if ( declarator->constant() != 0 )
			text += " const";
	}

	return text.replace( TQRegExp( " :: " ), "::" ).simplifyWhiteSpace();
}
