/* ****************************************************************************
  This file is part of KBabel

  Copyright (C) 2000 by Matthias Kiefer
                            <matthias.kiefer@gmx.de>

  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.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

**************************************************************************** */

#ifndef SEARCH_ENGINE_H
#define SEARCH_ENGINE_H

#include <qdatetime.h>
#include <qptrlist.h>
#include <qobject.h>
#include <qstring.h>
#include <qwidget.h>
#include <kaboutdata.h>
#include <kconfigbase.h>

 
/*
 * This class gives information about the translator, etc.  
 * Information, that is not available in a specific implementation of
 * the SearchEngine, should be left empty.
 */
class TranslationInfo
{
public:
    /** 
     * Information about the location, where this entry was found.
     * For example the PO-file it was found in, etc. 
     * */
    QString location; 

    /**
     * The complete path of the file, where this entry was found
     */
    QString filePath;


    /** The date of the last change */
    QDateTime lastChange;
    
    /** The language, the translation belongs to */
    QString languageCode;

    /**
     * The translator of this string
     * For example the translator found in the header of the PO-file.
     */
    QString translator;


    QString description;
};


/** 
 * This class contains a result from the search
 * plus additional information where it was found,
 * the date and time of the last change, the translator, etc.
 */
class SearchResult
{
public:
    SearchResult();
    SearchResult(const SearchResult&);
        
    /** The requested string to search for */
    QString requested;
    /** The string that, was found */
    QString found;
    /** The translation of the found string */
    QString translation;

    /** 
     * This string contains the plain translation if you are
     * using rich text. If you don't use rich text, you can leave
     * it empty
     */
    QString plainTranslation;

    /** 
     * This string contains the plain string, that was found, if you are
     * using rich text. If you don't use rich text, you can leave
     * it empty
     */
    QString plainFound;
    
    /** 
     * This string contains the plain requested string if you are
     * using rich text. If you don't use rich text, you can leave
     * it empty
     */
    QString plainRequested;
    
    /**
     * Constains a score for the found translation. 0 means exact matching.
     * The higher the score is, the worse is the matching.
     * How to compute the score is not yet really clear :-(
     */
    int score;

    QPtrList<TranslationInfo> descriptions;
};


/**
 * This class is the base class for the preferences widget used to
 * setup the search engines. Inherit from this and reimplement all
 * necessary function. The widget should not be bigger than 400x400.
 * If you need more space, you maybe want to use a tabbed widget.
 */
class PrefWidget : public QWidget
{
    Q_OBJECT
            
public:
    PrefWidget(QWidget *parent, const char* name=0);
    virtual ~PrefWidget();

public slots:
    /**
     * apply changes of the settings
     */
    virtual void apply()=0;
    /**
     * revert made changes
     */
    virtual void cancel()=0;
    /**
     * set settings to the standard options
     */
    virtual void standard()=0;
};


class SearchEngine : public QObject
{
    Q_OBJECT
            
public:
    struct Message
    {
        QString msgid;
        QString msgstr;
    };
        
    SearchEngine(QObject *parent=0, const char *name=0);
    virtual ~SearchEngine();

    

    /** @return the search result number n */
    virtual SearchResult *result(int n);
    
    /** @return the number of search results */
    virtual int numberOfResults() const;

    /** @return true, if a search is currently active */
    virtual bool isSearching() const = 0;
    

    /** save the settings in the given config object */
    virtual void saveSettings(KConfigBase *config) = 0;
    virtual void readSettings(KConfigBase *config) = 0;

    /** @returns true, if it was initialized correctly */
    virtual bool isReady() const =0;


    /** 
     * @returns the exact translation of text or a empty string
     * if no exact match was found.
     */
    virtual QString translate(const QString text)=0;
 
    /** 
     * @returns a fuzzy translation of text or a empty string
     * if no good match was found.
     */
    virtual QString fuzzyTranslation(const QString /*text*/, int &score) { 
      score = 0; return QString::null; };
   

    /**
     * Finds all messages belonging to package package. If nothing is found,
     * the list is empty.
     * @param package The name of the file, something like "kbabel.po"
     * @param resultList Will contain the found messages afterwards
     * @param error If an error occured, this should contain a description
     * 
     * @return true, if successfull
     */
    virtual bool messagesForPackage(const QString& package
                         , QValueList<Message>& resultList, QString& error);
    
    /** 
     * @returns true, if the searchresults are given as rich text
     * the default implementation returns false
     */ 
    virtual bool usesRichTextResults();

    /** @returns true, if the the entries in the database can be edited */
    virtual bool isEditable();
    
    /** 
     * @returns a widget which lets the user setup all preferences of this
     * search engine. The returned widget should not be bigger than
     * 400x400. If you need more space, you maybe want to use
     * a tabbed widget.
     * @param parent the parent of the returned widget
     */
    virtual PrefWidget* preferencesWidget(QWidget *parent)=0;

    /** @returns information about this SearchEngine */
    virtual const KAboutData *about() const= 0;

    /** @returns the i18n name of this search engine */
    virtual QString name() const= 0;

    /** @returns a untranslated name of this engine */
    virtual QString id() const= 0;

    /** @returns the last error message */
    virtual QString lastError() = 0;
            

    /**
     * sets the engine to always ask the preferences dialog for settings
     * if is existing before starting the search.
     */
    virtual void setAutoUpdateOptions(bool activate);


    /**
     *  @returns how good @param text1 matches @param text2
     *  comparing 3-grams .. n-grams, the returned value is
     *  a number between 0 and 100. @param ngram_len should be
     *  a value between 3 and 5. 
     */
    static uint ngramMatch (const QString text1, const QString text2, 
			    uint ngram_len=3);

public slots:
    /**
     * starts a search for string s in the original text
     * @returns false, if an error occured. Use @ref lastError
     * to get the last error message
     */
    virtual bool startSearch(QString s) = 0;

    /**
     * starts a search for string s in the translated text
     * @returns false, if an error occured. Use @ref lastError
     * to get the last error message
     */
    virtual bool startSearchInTranslation(QString s);


    /** stops a search */
    virtual void stopSearch() = 0;

    /** @return the next search result */
    virtual SearchResult *nextResult();
    
    /** @return the previous search result */
    virtual SearchResult *prevResult();

    /** @return the first search result */
    virtual SearchResult *firstResult();

    /** @return the last search result */
    virtual SearchResult *lastResult();
    
    /** clears the result list */
    virtual void clearResults();
    

    /**
     * This method allows a search engine to use different settings depending
     * on the edited file. The default implementation does nothing.
     * @param file The edited file with path
     */
    virtual void setEditedFile(QString file);

    /**
     * This method allows a search engine to use different settings depending
     * on the edited package. The default implementation does nothing.
     * @param package The name of the package, that is currently translated.
     */
    virtual void setEditedPackage(QString package);

    /**
     * This method allows a search engine to use different settings depending
     * on the language code. The default implementation does nothing.
     * @param lang The current language code (e.g. de).
     */
    virtual void setLanguageCode(QString lang);
    virtual void setLanguage(QString languageCode, QString languageName);



    /**
     * This method is called, if something has been changed in the
     * current file. See @ref setEditedFile if you want to know the file
     * name
     * @param orig the original string
     * @param translation the translated string  
     */
     virtual void stringChanged( QString orig, QString translated
                     , QString description);
    
    /**
     * If the database is editable this slot should open an dialog to let
     * the user edit the contents of the database.
     */
    virtual void edit();

    /** 
     * @returns the n-th directory name of path. Counting is started at
     * end of path. Example: directory("/usr/local/src/foobar, 0")
     * returns "foobar", while n=1 would return "src"
     */
    static QString directory(const QString& path, int n);

    /**
     * computes a score to assess the match of the two strings:
     * 0 means exact match, bigger means worse
     */
    static uint score(const QString& orig, const QString& found);
     
signals:
    /** signals, that a new search started */
    void started();
    
    /** 
     * signals progress in searching 
     * @param p should be between 0 and 100
     * */
    void progress(int p);
    
    /**
     * Use this, if you want to set your own message on the
     * progressbar or if you do something else then searching,
     * maybe loading a big file
     */
    void progressStarts(const QString);

    void progressEnds();
    
    /** 
     * signals, that the number of search results has changed 
     * @param n the new number of results
     * */
    void numberOfResultsChanged(int n);

    /**
     * signals, that the order of the results in the list has changed.
     * For example because a better matching string has been prepended.
     */
    void resultsReordered();

    /**
     * signals, that a new result was found
     */
    void resultFound(const SearchResult*);

    /** 
     * signals, that search has finished
     */
    void finished();
    
    /**
     * signals, that an error occured, for example, that you wasn't
     * able to open a database.      
     */ 
     void hasError(QString error);

protected:
    QPtrList<SearchResult> results;
    bool autoUpdate;
};


#endif // SEARCH_ENGINE_H
