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

#pragma once

#include "utils_global.h"

#include "fancylineedit.h"
#include "utility.h"

QT_BEGIN_NAMESPACE
class QAbstractButton;
class QLineEdit;
QT_END_NAMESPACE

namespace Utils {
Q_NAMESPACE_EXPORT(QTCREATOR_UTILS_EXPORT)

class CommandLine;
class Environment;
class FilePath;
class FilePaths;
class MacroExpander;
class PathChooserPrivate;

enum class PathChooserKind {
    ExistingDirectory,
    Directory, // A directory, doesn't need to exist
    File, // An existing file
    SaveFile, // A file that does not need to exist
    ExistingCommand, // A command that must exist at the time of selection
    Command, // A command that may or may not exist at the time of selection (e.g. result of a build)
    Any
};
Q_ENUM_NS(PathChooserKind)

class QTCREATOR_UTILS_EXPORT PathChooser : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QString path READ path WRITE setPath NOTIFY textChanged)

public:
    static QString browseButtonLabel();

    explicit PathChooser(QWidget *parent = nullptr);
    ~PathChooser() override;

    // Default is <ExistingDirectory>
    void setExpectedKind(PathChooserKind expected);
    PathChooserKind expectedKind() const;

    void setPromptDialogTitle(const QString &title);
    QString promptDialogTitle() const;

    void setPromptDialogFilter(const QString &filter);
    QString promptDialogFilter() const;

    void setInitialBrowsePathBackup(const FilePath &path);

    bool isValid() const;
    QString errorMessage() const;

    FilePath filePath() const; // Close to what's in the line edit. Expands macros.
    FilePath absoluteFilePath() const; // Relative paths resolved wrt the specified base dir.

    FilePath unexpandedFilePath() const; // The raw unexpanded input as FilePath.

    static FilePath expandPath(
        const FilePath &path,
        const MacroExpander *macroExpander,
        const FilePath &baseDirectory,
        const Environment &env,
        PathChooserKind expectedKind = PathChooserKind::Any);

    FilePath baseDirectory() const;
    void setBaseDirectory(const Lazy<FilePath> &base);

    void setEnvironment(const Environment &env);

    /** Returns the suggested label title when used in a form layout. */
    static QString label();

    FancyLineEdit::AsyncValidationFunction defaultValidationFunction() const;
    void setValidationFunction(const FancyLineEdit::ValidationFunction &fn);

    /** Return the home directory, which needs some fixing under Windows. */
    static FilePath homePath();

    void addButton(const QString &text, QObject *context, const std::function<void()> &callback);
    void insertButton(int index, QAbstractButton *button);
    void insertButton(int index, const QString &text, QObject *context, const std::function<void()> &callback);
    QAbstractButton *buttonAtIndex(int index) const;

    FancyLineEdit *lineEdit() const;

    // For PathChoosers of 'Command' type, this property specifies the arguments
    // required to obtain the tool version (commonly, '--version'). Setting them
    // causes the version to be displayed as a tooltip.
    QStringList commandVersionArguments() const;
    void setCommandVersionArguments(const QStringList &arguments);

    // Install a tooltip on lineedits used for binaries showing the version.
    static void installLineEditVersionToolTip(QLineEdit *le, const QStringList &arguments);

    // Enable a history completer with a history of entries.
    void setHistoryCompleter(const Key &historyKey, bool restoreLastItemFromHistory = false);

    // Sets a macro expander that is used when producing path and fileName.
    // By default, the global expander is used.
    // nullptr can be passed to disable macro expansion.
    void setMacroExpander(const MacroExpander *macroExpander);

    bool isReadOnly() const;
    void setReadOnly(bool b);

    void triggerChanged();

    // global handler for adding context menus to ALL pathchooser
    // used by the coreplugin to add "Open in Terminal" and "Open in Explorer" context menu actions
    using AboutToShowContextMenuHandler = std::function<void (PathChooser *, QMenu *)>;
    static void setAboutToShowContextMenuHandler(AboutToShowContextMenuHandler handler);

    void setOpenTerminalHandler(const std::function<void()> &openTerminal);
    std::function<void()> openTerminalHandler() const;

    // this sets the placeHolderText to defaultValue and enables to use this as
    // input value during validation if the real value is empty
    // setting an empty QString will disable this and clear the placeHolderText
    void setDefaultValue(const FilePath &defaultValue);
    void setPlaceholderText(const QString &placeholderText);
    void setToolTip(const QString &toolTip);

    void setAllowPathFromDevice(bool allow);
    bool allowPathFromDevice() const;

    void setValueAlternatives(const FilePaths &candidates);

    void setPath(const QString &);
    void setFilePath(const FilePath &);

signals:
    void validChanged(bool validState);
    void rawPathChanged();
    void textChanged(const QString &text); // Triggered from the line edit's textChanged()
    void editingFinished(); // Triggered from the line edit's editingFinished()
    void beforeBrowsing();
    void browsingFinished();
    void returnPressed();

private:
    QString path() const; // used by the Q_PROPERTY for wizard field registration
    // Returns overridden title or the one from <title>
    QString makeDialogTitle(const QString &title);
    void slotBrowse(bool remote);
    void contextMenuRequested(const QPoint &pos);

    PathChooserPrivate *d = nullptr;
};

} // namespace Utils
