/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <QPainter>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QResizeEvent>

#include "MvQOdbTableView.h"
#include "MvQOdbMetaData.h"
#include "MvQTheme.h"

MvQOdbTableView::MvQOdbTableView(QWidget* parent) :
    QGraphicsView(parent)
{
}

void MvQOdbTableView::init(MvQOdbMetaData* odb, QString table)
{
    odb_ = odb;
    selectedTable_ = table;

    // Number of rows and cols in graph
    int nx, ny;
    odb_->getTreePosRange(nx, ny);
    nx += 1;
    // ny+=1;

    // Compute the area occupied by the graph
    int w = 2 * tableOffsetX_ + nx * tableWidth_ + (nx - 1) * tableGapX_;
    int h = 2 * tableOffsetY_ + ny * tableHeight_ + (ny - 1) * tableGapY_;

    graphWidth_ = w;
    graphHeight_ = h;

    int dw, dh, pw, ph;
    // adjustPixmapSizeToView(width(),height(),dw,dh);
    adjustPixmapSizeToView(w, h, dw, dh);
    pw = w + dw;
    ph = h + dh;

    // pw=width()+dw;
    // ph=height()+dh;

    // Create the pixmap
    tablePixmap_ = new QPixmap(pw, ph);

    // Scene rect
    setSceneRect(0, 0, pw, ph);

    // Create a scene for the table graph
    auto* scene = new OdbTableScene;

    // Add scene to the graphics view
    setScene(scene);

    // Mouse press event in scene goes to
    connect(scene, SIGNAL(mousePressed(int, int)),
            this, SLOT(mousePressedInTableGraph(int, int)));

    setCacheMode(QGraphicsView::CacheBackground);
    // setBackgroundBrush(*tablePixmap_);

    renderTableGraph();

    emit tableSelection(selectedTable_);
}


void MvQOdbTableView::renderTableGraph()
{
    // QPixmap *pixmap = new QPixmap(600,400);
    QPainter painter(tablePixmap_);

    painter.setRenderHint(QPainter::Antialiasing, false);

    // QLinearGradient grad(0,0,100,100);

    QLinearGradient grad(0, 0, tablePixmap_->width(), tablePixmap_->height());
    grad.setColorAt(0, QColor::fromRgb(255, 242, 222));
    grad.setColorAt(1, QColor::fromRgb(255, 255, 255));


    // Define clear color and clear the display
    painter.fillRect(0, 0, tablePixmap_->width(), tablePixmap_->height(),
                     QBrush(grad));
    // QBrush(Qt::white, Qt::SolidPattern));

    // Render net
    int xp, yp;
    painter.setPen(QPen(QColor(213, 209, 217), 0.5, Qt::SolidLine, Qt::RoundCap));

    yp = tablePixmap_->height();
    while (yp > 0) {
        painter.drawLine(0, yp, tablePixmap_->width(), yp);
        yp -= 15;
    }

    xp = 0;
    while (xp < tablePixmap_->width()) {
        painter.drawLine(xp, 0, xp, tablePixmap_->height());
        xp += 15;
    }

    painter.setPen(QPen(Qt::black, 0.5, Qt::SolidLine, Qt::RoundCap));

    // Draw the graph

    QMapIterator<QString, MvQOdbTable*> it(odb_->tables());
    while (it.hasNext()) {
        it.next();
        getTablePos(it.value()->treePosX(), it.value()->treePosY(), xp, yp);

        foreach (QString tblName, it.value()->linksTo()) {
            int xp1, yp1;
            MvQOdbTable* tbl = odb_->tables()[tblName];
            getTablePos(tbl->treePosX(), tbl->treePosY(), xp1, yp1);

            painter.drawLine(xp, yp, (xp + xp1) / 2, yp);
            painter.drawLine((xp + xp1) / 2, yp, (xp + xp1) / 2, yp1);
            painter.drawLine((xp + xp1) / 2, yp1, xp1, yp1);
        }
    }


    painter.setFont(QFont("Helvetica [Cronyx]", 8));
    painter.setRenderHint(QPainter::TextAntialiasing, true);
    // painter.setFont(QFont("Sans Serif", 7));

    it.toFront();
    while (it.hasNext()) {
        it.next();
        getTablePos(it.value()->treePosX(), it.value()->treePosY(), xp, yp);

        if (it.value()->name() == selectedTable_) {
            QLinearGradient gradient(xp, yp - tableHeight_ / 2.,
                                     xp, yp + tableHeight_ / 2);
            gradient.setColorAt(0, QColor::fromRgb(227, 59, 101));
            gradient.setColorAt(1, QColor::fromRgb(229, 117, 128));

            painter.fillRect(xp - tableWidth_ / 2., yp - tableHeight_ / 2.,
                             tableWidth_, tableHeight_, QBrush(gradient));
            // QBrush(QColor(255,64,105), Qt::SolidPattern));
        }
        else {
            QLinearGradient gradient(xp, yp - tableHeight_ / 2.,
                                     xp, yp + tableHeight_ / 2);
            gradient.setColorAt(0, QColor("#6ea1f1"));
            gradient.setColorAt(1, QColor("#567dbc"));

            painter.fillRect(xp - tableWidth_ / 2., yp - tableHeight_ / 2.,
                             tableWidth_, tableHeight_, QBrush(gradient));
            // QBrush(QColor(119,215,196), Qt::SolidPattern));
        }

        painter.drawRect(xp - tableWidth_ / 2., yp - tableHeight_ / 2.,
                         tableWidth_, tableHeight_);

        if (it.value()->name() == selectedTable_) {
            // painter.setPen(QPen(Qt::white, 0.5, Qt::SolidLine, Qt::RoundCap));
        }


        painter.setPen(QPen(Qt::white, 0.5, Qt::SolidLine, Qt::RoundCap));
        painter.drawText(QRectF(xp - tableWidth_ / 2., yp - tableHeight_ / 2,
                                tableWidth_, tableHeight_),
                         Qt::AlignCenter,
                         it.value()->name());
        painter.setPen(QPen(Qt::black, 0.5, Qt::SolidLine, Qt::RoundCap));


        if (it.value()->name() == selectedTable_) {
            // painter.setPen(QPen(Qt::black, 0.5, Qt::SolidLine, Qt::RoundCap));
        }
    }

    /*graphicsView_table->setCacheMode(QGraphicsView::CacheBackground);
    graphicsView_table->resetCachedContent();*/

    setBackgroundBrush(*tablePixmap_);
}


void MvQOdbTableView::getTablePos(int row, int col, int& x, int& y)
{
    x = tableOffsetX_ + row * (tableWidth_ + tableGapX_) + tableWidth_ / 2.;
    y = tableOffsetY_ + col * (tableHeight_ + tableGapY_ / 2.);
}


bool MvQOdbTableView::setSelectedTable(int x, int y)
{
    int xp, yp;
    QMapIterator<QString, MvQOdbTable*> it(odb_->tables());
    while (it.hasNext()) {
        it.next();
        getTablePos(it.value()->treePosX(), it.value()->treePosY(), xp, yp);

        if (x > xp - tableWidth_ / 2. && x < xp + tableWidth_ / 2. &&
            y < yp + tableHeight_ / 2. && y > yp - tableHeight_ / 2.) {
            if (selectedTable_ != it.key()) {
                selectedTable_ = it.key();
                return true;
            }
        }
    }

    return false;
}
void MvQOdbTableView::setSelectedTable(QString table)
{
    if (selectedTable_ != table) {
        selectedTable_ = table;
        renderTableGraph();
        centreTableGraph();
    }
}

void MvQOdbTableView::mousePressedInTableGraph(int x, int y)
{
    if (setSelectedTable(x, y)) {
        renderTableGraph();
        emit tableSelection(selectedTable_);
    }
}

void MvQOdbTableView::centreTableGraph()
{
    int x, y;
    MvQOdbTable* t = odb_->tables()[selectedTable_];
    getTablePos(t->treePosX(), t->treePosY(), x, y);
    centerOn(x, y);
}

void MvQOdbTableView::resizeEvent(QResizeEvent* event)
{
    int pw = tablePixmap_->width();
    int ph = tablePixmap_->height();

    int dw;
    int dh;
    adjustPixmapSizeToView(pw, ph, dw, dh);

    if (dw != 0 || dh != 0) {
        delete tablePixmap_;
        tablePixmap_ = new QPixmap(pw + dw, ph + dh);

        // setBackgroundBrush(*tablePixmap_);

        setSceneRect(0, 0, pw + dw, ph + dh);

        renderTableGraph();
    }

    QGraphicsView::resizeEvent(event);
}

void MvQOdbTableView::adjustPixmapSizeToView(int pw, int ph, int& dw, int& dh)
{
    dw = 0;
    dh = 0;

    int w = width();
    int h = height();

    if (pw < w) {
        dw = (w - pw < 100) ? 100 : (w - pw);
    }
    else {
        if (pw > graphWidth_ && w < graphWidth_) {
            dw = graphWidth_ - pw;
        }
    }

    if (ph < h) {
        dh = (h - ph < 100) ? 100 : (h - ph);
    }
    else {
        if (ph > graphHeight_ && h < graphHeight_) {
            dh = graphHeight_ - ph;
        }
    }
}


OdbTableScene::OdbTableScene(QGraphicsScene* parent) :
    QGraphicsScene(parent)
{
}

void OdbTableScene::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
    QPointF p = event->buttonDownScenePos(Qt::LeftButton);

    emit mousePressed(p.rx(), p.ry());
}
