/***************************************************************************
*   Copyright (C) 2004 by                                                 *
*   Jason Kivlighn (jkivlighn@gmail.com)                                  *
*                                                                         *
*   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 "kretextedit.h"

#include <tqtextstream.h>

#include <tdeaccel.h>
#include <kdebug.h>

KreTextEdit::KreTextEdit( TQWidget *parent ) : KTextEdit( parent ), TDECompletionBase()
{
	TDECompletion * comp = completionObject(); //creates the completion object
	comp->setIgnoreCase( true );

	completing = false;

	connect( this, TQ_SIGNAL( clicked( int, int ) ), TQ_SLOT( haltCompletion() ) );
}

void KreTextEdit::haltCompletion()
{
	completing = false;
}

void KreTextEdit::keyPressEvent( TQKeyEvent *e )
{
	// Filter key-events if completion mode is not set to CompletionNone
	KKey key( e );

	KeyBindingMap keys = getKeyBindings();
	TDEShortcut cut;
	bool noModifier = ( e->state() == NoButton || e->state() == ShiftButton );

	if ( noModifier ) {
		TQString keycode = e->text();
		if ( !keycode.isEmpty() && keycode.unicode() ->isPrint() ) {
			TQTextEdit::keyPressEvent ( e );
			tryCompletion();
			e->accept();
			return ;
		}
	}

	// Handles completion
	if ( keys[ TextCompletion ].isNull() )
		cut = TDEStdAccel::shortcut( TDEStdAccel::TextCompletion );
	else
		cut = keys[ TextCompletion ];

	//using just the standard Ctrl+E isn't user-friendly enough for Grandma...
	if ( completing && ( cut.contains( key ) || e->key() == TQt::Key_Enter || e->key() == TQt::Key_Return ) ) {
		int paraFrom, indexFrom, paraTo, indexTo;
		getSelection ( &paraFrom, &indexFrom, &paraTo, &indexTo );

		removeSelection();
		setCursorPosition( paraTo, indexTo );

		completing = false;
		return ;
	}

	// handle rotation

	// Handles previous match
	if ( keys[ PrevCompletionMatch ].isNull() )
		cut = TDEStdAccel::shortcut( TDEStdAccel::PrevCompletion );
	else
		cut = keys[ PrevCompletionMatch ];

	if ( cut.contains( key ) ) {
		rotateText( TDECompletionBase::PrevCompletionMatch );
		return ;
	}

	// Handles next match
	if ( keys[ NextCompletionMatch ].isNull() )
		cut = TDEStdAccel::shortcut( TDEStdAccel::NextCompletion );
	else
		cut = keys[ NextCompletionMatch ];

	if ( cut.contains( key ) ) {
		rotateText( TDECompletionBase::NextCompletionMatch );
		return ;
	}

	//any other key events will end any text completion execpt for modifiers
	switch ( e->key() ) {
	case TQt::Key_Shift:
	case TQt::Key_Control:
	case TQt::Key_Alt:
	case TQt::Key_Meta:
		break;
	default:
		completing = false;
		break;
	}

	// Let KTextEdit handle any other keys events.
	KTextEdit::keyPressEvent ( e );
}

void KreTextEdit::setCompletedText( const TQString &txt )
{
	int para, index;
	getCursorPosition( &para, &index );

	TQString para_text = text( para );
	int word_length = index - completion_begin;

	insert( txt.right( txt.length() - word_length ) );
	setSelection( para, index, para, completion_begin + txt.length() );
	setCursorPosition( para, index );

	completing = true;
}

void KreTextEdit::setCompletedItems( const TQStringList &/*items*/ )
{}

void KreTextEdit::tryCompletion()
{
	int para, index;
	getCursorPosition( &para, &index );

	TQString para_text = text( para );
	if ( para_text.at( index ).isSpace() || completing ) {
		if ( !completing )
			completion_begin = para_text.findRev( ' ', index - 1 ) + 1;

		TQString completing_word = para_text.mid( completion_begin, index - completion_begin );

		TQString match = compObj() ->makeCompletion( completing_word );

		if ( !match.isNull() && match != completing_word )
			setCompletedText( match );
		else
			completing = false;
	}
}

void KreTextEdit::rotateText( TDECompletionBase::KeyBindingType type )
{
	TDECompletion * comp = compObj();
	if ( comp && completing &&
	        ( type == TDECompletionBase::PrevCompletionMatch ||
	          type == TDECompletionBase::NextCompletionMatch ) ) {
		TQString input = ( type == TDECompletionBase::PrevCompletionMatch ) ? comp->previousMatch() : comp->nextMatch();

		// Skip rotation if previous/next match is null or the same text
		int para, index;
		getCursorPosition( &para, &index );
		TQString para_text = text( para );
		TQString complete_word = para_text.mid( completion_begin, index - completion_begin );
		if ( input.isNull() || input == complete_word )
			return ;
		setCompletedText( input );
	}
}

void KreTextEdit::addCompletionItem( const TQString &name )
{
	compObj() ->addItem( name );
}

void KreTextEdit::removeCompletionItem( const TQString &name )
{
	compObj() ->removeItem( name );
}

void KreTextEdit::clearCompletionItems()
{
	compObj() ->clear();
}

#include "kretextedit.moc"
