#ifndef QGUI_H
#define QGUI_H

#include <QComboBox>
#include <QHeaderView>
#include <QLabel>
#include <QListWidget>
#include <QSplitter>
#include <QStackedLayout>
#include <QTableWidget>
#include <QTextEdit>

#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 QWidget *parentWgt(QObject *obj) {
    while(obj && ! obj->isWidgetType()) obj = obj->parent();
    return (QWidget*) obj;
}
inline QWidget *parentWin(QObject *obj) {
    while(obj) {
        if(obj->isWidgetType()) return ((QWidget*) obj)->window();
        obj = obj->parent();
    }
    return (QWidget*) obj;
}

inline int setCurrentData(QComboBox *combo, const QVariant &data) {
    auto idx = combo->findData(data);
    if(idx>-1) combo->setCurrentIndex(idx);
    return idx;
}
inline void gFont(QWidget *wgt, int size, bool bold = false, bool italic = false) {
    auto ft = wgt->font();
    ft.setPixelSize(size);
    if(bold) ft.setBold(true);
    if(italic) ft.setItalic(true);
    wgt->setFont(ft);
}
inline void gFont(QWidget *wgt, const QString &family, int size = 0, bool bold = false, bool italic = false) {
    auto ft = wgt->font();
    ft.setFamily(family);
    if(size) ft.setPixelSize(size);
    if(bold) ft.setBold(true);
    if(italic) ft.setItalic(true);
    wgt->setFont(ft);
}
inline QFont qfont(const QString &family, int pixelSize, bool bold = false, bool italic = false) {
    QFont ft(family);
    ft.setPixelSize(pixelSize);
    if(bold) ft.setBold(true);
    if(italic) ft.setItalic(true);
    return ft;
}
inline void gAppendText(QTextEdit *wgt, const QString &text, const QColor &color) {
    auto c0 = wgt->textColor();
    wgt->setTextColor(color);
    wgt->append(text);
    wgt->setTextColor(c0);
}

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 *stack) : QBoxLayout(TopToBottom, new QWidget) {
        stack->addWidget(parentWidget());
        setContentsMargins(0,0,0,0);
    };
    inline VBox(QSplitter *splitter) : QBoxLayout(TopToBottom, new QWidget) {
        splitter->addWidget(parentWidget());
        setContentsMargins(0,0,0,0);
    };
    inline QLabel *addLabel(const QString &text) {
        auto lb = new QLabel(text);
        addWidget(lb);
        return lb;
    }
};
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 *stack) : QBoxLayout(LeftToRight, new QWidget) {
        stack->addWidget(parentWidget());
        setContentsMargins(0,0,0,0);
    };
    inline HBox(QSplitter *splitter) : QBoxLayout(LeftToRight, new QWidget) {
        splitter->addWidget(parentWidget());
        setContentsMargins(0,0,0,0);
    };
    inline QLabel *addLabel(const QString &text) {
        auto lb = new QLabel(text);
        addWidget(lb);
        return lb;
    }
};
class Grid : public QGridLayout {
public:
    using QGridLayout::QGridLayout;
    inline Grid(QBoxLayout *parent) {
        parent->addLayout(this);
    };
    inline Grid(QStackedLayout *stack) : QGridLayout(new QWidget) {
        stack->addWidget(parentWidget());
    };
    inline Grid(QSplitter *splitter) : QGridLayout(new QWidget) {
        splitter->addWidget(parentWidget());
    };
    inline QLabel *addLabel(const QString &text) {
        auto lb = new QLabel(text);
        addWidget(lb);
        return lb;
    }
};

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 {
    ColAttr(QString field, QString text, int width=0, QHeaderView::ResizeMode resizeMode = QHeaderView::Interactive) : field(field), text(text), width(width), resizeMode(resizeMode) {}
    ColAttr(QString field, QString text, QHeaderView::ResizeMode resizeMode) : field(field), text(text), resizeMode(resizeMode) {}
    QString field;
    QString text;
    int width{0};
    QHeaderView::ResizeMode resizeMode;
};
class Table : public QTableWidget {
    Q_OBJECT
public:
    using QTableWidget::QTableWidget;
    Table() {}
    Table(std::initializer_list<ColAttr> colAttrs, int rows = 0, QWidget *parent = 0);

    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, QHeaderView::ResizeMode mode = QHeaderView::Interactive) {
        auto header = horizontalHeader();
        header->setDefaultSectionSize(value);
        if(mode!=QHeaderView::Interactive) header->setSectionResizeMode(mode);
        return this;
    }
    inline auto setRowHeight(int value, QHeaderView::ResizeMode mode = QHeaderView::Interactive) {
        auto header = verticalHeader();
        header->setDefaultSectionSize(value);
        if(mode!=QHeaderView::Interactive) header->setSectionResizeMode(mode);
        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 setVHeaderText(int row, QString text) {
        auto item = verticalHeaderItem(row);
        if(item==0) setVerticalHeaderItem(row, item = new QTableWidgetItem());
        item->setText(text);
        return item;
    }

    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);
    }

    std::map<QString, int> mFieldMap;
public Q_SLOTS:
    inline void clearRows() {setRowCount(0);}
signals:
    void updGeos();
protected:
    void resizeEvent(QResizeEvent *event) override;
    void updateGeometries() override;
    void resizeSec();
    bool noStretch{true};
};

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