#ifndef CONFIGDIALOG_H
#define CONFIGDIALOG_H

#include "config_builder.h"
#include "datatype.h"
#include "common/bihash.h"
#include "gui_global.h"
#include <QDialog>
#include <QHash>


class QTableWidgetItem;

class CellRendererPlugin;

class ComboNoWheelFilter;

class QKeySequenceEdit;
namespace Ui {
    class ConfigDialog;
}

class QListWidgetItem;
class QTreeWidgetItem;
class CustomConfigWidgetPlugin;
class QSignalMapper;
class Plugin;
class PluginType;
class QComboBox;
class QToolButton;
class QTreeWidget;
class QListWidget;
class QTableWidget;
class ConfigMapper;
class MultiEditorWidgetPlugin;
class ConfigNotifiablePlugin;
class UiConfiguredPlugin;
class SyntaxHighlighterPlugin;
class QPlainTextEdit;
class QSyntaxHighlighter;
class SqlEditor;

#define CFG_UI_NAME "Ui"
#define CFG_COLORS_NAME "Colors"

class GUI_API_EXPORT ConfigDialog : public QDialog
{
    Q_OBJECT

    public:
        explicit ConfigDialog(QWidget *parent = 0);
        ~ConfigDialog();

        static QList<CfgMain*> getShortcutsCfgMains();

        void configureDataEditors(const QString& dataTypeString);
        void openAtSettingWidget(const QString& categoryKey, const QString& widgetName);
        QWidget* openAtSettingCategory(const QString& categoryKey);
        void openAtSettingHotkey(const QString& categoryKey, const QString& hotkeyName);

        static QString getFilterString(QWidget* widget);
        static QString getFilterString(QComboBox* widget);
        static QString getFilterString(QTreeWidget* widget);
        static QString getFilterString(QListWidget* widget);
        static QString getFilterString(QTableWidget* widget);

        static ConfigDialog* openModal();

    protected:
        void showEvent(QShowEvent* event);

    private:
        void init();
        void load();
        void initCategoriesTree();
        void initPageMap();
        void initInternalCustomConfigWidgets();
        void initFormatterPlugins();
        void initPlugins();
        void initPluginsPage();
        bool initPluginPage(Plugin* plugin, bool skipConfigLoading);
        void deinitPluginPage(Plugin* pluginName);
        void initDataEditors();
        void initDataRenderers();
        void initShortcuts();
        void initShortcuts(CfgCategory* cfgCategory);
        void initLangs();
        void initTooltips();
        void initColors();
        void initLookAndFeelPage();
        void initScale();
        void initIconSets();
        void applyStyle(QWidget* widget, QStyle* style);
        QTreeWidgetItem* getPluginsCategoryItem() const;
        QTreeWidgetItem* getPluginsCategoryItem(PluginType* type) const;
        QTreeWidgetItem* getPluginItem(Plugin* plugin) const;
        QTreeWidgetItem* createPluginsTypeItem(const QString& widgetName, const QString& title) const;
        QTreeWidgetItem* getItemByTitle(const QString& title) const;
        void switchPageToPlugin(QTreeWidgetItem* item);
        bool isPluginCategoryItem(QTreeWidgetItem *item) const;
        void codeFormatterUnloaded();
        void codeFormatterLoaded();
        void updatePluginCategoriesVisibility(QTreeWidgetItem* categoryItem);
        QString collectLoadedPlugins() const;
        QHash<QWidget*,QTreeWidgetItem*> buildPageToCategoryItemMap() const;
        QList<QTreeWidgetItem*> getAllCategoryItems() const;
        QList<MultiEditorWidgetPlugin*> getDefaultEditorsForType(DataType::Enum dataType);
        QList<MultiEditorWidgetPlugin*> updateCustomDataTypeEditors(const QStringList& editorsOrder);
        QList<MultiEditorWidgetPlugin*> updateDefaultDataTypeEditors(DataType::Enum typeEnum);
        void addDataTypeEditor(const QString& pluginName);
        void addDataTypeEditor(MultiEditorWidgetPlugin* plugin);
        void removeDataTypeEditor(QListWidgetItem* item, const QString& pluginName);
        void removeDataTypeEditor(int idx);
        void transformDataTypeEditorsToCustomList(QListWidgetItem* typeItem);
        QStringList getPluginNamesFromDataTypeItem(QListWidgetItem* typeItem, bool* exists = nullptr);
        void setPluginNamesForDataTypeItem(QListWidgetItem* typeItem, const QStringList& pluginNames);
        void addEditorDataType(const QString& typeStr);
        void addRendererDataType(const QString& typeStr);
        void defineDefaultStyleForRendererCombo(QComboBox* combo);
        void defineAltStyleForRendererCombo(QComboBox* combo, int idx);
        void applyRendererComboStyle(QComboBox* combo, int idx);
        void saveIconSet();
        void rollbackPluginConfigs();
        void rollbackColorsConfig();
        void commitPluginConfigs();
        void commitColorsConfig();
        void connectMapperSignals(ConfigMapper* mapper);
        QList<CfgCategory*> getShortcutsCfgCategories() const;
        void refreshColorsInSyntaxHighlighters();
        void colorChanged();
        QList<QWidget*> getUnmodifiedSyntaxSettingWidgets();
        void adjustSyntaxColorsForStyle(QList<QWidget*>& unmodifiedColors);
        void highlighterPluginLoaded(SyntaxHighlighterPlugin* plugin);
        void highlighterPluginUnloaded(SyntaxHighlighterPlugin* plugin);
        void dataTypeEditorPluginLoaded(MultiEditorWidgetPlugin* plugin);
        void dataTypeEditorPluginUnloaded(MultiEditorWidgetPlugin* plugin);
        void rememberLastUsedPage();
        void restoreLastUsedPage();
        void resetShortcut(CfgEntry* entry, QKeySequenceEdit* seqEdit);
        void markTargetWidget(bool marked);

        Ui::ConfigDialog *ui = nullptr;
        QWidget* targetWidgetOnOpen = nullptr;
        QStyle* previewStyle = nullptr;
        QHash<QString,QWidget*> nameToPage;
        BiHash<QTreeWidgetItem*,QString> pluginListItemToPluginNameMap;
        QHash<PluginType*,QTreeWidgetItem*> pluginTypeToItemMap;
        QHash<Plugin*,QTreeWidgetItem*> pluginToItemMap;
        QHash<QString,QComboBox*> formatterLangToPluginComboMap;
        QHash<QString,QToolButton*> formatterLangToConfigButtonMap;
        ConfigMapper* configMapper = nullptr;
        QHash<UiConfiguredPlugin*,ConfigMapper*> pluginConfigMappers;
        QAction* dataEditRenameAction = nullptr;
        QAction* dataEditDeleteAction = nullptr;
        QAction* dataRenderRenameAction = nullptr;
        QAction* dataRenderDeleteAction = nullptr;
        bool updatingDataEditorItem = false;
        bool updatingDataRendererItem = false;
        bool modifiedFlag = false;
        QList<ConfigNotifiablePlugin*> notifiablePlugins;
        bool requiresSchemasRefresh = false;
        QList<QPlainTextEdit*> colorPreviewEditors;
        SqlEditor* codePreviewSqlEditor = nullptr;
        QList<QSyntaxHighlighter*> colorPreviewHighlighters;
        BiHash<QPlainTextEdit*, SyntaxHighlighterPlugin*> highlightingPluginForPreviewEditor;
        bool resettingColors = false;

    private slots:
        void refreshFormattersPage();
        void pageSwitched();
        void updateDataTypeEditors();
        void updateDataTypeListState();
        void updateDataTypeRendererState();
        void dataEditorItemEdited(QListWidgetItem* item);
        void dataEditorAvailableChanged(QListWidgetItem* item);
        void dataEditorTabsOrderChanged(int from, int to);
        void dataRendererItemEdited(QTableWidgetItem* item);
        void addEditorDataType();
        void renameEditorDataType();
        void delEditorDataType();
        void addRendererDataType();
        void renameRendererDataType();
        void delRendererDataType();
        void switchPage(QTreeWidgetItem* item);
        void updateStylePreview();
        void apply();
        void save();
        void storeSelectedFormatters();
        void markModified();
        void setModified(bool modified);
        void updateModified();
        void applyFilter(const QString& filter);
        void updateActiveFormatterState();
        void configureFormatter(const QString& pluginTitle);
        void activeFormatterChanged();
        void detailsClicked(const QString& pluginName);
        void loadUnloadPlugin(const QString& pluginName, bool checked);
        void pluginAboutToUnload(Plugin* plugin, PluginType* type);
        void pluginLoaded(Plugin* plugin, PluginType* type, bool skipConfigLoading = false);
        void pluginUnloaded(const QString& pluginName, PluginType* type);
        void updatePluginCategoriesVisibility();
        void updateBuiltInPluginsVisibility();
        void applyShortcutsFilter(const QString& filter);
        void markRequiresSchemasRefresh();
        void notifyPluginsAboutModification(QWidget*, CfgEntry* key, const QVariant& value);
        void resetCodeSyntaxColors();
        void resetShortcuts();
        void updateIconSetPreview();

    public slots:
        void accept();
};

#endif // CONFIGDIALOG_H
