#ifndef QGUI_H
#define QGUI_H

#include <QComboBox>
#include <QStackedLayout>
#include <QTableWidget>
#include <QHeaderView>

extern const int AlignRight;

inline int setCurrentData(QComboBox *combo, const QVariant &data) {
    auto idx = combo->findData(data);
    if(idx>-1) combo->setCurrentIndex(idx);
    return idx;
}

class VBox : public QBoxLayout {
public:
    inline VBox(QWidget *parent=nullptr) : QBoxLayout(TopToBottom, parent) {}
    inline VBox(QBoxLayout *parent) : QBoxLayout(TopToBottom) {
        parent->addLayout(this);
    };
    inline VBox(QStackedLayout *parent) : QBoxLayout(TopToBottom) {
        setContentsMargins(0,0,0,0);
        auto wgt = new QWidget;
        wgt->setLayout(this);
        parent->addWidget(wgt);
    };
};
class HBox : public QBoxLayout {
public:
    inline HBox(QWidget *parent=nullptr) : QBoxLayout(LeftToRight, parent) {}
    inline HBox(QBoxLayout *parent) : QBoxLayout(LeftToRight) {
        parent->addLayout(this);
    };
    inline HBox(QStackedLayout *parent) : QBoxLayout(LeftToRight) {
        setContentsMargins(0,0,0,0);
        auto wgt = new QWidget;
        wgt->setLayout(this);
        parent->addWidget(wgt);
    };
};
class Grid : public QGridLayout {
public:
    inline Grid(QWidget *parent=0) : QGridLayout(parent) {}
    inline Grid(QBoxLayout *parent) {
        parent->addLayout(this);
    };
    inline Grid(QStackedLayout *parent) {
        auto wgt = new QWidget;
        wgt->setLayout(this);
        parent->addWidget(wgt);
    };
};

class NumTable : public QTableWidget {
    Q_OBJECT
public:
    explicit NumTable(QWidget *parent = 0) : QTableWidget{parent} {}
    NumTable(int rows, int columns, QWidget *parent = 0) : QTableWidget{rows, columns, parent} {}

    inline auto setNoEdit() {
        setEditTriggers(QAbstractItemView::NoEditTriggers);
        return this;
    }
    inline auto setColWidth(int value) {
        horizontalHeader()->setDefaultSectionSize(value);
        return this;
    }
    inline auto setRowHeight(int value) {
        verticalHeader()->setDefaultSectionSize(value);
        return this;
    }

    inline auto setHeaderText(int column, QString text) {
        auto item = horizontalHeaderItem(column);
        if(item==0) setHorizontalHeaderItem(column, item = new QTableWidgetItem());
        item->setText(text);
        return item;
    }

    inline auto itemValid(int row, int column) {
        auto item = QTableWidget::item(row, column);
        if(item==0) setItem(row, column, item = new QTableWidgetItem);
        return item;
    }
    inline auto text(int row, int column) {
        auto item = QTableWidget::item(row, column);
        if(item==0) return QString();
        return item->text();
    }
    inline auto setText(int row, int column, const QString &text) {
        auto item = QTableWidget::item(row, column);
        if(item) item->setText(text);
        else setItem(row, column, item = new QTableWidgetItem(text));
        return item;
    }

    inline auto data(int row, int col) {
        auto item = QTableWidget::item(row, col);
        if(item==0) return QVariant();
        return item->data(Qt::UserRole);
    }
    inline auto setData(int row, int col, const QVariant &value) {
        auto item = QTableWidget::item(row, col);
        if(item==0) setItem(row, col, item = new QTableWidgetItem);
        item->setData(Qt::UserRole, value);
        return item;
    }
};

struct ColAttr {
    QString field;
    QString text;
    int width{0};
    int resizeMode{-1};
};
class Table : public NumTable {
    Q_OBJECT
public:
    explicit Table(QWidget *parent = nullptr) : NumTable{parent} {}
    Table(std::initializer_list<ColAttr> colAttrs, int rows = 0, QWidget *parent = nullptr);

    inline auto setDefs() {
        setSelectionBehavior(QTableWidget::SelectRows);
        setEditTriggers(QAbstractItemView::NoEditTriggers);
        setAlternatingRowColors(true);
        return this;
    }
    inline auto setColStretch() {
        horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
        return this;
    }
    inline auto setRowStretch() {
        verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
        return this;
    }
    inline auto setColFit() {
        horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
        return this;
    }
    inline auto setRowFit() {
        verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
        return this;
    }
    inline auto setColWidth(int value) {
        horizontalHeader()->setDefaultSectionSize(value);
        return this;
    }
    inline auto setRowHeight(int value) {
        verticalHeader()->setDefaultSectionSize(value);
        return this;
    }

    inline auto setHeaderText(QString column, QString text) {
        auto col = mFieldMap[column];
        auto item = horizontalHeaderItem(col);
        if(item==0) setHorizontalHeaderItem(col, item = new QTableWidgetItem());
        item->setText(text);
        return item;
    }

    inline auto appendRow() {
        auto value = rowCount();
        setRowCount(value + 1);
        return value;
    }

    inline auto item(int row, QString column) {
        auto col = mFieldMap[column];
        return QTableWidget::item(row, col);
    }
    inline void setItem(int row, QString column, QTableWidgetItem *item) {
        auto col = mFieldMap[column];
        QTableWidget::setItem(row, col, item);
    }
    inline auto text(int row, QString column) {
        auto col = mFieldMap[column];
        auto item = QTableWidget::item(row, col);
        if(item==0) return QString();
        return item->text();
    }
    inline auto setText(int row, QString column, const QString &text) {
        auto col = mFieldMap[column];
        auto item = QTableWidget::item(row, col);
        if(item) item->setText(text);
        else QTableWidget::setItem(row, col, item = new QTableWidgetItem(text));
        return item;
    }

    inline auto data(int row, QString column) {
        auto col = mFieldMap[column];
        auto item = QTableWidget::item(row, col);
        if(item==0) return QVariant();
        return item->data(Qt::UserRole);
    }
    inline auto setData(int row, QString column, const QVariant &value) {
        auto col = mFieldMap[column];
        auto item = QTableWidget::item(row, col);
        if(item==0) QTableWidget::setItem(row, col, item = new QTableWidgetItem);
        item->setData(Qt::UserRole, value);
        return item;
    }

    inline auto cellWidget(int row, QString column) {
        auto col = mFieldMap[column];
        return QTableWidget::cellWidget(row, col);
    }
    inline void setCellWidget(int row, QString column, QWidget *widget) {
        auto col = mFieldMap[column];
        QTableWidget::setCellWidget(row, col, widget);
    }

    QMap<QString,int> mFieldMap;

public Q_SLOTS:
    inline void clearRows() {setRowCount(0);}

protected:
    int sizeHintForColumn(int column) const override;
};

class ResizeEmitedWgt : public QWidget {
    Q_OBJECT
public:
    explicit ResizeEmitedWgt(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) : QWidget{parent, f} {}
protected:
    void resizeEvent(QResizeEvent *) override {emit resized();}
signals:
    void resized();
};


template<class T>
class Wrp {
public:
    T *obj;
    Wrp(T *obj = nullptr){
        this->obj = obj;
    };
    inline Wrp& operator()(T *obj){
        this->obj = obj;
        return *this;
    }
    inline Wrp& operator()(T *obj, QLayout *layout){
        this->obj = obj;
        layout->addWidget(obj);
        return *this;
    }
    inline Wrp& addTo(QLayout *layout){
        layout->addWidget(obj);
        return *this;
    }
    inline Wrp& margin(int a){
        obj->setMargin(a);
        return *this;
    }
    inline Wrp& font(const QFont &font){
        obj->setFont(font);
        return *this;
    }
    inline Wrp& font(int size){
        QFont font = obj->font();
        font.setPointSize(size);
        obj->setFont(font);
        return *this;
    }

    inline Wrp& width(int w){
        obj->setFixedWidth(w);
        return *this;
    }
    inline Wrp& height(int h){
        obj->setFixedHeight(h);
        return *this;
    }
    inline Wrp& padding(int wAdd, int hAdd, int minW = 32, int minH = 16){
        wAdd+=8;
        hAdd+=8;
        QSize size = obj->fontMetrics().size(Qt::TextShowMnemonic, obj->text());
        int &rwidth = size.rwidth();
        rwidth += wAdd;
        if(rwidth < minW) rwidth = minW;
        int &rheight = size.rheight();
        rheight += hAdd;
        if(rheight < minH) rheight = minH;
        obj->setFixedSize(size);
        return *this;
    }

    inline Wrp& alignC(){
        obj->setAlignment(Qt::AlignCenter);
        return *this;
    }
    inline Wrp& alignR(){
        obj->setAlignment(Qt::AlignRight);
        return *this;
    }
};

#endif
