/*
    This file is part of Kiten, a KDE Japanese Reference Tool
    SPDX-FileCopyrightText: 2006 Joseph Kerian <jkerian@gmail.com>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#ifndef KITEN_DICTFILE_H
#define KITEN_DICTFILE_H

#include "kiten_export.h"

#include <QMap>
#include <QStringList>

class DictQuery;
class DictionaryPreferenceDialog;
class Entry;
class EntryList;
class KConfig;
class KConfigSkeleton;
class QWidget;

/**
 * @short Abstract base class, used internally by the library for handling different types of dictionaries
 * This is a virtual class that enforces the interface between the DictionaryManager
 * class and the DictionaryManager.handler files. IMPLEMENT in combination with an
 * Entry subclass (if needed) to add a new dictionary format. Also see the addDictionary
 * method in the DictionaryManager class.
 *
 * This documentation is mostly for those who are adding a new type of dictionary to
 * kiten. This class is not exported outside of the library. */
class /* NO_EXPORT */ DictFile
{
private:
    /**
     * You are not allowed to create a dictFile subclass without specifying the type-name
     */
    DictFile() = default;

public:
    /**
     * Use this constructor for your subclasses. Dictionary subclasses MUST specify their type
     * at creation.
     */
    explicit DictFile(const QString &dictionaryTypeName)
        : m_dictionaryType(dictionaryTypeName)
    {
    }
    /**
     * Destructor
     */
    virtual ~DictFile() = default;
    /**
     * This method allows the user to test if a dictionary is the proper type for this format.
     * This process is allowed to take some time, but nonetheless you should find checking the format
     * of a few hundred entries sufficient for this.
     *
     * @param filename the name of the file, suitable for using with QFile::setFileName() */
    virtual bool validDictionaryFile(const QString &filename) = 0;
    /**
     * Is this query relevant to this dictionary type? Usually this will return true,
     * unless the query specifies extended attributes that the dictionary does not provide.
     *
     * @param query the query to examine for relevance to this dictionary type */
    virtual bool validQuery(const DictQuery &query) = 0;
    /**
     * This actually conducts the search on the given query. This is usually most of the work
     *
     * @param query the DictQuery that specifies what results to return
     */
    virtual EntryList *doSearch(const DictQuery &query) = 0;
    /**
     * Load a dictionary as at system startup.
     *
     * @param file the file to open, in a format suitable for use with QFile::setFileName()
     * @param name the name of the file to open, used in various user-interface aspects.
     *             It may be related to the file parameter, but perhaps not.
     */
    virtual bool loadDictionary(const QString &file, const QString &name) = 0;
    /**
     * Load a new dictionary. This is called with the assumption that this dictionary
     * has not been opened previously, in case you need to build an index or other activity.
     * If you do not re-implement this method, it simply calls loadDictionary().
     *
     * @param file the file to open, in a format suitable for use with QFile::setFileName()
     * @param name the name of the file to open, used in various user-interface aspects.
     *             It may be related to the file parameter, but perhaps not.
     */
    virtual bool loadNewDictionary(const QString &file, const QString &name)
    {
        return loadDictionary(file, name);
    }
    /**
     * Return a list of the fields that can be displayed, note the following
     * should probably always be returned: --NewLine--, Word/Kanji, Meaning,
     * Reading.  This function is passed a list originally containing those
     * four items. This function is used to enumerate possible types the user
     * chooses to have displayed in the preferences dialog box.
     * This will often be a very similar list to getSearchableAttributes(),
     * but due to optional forms of spelling and other situations, it may
     * not be exactly the same. Note: The "Dictionary" option will be
     * appended to your list at the end.
     */
    virtual QStringList listDictDisplayOptions(QStringList) const = 0;
    /**
     * If you want your own dialog to pick preferences for your dict, then override this.
     * Leaving it blank will leave your dictionary type without a preferences dialog.
     *
     * @param config the KConfigSkeleton object that is currently in use
     * @param parent the parent widget for your preferences dialog
     */
    virtual DictionaryPreferenceDialog *preferencesWidget(KConfigSkeleton *config, QWidget *parent = nullptr)
    {
        Q_UNUSED(parent)
        Q_UNUSED(config)
        return nullptr;
    }
    /**
     * Load information from the KConfigSkeleton that you've setup in
     * the above preferences widget.
     */
    virtual void loadSettings(KConfigSkeleton *)
    {
    }

    /**
     * Returns the name of the dictionary
     */
    virtual QString getName() const
    {
        return m_dictionaryName;
    }
    /**
     * Returns the type of files this dictFile object deals with
     */
    virtual QString getType() const
    {
        return m_dictionaryType;
    }
    /**
     * Returns the file that this is working with, usually used in the preferences display
     */
    virtual QString getFile() const
    {
        return m_dictionaryFile;
    }
    /**
     * Fetch a list of searchable attributes and their codes
     */
    virtual const QMap<QString, QString> &getSearchableAttributes() const
    {
        return m_searchableAttributes;
    }

protected:
    /**
     * Name is the 'primary key' of the list of dictionaries. You will want to
     * place this into your Entry objects to identify where they came from
     * (fairly important)
     */
    QString m_dictionaryName;

    /**
     * This is mostly a placeholder, but your class will get asked what file
     * it is using, so either be sure to put something here, or override
     * getFile() and respond with something that will be sensical in a
     * dictionary selection dialog box.
     */
    QString m_dictionaryFile;

    /**
     * This MUST BE SET IN THE CONSTRUCTOR. The dictionary class occasionally
     * uses this value and it's important for it to be set at anytime after the
     * constructor is called. It also must be unique to the dictionary type. If
     * relevant, specify dictionary versions here.
     */
    QString m_dictionaryType;
    /**
     * This allows the programming user to see a list
     * of possible search types (probably through a drop down menu).
     * You may also find it useful in your dictFile implementation
     * to translate from extended attribute keys into the simpler one or two letter
     * code keys. These should take the format of:
     * (Kanji Grade => G), (Strokes => S), (Heisig Number => H)
     * for a simple example appropriate to kanji.
     */
    QMap<QString, QString> m_searchableAttributes;
};

#endif
