/* This file is part of KOffice
   Copyright (C) 2004 Zack Rusin <zack@kde.org>

   Original version written by David Sweet <dsweet@kde.org> and
         Wolfram Diestel <wolfram@steloj.de>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "config.h"
#include "KoSpell.h"

#include "KoTextObject.h"
#include "KoTextParag.h"
#include "KoTextIterator.h"

#include <tdespell2/broker.h>
#include <tdespell2/filter.h>

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

#include <tqtimer.h>

//#define DEBUG_SPELL

using namespace KSpell2;

class KoSpell::Private
{
public:
    KoTextIterator *itr;
    KoTextParag    *parag;
    bool            dialog;
    bool            needsIncrement;
    KoTextDocument *lastTxtDocument;
};

KoSpell::KoSpell( const Broker::Ptr& broker,  TQObject *parent,
                  const char *name )
    : BackgroundChecker( broker, parent, name )
{
    d = new Private;
    d->parag = 0;
    d->itr = 0;
    d->dialog = false;
    d->needsIncrement = false;
    d->lastTxtDocument = 0;
}

KoSpell::~KoSpell()
{
    delete d;
}

bool KoSpell::check( KoTextIterator *itr, bool dialog )
{
    bool ret = false;

    if ( !itr )
        return ret;

    d->itr = itr;
    connect( d->itr, TQT_SIGNAL( currentParagraphDeleted() ), TQT_SLOT( slotCurrentParagraphDeleted() ) );
    d->lastTxtDocument = d->itr->currentTextObject()->textDocument();
    d->needsIncrement = false;
    ret = !d->itr->atEnd();
    d->dialog = dialog;

    return ret;
}

bool KoSpell::check( KoTextParag *parag )
{
    if ( checking() || !parag )
        return false;

    d->parag = parag;
    d->lastTxtDocument = d->parag->textDocument();

    start();

    return true;
}

bool KoSpell::checkWordInParagraph( KoTextParag *parag, int pos,
                                    TQString& foundWord, int& start )
{
    if ( !parag ) {
        start = -1;
        return false;
    }

    d->parag = parag;
    d->lastTxtDocument = d->parag->textDocument();
    TQString str = parag->string()->stringToSpellCheck();
    /// ##### do we really need to create a Filter every time?
    Filter filter;
    filter.setBuffer( str );
    filter.setSettings( broker()->settings() );
    Word w = filter.wordAtPosition( pos );
    foundWord = w.word;
    start = w.start;
#ifdef DEBUG_SPELL
    kdDebug()<<"KoSpell: WORD IS " << w.word << ", pos = "<< pos
             << ", start = "<< w.start <<endl;
#endif
    return checkWord( w.word );
}

TQString KoSpell::getMoreText()
{
#ifdef DEBUG_SPELL
    kdDebug()<<"getMoreText: dialog = " << d->dialog << ", itr = "
             << d->itr << ", atEnd = "
             << ( ( d->itr ) ? d->itr->atEnd() : true )
             << " d->parag=" << d->parag
             << endl;
#endif

    if ( d->needsIncrement && d->itr && !d->itr->atEnd() ) {
        ++( *d->itr );
        if ( !d->itr->atEnd() )
            d->lastTxtDocument = d->itr->currentTextObject()->textDocument();
    }

    if ( d->itr && d->itr->atEnd() )
        return TQString();

    if ( !d->dialog && !d->itr ) {
        TQString str = d->parag ? d->parag->string()->stringToSpellCheck() : TQString();
        if ( !str.isEmpty() )
            emit aboutToFeedText();
        return str;
    }

    d->needsIncrement = true;

    TQString text = d->itr->currentText();
    d->parag = d->itr->currentParag();

    emit aboutToFeedText();
    //kdDebug()<<"here 2"<<endl;
    while ( !d->dialog && d->parag ) {
        if ( d->parag->string()->needsSpellCheck() &&
             d->parag->length() > 1 )
            break;
        ++(*d->itr);
        if ( d->itr->atEnd() ) {
            d->needsIncrement = false;
            return TQString();
        }
        d->parag = d->itr->currentParag();
        d->lastTxtDocument = d->parag->textDocument();
        text = d->itr->currentText();
    }

    d->parag->string()->setNeedsSpellCheck( false );

    return text;
}

void KoSpell::finishedCurrentFeed()
{
    emit paragraphChecked( d->parag );
}

KoTextParag  *KoSpell::currentParag() const
{
    return d->parag;
}

KoTextObject *KoSpell::currentTextObject() const
{
    if ( d->itr && !d->itr->atEnd() )
        return d->itr->currentTextObject();
    return 0;
}

int KoSpell::currentStartIndex() const
{
    if ( d->itr && !d->itr->atEnd() )
        return d->itr->currentStartIndex();
    return 0;
}

void KoSpell::slotCurrentParagraphDeleted()
{
#ifdef DEBUG_SPELL
    kdDebug() << "KoSpell::slotCurrentParagraphDeleted itr=" << d->itr << endl;
#endif
    stop();
    if ( d->itr ) {
        d->needsIncrement = false;
        d->parag = d->itr->currentParag();
#ifdef DEBUG_SPELL
        kdDebug() << "KoSpell::slotCurrentParagraphDeleted d->parag=" << d->parag << endl;
#endif
        start();
    } else {
        d->parag = 0;
    }
}

bool KoSpell::checking() const
{
#ifdef DEBUG_SPELL
    kdDebug()<< "KoSpell::checking: itr=" << d->itr
             << ", atEnd=" << ( ( d->itr ) ? d->itr->atEnd() : false )
             << ", filter()->atEnd()=" << filter()->atEnd()
             << endl;
#endif
    if ( d->itr ) {
        if ( d->itr->atEnd() &&
             filter()->atEnd() )
            return false;
        else
            return true;
    } else
        return !filter()->atEnd();
}

KoTextDocument * KoSpell::textDocument() const
{
    return d->lastTxtDocument;
}

KSpell2::Settings * KoSpell::settings() const
{
    return broker()->settings();
}

#include "KoSpell.moc"