// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include "behaviorsettings.h"

#include "extraencodingsettings.h"
#include "icodestylepreferences.h"
#include "storagesettings.h"
#include "tabsettings.h"
#include "texteditorconstants.h"
#include "texteditortr.h"
#include "typingsettings.h"

#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/messagemanager.h>

#include <utils/fancylineedit.h>
#include <utils/hostosinfo.h>
#include <utils/layoutbuilder.h>

using namespace Utils;

namespace TextEditor {

BehaviorSettings::BehaviorSettings(const Key &keyPrefix)
{
    setSettingsGroup("textBehaviorSettings");

    mouseHiding.setSettingsKey(keyPrefix + "MouseHiding");
    mouseHiding.setDefaultValue(true);
    mouseHiding.setVisible(!HostOsInfo::isMacHost());
    mouseHiding.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
    mouseHiding.setLabelText(Tr::tr("Hide mouse cursor while typing"));

    mouseNavigation.setSettingsKey(keyPrefix + "MouseNavigation");
    mouseNavigation.setDefaultValue(true);
    mouseNavigation.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
    mouseNavigation.setLabelText(Tr::tr("Enable &mouse navigation"));

    scrollWheelZooming.setSettingsKey(keyPrefix + "ScrollWheelZooming");
    scrollWheelZooming.setDefaultValue(true);
    scrollWheelZooming.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
    scrollWheelZooming.setLabelText(Tr::tr("Enable scroll &wheel zooming"));

    constrainHoverTooltips.setSettingsKey(keyPrefix + "ConstrainTooltips");
    constrainHoverTooltips.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
    constrainHoverTooltips.setUseDataAsSavedValue();
    constrainHoverTooltips.setLabelText(Tr::tr("Show help tooltips using the mouse:"));
    constrainHoverTooltips.addOption({
        Tr::tr("On Mouseover"),
        Tr::tr("Displays context-sensitive help or type information on mouseover."),
        QVariant(false)
    });
    constrainHoverTooltips.addOption({
        Tr::tr("On Shift+Mouseover"),
        Tr::tr("Displays context-sensitive help or type information on Shift+Mouseover."),
        QVariant(true)
    });
    constrainHoverTooltips.setLabelText(Tr::tr("Show help tooltips using the mouse:"));

    camelCaseNavigation.setSettingsKey(keyPrefix + "CamelCaseNavigation");
    camelCaseNavigation.setDefaultValue(true);
    camelCaseNavigation.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
    camelCaseNavigation.setLabelText(Tr::tr("Enable built-in camel case &navigation"));

    keyboardTooltips.setSettingsKey(keyPrefix + "KeyboardTooltips");
    keyboardTooltips.setDefaultValue(false);
    keyboardTooltips.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
    keyboardTooltips.setLabelText(Tr::tr("Show help tooltips using keyboard shortcut (Alt)"));
    keyboardTooltips.setToolTip(Tr::tr("Pressing Alt displays context-sensitive help or type information as tooltips."));

    smartSelectionChanging.setSettingsKey(keyPrefix + "SmartSelectionChanging");
    smartSelectionChanging.setDefaultValue(true);
    smartSelectionChanging.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
    smartSelectionChanging.setLabelText(Tr::tr("Enable smart selection changing"));
    smartSelectionChanging.setToolTip(Tr::tr("Using Select Block Up / Down actions will now provide smarter selections."));

    setLayouter([this] {
        using namespace Layouting;
        return Column {
            Group {
                title(Tr::tr("Mouse and Keyboard")),
                Row {
                    Form {
                        mouseHiding, br,
                        mouseNavigation, br,
                        scrollWheelZooming, br,
                        camelCaseNavigation, br,
                        smartSelectionChanging, br,
                        keyboardTooltips, br,
                        constrainHoverTooltips, br
                    }, st
                }
            }
        };
    });
}

void BehaviorSettings::setData(const BehaviorSettingsData &data)
{
    mouseHiding.setValue(data.m_mouseHiding);
    mouseNavigation.setValue(data.m_mouseNavigation);
    scrollWheelZooming.setValue(data.m_scrollWheelZooming);
    constrainHoverTooltips.setValue(data.m_constrainHoverTooltips);
    camelCaseNavigation.setValue(data.m_camelCaseNavigation);
    keyboardTooltips.setValue(data.m_keyboardTooltips);
    smartSelectionChanging.setValue(data.m_smartSelectionChanging);
}

void BehaviorSettings::apply()
{
    AspectContainer::apply();
    AspectContainer::writeSettings();
}

BehaviorSettingsData BehaviorSettings::data() const
{
    BehaviorSettingsData d;
    d.m_mouseHiding = mouseHiding();
    d.m_mouseNavigation = mouseNavigation();
    d.m_scrollWheelZooming = scrollWheelZooming();
    d.m_constrainHoverTooltips = constrainHoverTooltips();
    d.m_camelCaseNavigation = camelCaseNavigation();
    d.m_keyboardTooltips = keyboardTooltips();
    d.m_smartSelectionChanging = smartSelectionChanging();
    return d;
}

BehaviorSettings &globalBehaviorSettings()
{
    static BehaviorSettings theGlobalBehaviorSettings;
    return theGlobalBehaviorSettings;
}

// BehaviorSettingsPage

class BehaviorPage final : public AspectContainer
{
public:
    BehaviorPage()
    {
        registerAspect(&globalTabSettings());
        registerAspect(&globalTypingSettings());
        registerAspect(&globalStorageSettings());
        registerAspect(&globalExtraEncodingSettings());
        registerAspect(&globalBehaviorSettings());

        setLayouter([] {
            using namespace Layouting;
            return Column {
                &globalTabSettings(),
                &globalTypingSettings(),
                &globalStorageSettings(),
                &globalExtraEncodingSettings(),
                &globalBehaviorSettings(),
                st,
            };
        });
    }
};

class BehaviorSettingsPage final : public Core::IOptionsPage
{
public:
    BehaviorSettingsPage()
    {
        setId(Constants::TEXT_EDITOR_BEHAVIOR_SETTINGS);
        setDisplayName(Tr::tr("Behavior"));
        setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY);
        setSettingsProvider([] {
            static BehaviorPage thePage;
            return static_cast<AspectContainer *>(&thePage);
        });
    }
};

void Internal::setupBehaviorSettings()
{
    globalBehaviorSettings().readSettings();
    auto update = [] {
        const BehaviorSettingsData bs = globalBehaviorSettings().data();
        Core::MessageManager::setWheelZoomEnabled(bs.m_scrollWheelZooming);
        FancyLineEdit::setCamelCaseNavigationEnabled(bs.m_camelCaseNavigation);
    };
    QObject::connect(&globalBehaviorSettings(), &AspectContainer::changed,
                     &globalBehaviorSettings(), update);
    update();
    static BehaviorSettingsPage theBehaviorSettingsPage;
}

} // namespace TextEditor
