/*
 * scriptdialog.h
 * Copyright 2022, dogboydog
 * Copyright 2022, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
 *
 * This file is part of Tiled.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <QAbstractButton>
#include <QBoxLayout>
#include <QButtonGroup>
#include <QColor>
#include <QDialog>
#include <QLabel>

class QGridLayout;
class QHBoxLayout;

class QJSEngine;

namespace Tiled {

class ScriptImage;

/**
 * A widget which allows the user to display a ScriptImage
 */
class ScriptImageWidget : public QLabel
{
    Q_OBJECT

    Q_PROPERTY(Tiled::ScriptImage *image READ image WRITE setImage)

public:
    ScriptImageWidget(Tiled::ScriptImage *image, QWidget *parent);

    ScriptImage *image() const;
    void setImage(ScriptImage *image);
};


class ScriptButtonGroup : public QButtonGroup
{
    Q_OBJECT
    Q_PROPERTY(QList<QAbstractButton *> buttons READ buttons CONSTANT)
    Q_PROPERTY(QAbstractButton * checkedButton READ checkedButton CONSTANT)
    Q_PROPERTY(int checkedIndex READ checkedIndex CONSTANT)

public:
    ScriptButtonGroup(QWidget *parent, QHBoxLayout *layout)
        : QButtonGroup(parent)
        , mLayout(layout)
    {}

    Q_INVOKABLE void addItems(const QStringList &values, const QStringList &toolTips);
    Q_INVOKABLE QAbstractButton *addItem(const QString &value, const QString &toolTip = QString());

    int checkedIndex() const { return QButtonGroup::checkedId(); }

private:
    QHBoxLayout *mLayout;
};


class ScriptDialog : public QDialog
{
    Q_OBJECT

    Q_PROPERTY(Tiled::ScriptDialog::NewRowMode newRowMode READ newRowMode WRITE setNewRowMode)

public:
    enum NewRowMode {
        SameWidgetRows = 0,
        ManualRows = 1,
        SingleWidgetRows = 2
    };
    Q_ENUM(NewRowMode)

    // Duplicate from QDialog, because the enum on QDialog isn't marked Q_ENUM
    enum DialogCode { Rejected, Accepted };
    Q_ENUM(DialogCode)

    Q_INVOKABLE ScriptDialog(const QString &title = QString());
    ~ScriptDialog() override;

    Q_INVOKABLE QWidget *addHeading(const QString &text, bool fillRow = false);
    Q_INVOKABLE QWidget *addLabel(const QString &text, const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addSeparator(const QString &labelText = QString());
    Q_INVOKABLE QWidget *addTextInput(const QString &labelText = QString(), const QString &defaultValue = QString(), const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addTextEdit(const QString &labelText = QString(), const QString &defaultValue = QString(), const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addNumberInput(const QString &labelText = QString(), double defaultValue = 0.0, const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addSlider(const QString &labelText = QString(), int defaultValue = 0, const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addComboBox(const QString &labelText, const QStringList &values, int defaultIndex = 0, const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addCheckBox(const QString &text = QString(), bool defaultValue = false, const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addButton(const QString &text = QString(), const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addFilePicker(const QString &labelText = QString(), const QString &defaultValue = QString(), const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addColorButton(const QString &labelText = QString(), const QColor &defaultValue = QColor(), const QString &toolTip = QString());
    Q_INVOKABLE QWidget *addImage(const QString &labelText, Tiled::ScriptImage *image, const QString &toolTip = QString());
    Q_INVOKABLE ScriptButtonGroup *addRadioButtonGroup(const QString &labelText,
                                                       const QStringList &values,
                                                       const QString &toolTip = QString(),
                                                       const QStringList &buttonToolTips = QStringList());
    Q_INVOKABLE void clear();
    Q_INVOKABLE void addNewRow();

    NewRowMode newRowMode() const;
    void setNewRowMode(NewRowMode mode);

    int exec() override;

    static void deleteAllDialogs();

private:
    QLabel *newLabel(const QString &labelText);
    void initializeLayout();
    void determineWidgetGrouping(QWidget *widget);
    QWidget *addDialogWidget(QWidget *widget,
                             const QString &label = QString(),
                             const QString &labelToolTip = QString(),
                             const QString &widgetToolTip = QString());

    int m_rowIndex = 0;
    int m_widgetsInRow = 0;
    QGridLayout *m_gridLayout;
    QHBoxLayout *m_rowLayout;
    const QMetaObject *m_lastWidgetType;
    NewRowMode m_newRowMode = SameWidgetRows;

    static QSet<ScriptDialog*> sDialogInstances;
};


void registerDialog(QJSEngine *jsEngine);

} // namespace Tiled
