/**
 * @file PlotGrid.cpp
 */

#include "PlotGrid.h"
#include "PlotWidget.h"
#include "Hub.h"

#include <QVBoxLayout>
#include <QSplitter>
#include <QDateTime>

namespace shq {

static double nowSec() {
    return QDateTime::currentMSecsSinceEpoch() / 1000.0;
}

PlotGrid::PlotGrid(Hub* hub, GlobalView* gv, QWidget* parent)
    : QWidget(parent), hub_(hub), gv_(gv) {
    /* Persistent pool: one PlotWidget per slot, fixed plotIdx (== zoom cache
     * index). Plots beyond the current layout are simply not mounted. */
    pool_.reserve(kMaxPlotSlots);
    for (int i = 0; i < kMaxPlotSlots; i++) {
        auto* p = new PlotWidget(hub_, gv_, i, this);
        connect(hub_, &Hub::zoomReceived,        p, &PlotWidget::onZoomReceived);
        connect(hub_, &Hub::historyZoomReceived, p, &PlotWidget::onHistoryZoomReceived);
        connect(hub_, &Hub::captureReceived,     p, &PlotWidget::onCaptureReceived);
        p->setParent(nullptr);
        p->hide();
        pool_.push_back(p);
    }

    auto* lay = new QVBoxLayout(this);
    lay->setContentsMargins(0, 0, 0, 0);
    rebuild();
}

void PlotGrid::setLayout(PlotLayout l) {
    if (l == layout_) { return; }
    layout_ = l;
    rebuild();
}

void PlotGrid::rebuild() {
    /* Detach every pooled plot from any previous splitter. */
    for (auto* p : pool_) { p->setParent(this); p->hide(); }

    /* Drop the old root splitter (if any). */
    QLayout* lay = this->QWidget::layout();
    QLayoutItem* item;
    while ((item = lay->takeAt(0)) != nullptr) {
        if (QWidget* w = item->widget()) {
            if (qobject_cast<QSplitter*>(w)) { w->deleteLater(); }
        }
        delete item;
    }

    int cols, rows;
    layoutDims(layout_, cols, rows);

    auto* outer = new QSplitter(Qt::Vertical, this);
    outer->setChildrenCollapsible(false);
    outer->setHandleWidth(5);

    plots_.clear();
    for (int r = 0; r < rows; r++) {
        QSplitter* rowSplit = outer;
        if (cols > 1) {
            rowSplit = new QSplitter(Qt::Horizontal, outer);
            rowSplit->setChildrenCollapsible(false);
            rowSplit->setHandleWidth(5);
        }
        for (int c = 0; c < cols; c++) {
            int idx = r * cols + c;
            PlotWidget* p = pool_[idx];
            p->setParent(rowSplit);
            p->show();
            if (cols > 1) { rowSplit->addWidget(p); }
            else          { outer->addWidget(p); }
            plots_.push_back(p);
        }
        if (cols > 1) { outer->addWidget(rowSplit); }
    }

    lay->addWidget(outer);
    onModelChanged();
}

void PlotGrid::onModelChanged() { for (auto* p : plots_) { p->onModelChanged(); } }
void PlotGrid::onPauseChanged() { for (auto* p : plots_) { p->onPauseChanged(); } }
void PlotGrid::tick()           { for (auto* p : plots_) { p->tick(); } }

void PlotGrid::goLive() {
    for (auto* p : plots_) { p->setLive(true); }
}

void PlotGrid::setAllStoredX(double t0, double t1) {
    if (t1 <= t0) { return; }
    for (auto* p : plots_) { p->setLive(false); p->setStoredX(t0, t1); }
}

bool PlotGrid::anyNonLive() const {
    for (auto* p : plots_) { if (!p->isLive()) { return true; } }
    return false;
}

bool PlotGrid::currentRange(double& t0, double& t1) const {
    for (auto* p : plots_) {
        if (!p->isLive()) { t0 = p->xMin(); t1 = p->xMax(); return true; }
    }
    return false;
}

void PlotGrid::panAll(double frac) {
    const double wallNow = nowSec();
    for (auto* p : plots_) {
        if (p->isLive()) { continue; }
        double span = p->xMax() - p->xMin();
        if (span <= 0.0) { continue; }
        double d = span * frac;
        double mn = p->xMin() + d, mx = p->xMax() + d;
        if (mx > wallNow) { mx = wallNow; mn = mx - span; }
        p->setStoredX(mn, mx);
    }
}

void PlotGrid::jumpAllAgo(double secAgo) {
    const double wallNow = nowSec();
    for (auto* p : plots_) {
        double span = p->xMax() - p->xMin();
        if (span <= 0.0) { span = gv_->windowSec; }
        p->setLive(false);
        p->setStoredX(wallNow - secAgo - span, wallNow - secAgo);
    }
}

} /* namespace shq */
