#include "graphview.h"
#include "tablemodel.h"
#include <QtGui>

//
// Public Functions
//
GraphView::GraphView(QWidget *parent)
    : QWidget(parent)
{
    shouldGroup = false;
}

QSize GraphView::sizeHint() const
{
    return QSize(500, 300);
}

void GraphView::setModel(TableModel *m)
{
    // Update graph values.
    contents = m->getContents();

    // Create a map with a color for each group.
    lineTitles = m->getColumnTitles();
    QStringList groups = lineTitles;
    groups.removeDuplicates();

    foreach(QString title, groups)
        colorMap.insert(title, randomColor());

    if (!contents.isEmpty()) {
        max = getMax(contents);
        min = getMin(contents);
        range = max - min;
    }
}


//
// Public Slots
//
/**
 * Turns grouping with color on or off.
 * @param {bool} on - whether or not it
 *      will group
 */
void GraphView::setGrouping(bool on)
{
    shouldGroup = on;
}


//
// Protected Functions
//
/**
 * Paints the widget.
 * @param {QPaintEvent*} event - the paint even
 */
void GraphView::paintEvent(QPaintEvent *event)
{
    // Seed the random function with a constant value
    // so that the colors don't change whenever the
    // widget is redrawn.
    qsrand(10);

    // Fill in the background white with
    // a gray border.
    QPainter painter(this);
    painter.fillRect(rect(), Qt::white);
    QPen pen;
    pen.setBrush(Qt::gray);
    painter.setPen(pen);
    painter.drawRect(rect().adjusted(0, 0, -1, -1));

    // If there is no current model, we have
    // nothing to draw. Return.
    if (contents.isEmpty())
        return;


    // Calculate the x and y scales.
    double yScale = (height() - 20) / range;
    double xScale = width() / (contents.length() - 1.0);

    // Draw the graphs.
    // i represents the column, a line.
    for (int i = 0; i < contents.at(0).length(); i++) {
        QPainterPath path;
        path.moveTo(0, calcYCoord(contents.at(0).at(i), yScale));
        // j represents the row, a point in the line.
        for (int j = 1; j < contents.length(); j++) {
            int x = j * xScale;
            int y = calcYCoord(contents.at(j).at(i), yScale);
            path.lineTo(x, y);
        }
        QPen pen;
        if (shouldGroup) {
            pen.setColor(colorMap.value(lineTitles.at(i)));
            // Sets the pen a color for regression. Really should be a separate option.
            pen.setColor(QColor(0, lineTitles.at(i).toDouble() * 10, 100));
            //
        }
        else
            pen.setColor(randomColor());

        painter.setPen(pen);
        painter.drawPath(path);

    }
}


//
// Private Functions
//
/**
 * Finds the maximum in a 2D list.
 * @param {QList<QList<double> >} table - the 2d list
 * @return {double} the maximum value in the list
 */
double GraphView::getMax(QList<QList<double> > table) const
{
    double maximum = table.at(0).at(0);
    for (int i = 1; i < table.length(); i++)
        for (int j = 0; j < table.at(i).length(); j++)
            if (table.at(i).at(j) > maximum)
                maximum = table.at(i).at(j);

    return maximum;
}

/**
 * Finds the minimum in a 2D list.
 * @param {QList<QList<double> >} table - the 2d list
 * @return {double} the minimum value in the list
 */
double GraphView::getMin(QList<QList<double> > table) const
{
    double minimum = table.at(0).at(0);
    for (int i = 1; i < table.length(); i++)
        for (int j = 0; j < table.at(i).length(); j++)
            if (table.at(i).at(j) < minimum)
                minimum = table.at(i).at(j);

    return minimum;
}

/**
 * Calculates the y coordinate given a certain value.
 * @param {double} value - the value from the 2d list
 * @param {double} yScale - the scale of the graph
 * @return {int} the real y coordinate for the graph
 */
int GraphView::calcYCoord(double value, double yScale) const
{
    double yDiff = value - min;
    int scaledY = yDiff * yScale + 10;
    int yCoord = height() - scaledY;

    return yCoord;
}

/**
 * Creates a color with a random R, G, and B value.
 * @return {QColor} the random color
 */
QColor GraphView::randomColor() const
{
    int r = qrand() % 255;
    int g = qrand() % 255;
    int b = qrand() % 255;
    return QColor(r, g, b);
}
