#include "layoutgadget.h"
using Xybrid::UI::LayoutGadget;

#include "ui/patchboard/nodeobject.h"

namespace Xybrid::UI {
    class LayoutSpacerGadget : public Gadget {
    public:
        LayoutSpacerGadget(QGraphicsItem* parent = nullptr) : Gadget(parent) { }
        ~LayoutSpacerGadget() override = default;

        QRectF boundingRect() const override;
    };
}
using Xybrid::UI::LayoutSpacerGadget;

QRectF LayoutSpacerGadget::boundingRect() const {
    auto l = static_cast<LayoutGadget*>(parentItem());
    auto w = l->spacing;
    return QRectF(QPointF(), QSizeF(w, w));
}

QPointF LayoutGadget::orient(const QPointF& o) const {
    if (!vertical) return o;
    return QPointF(o.y(), o.x());
}

QSizeF LayoutGadget::orient(const QSizeF& o) const {
    if (!vertical) return o;
    return o.transposed();
}

QRectF LayoutGadget::orient(const QRectF& o) const {
    if (!vertical) return o;
    return o.transposed();
}

LayoutGadget::LayoutGadget(QGraphicsItem* parent, bool vertical) : Gadget(parent), vertical(vertical) {
    setFlag(GraphicsItemFlag::ItemClipsChildrenToShape, false);
    setFlag(GraphicsItemFlag::ItemClipsToShape, false);
    if (vertical) { // different defaults for vertical layouts
        margin = 0;
        spacing = 3;
    }
}

LayoutGadget::LayoutGadget(NodeObject* parent, bool vertical) : LayoutGadget(parent->contents, vertical) {
    QObject::connect(parent, &NodeObject::finalized, this, [this, parent] {
        updateGeometry();
        parent->setGadgetSize();
    });
}

LayoutGadget* LayoutGadget::addSpacer() { new LayoutSpacerGadget(this); return this; }

void LayoutGadget::updateGeometry() {
    qreal cur = margin;
    auto ms = orient(minSize);
    qreal h = ms.height();
    for (auto c : childItems()) {
        auto g = static_cast<Gadget*>(c);
        g->updateGeometry();
        auto r = orient(g->layoutBoundingRect());
        h = std::max(h, r.height());
    }
    for (auto c : childItems()) {
        auto g = static_cast<Gadget*>(c);
        auto r = orient(g->layoutBoundingRect());
        g->centerOn(orient(QPointF(cur + r.width()/2, r.height()/2 + (h - r.height())*bias)));
        cur += r.width() + spacing;
    }
    cur += margin - spacing;
    size = orient(QSizeF(std::max(cur, ms.width()), h));
}

QRectF LayoutGadget::boundingRect() const { return { QPointF(), size }; }
