#ifndef QGUI_H
#define QGUI_H

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

#define MainMust \
#if(QT_VERSION_MAJOR > 5) \
    QImageReader::setAllocationLimit(0);\
#else\
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\
    QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);\
    QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);\
#endif


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:
    using QGridLayout::QGridLayout;
    inline Grid(QBoxLayout *parent) {
        parent->addLayout(this);
    };
    inline Grid(QStackedLayout *parent) {
        auto wgt = new QWidget;
        wgt->setLayout(this);
        parent->addWidget(wgt);
    };
};

inline QFont qfont(const QString &family, int pixelSize, bool bold = false, bool italic = false) {
    QFont font(family);
    font.setPixelSize(pixelSize);
    if(bold) font.setBold(true);
    if(italic) font.setItalic(true);
    return font;
}

class ListWgt : public QListWidget {
public:
    using QListWidget::QListWidget;

    using QListWidget::addItem;
    inline auto addItem(const QString &text, const QVariant &value) {
        auto item = new QListWidgetItem(text);
        item->setData(Qt::UserRole, value);
        insertItem(count(), item);
        return this;
    }
};

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

    inline auto setNoEdit() {
        setEditTriggers(QAbstractItemView::NoEditTriggers);
        return this;
    }
    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(int col, QString text) {
        auto item = horizontalHeaderItem(col);
        if(item==0) setHorizontalHeaderItem(col, item = new QTableWidgetItem());
        item->setText(text);
        return item;
    }
    inline auto setHeaderText(QString column, QString text) {
        auto col = mFieldMap[column];
        return setHeaderText(col, text);
    }

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

    using QTableWidget::item;
    inline auto item(int row, QString column) {
        auto col = mFieldMap[column];
        return item(row, col);
    }
    inline auto itemValid(int row, int col) {
        auto anitem = item(row, col);
        if(anitem==0) setItem(row, col, anitem = new QTableWidgetItem);
        return anitem;
    }
    inline auto itemValid(int row, QString column) {
        auto col = mFieldMap[column];
        return itemValid(row, col);
    }
    using QTableWidget::setItem;
    inline void setItem(int row, QString column, QTableWidgetItem *item) {
        auto col = mFieldMap[column];
        setItem(row, col, item);
    }

    inline auto text(int row, int col) {
        auto itm = item(row, col);
        if(itm==0) return QString();
        return itm->text();
    }
    inline auto text(int row, QString column) {
        auto col = mFieldMap[column];
        return text(row, col);
    }

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

    inline auto data(int row, int col) {
        auto itm = item(row, col);
        if(itm==0) return QVariant();
        return itm->data(Qt::UserRole);
    }
    inline auto data(int row, QString column) {
        auto col = mFieldMap[column];
        return data(row, col);
    }

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

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

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

protected:
    int sizeHintForColumn(int column) const override;

    QMap<QString,int> mFieldMap;
};

class ResizeEmitedWgt : public QWidget {
    Q_OBJECT
public:
    using QWidget::QWidget;
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){
        auto font = obj->font();
        font.setPixelSize(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
