/*
 * Copyright (c) 2015, University of Kaiserslautern
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors:
 *    Janik Schlemminger
 *    Robert Gernhardt
 *    Matthias Jung
 */

#include "phase.h"
#include "presentation/tracedrawing.h"
#include "businessObjects/transaction.h"
#include <cmath>

using namespace std;

void Phase::draw(QPainter *painter, const QwtScaleMap &xMap,
                 const QwtScaleMap &yMap, const QRectF &canvasRect, bool highlight,
                 const TraceDrawingProperties &drawingProperties) const
{
    Q_UNUSED(canvasRect);

    QColor color = getColor(drawingProperties);
    painter->setBrush(QBrush(getColor(drawingProperties), getBrushStyle()));

    if (!drawingProperties.drawBorder) {
        painter->setPen(color);
    } else {
        painter->setPen(Qt::black);
    }

    if (highlight) {
        QPen pen(Qt::red);
        pen.setWidth(3);
        painter->setPen(pen);
    }

    if (!isBankwise()) {
        for (unsigned int i = 0; i < drawingProperties.numberOfBanks; i++)
            drawPhaseSymbol(span.Begin(), span.End(), i, drawingProperties.drawText,
                            getPhaseSymbol(), painter, xMap, yMap);
    } else
        drawPhaseSymbol(span.Begin(), span.End(), getYVal(drawingProperties),
                        drawingProperties.drawText, getPhaseSymbol(), painter, xMap, yMap);

    for (Timespan span : spansOnCommandBus) {
        drawPhaseSymbol(span.Begin(), span.End(), drawingProperties.yValCommandBus,
                        false, PhaseSymbol::Hexagon, painter, xMap, yMap);
    }

    if (spanOnDataBus) {
        drawPhaseSymbol(spanOnDataBus->Begin(), spanOnDataBus->End(),
                        drawingProperties.yValDataBus, false, PhaseSymbol::Hexagon, painter, xMap,
                        yMap);
    }
}

void Phase::drawPhaseSymbol(traceTime begin, traceTime end, double y,
                            bool drawtext, PhaseSymbol symbol, QPainter *painter, const QwtScaleMap &xMap,
                            const QwtScaleMap &yMap) const
{
    double yVal = yMap.transform(y);
    double symbolHeight = yMap.transform(0) - yMap.transform(hexagonHeigth);

    if (symbol == PhaseSymbol::Hexagon) {
        QPoint hexFrom(xMap.transform(begin), yVal);
        QPoint hexTo(xMap.transform(end), yVal);
        drawHexagon(painter, hexFrom, hexTo, symbolHeight);
    } else {
        QPoint upperLeft(xMap.transform(begin), yVal - symbolHeight / 2);
        QPoint bottomRight(xMap.transform(end), yVal + symbolHeight / 2);
        painter->drawRect(QRect(upperLeft, bottomRight));
    }

    if (drawtext)
        drawText(painter, Name(), QPoint(xMap.transform(begin),
                                         yVal + symbolHeight / 2), TextPositioning::bottomRight);
}

QColor Phase::getColor(const TraceDrawingProperties &drawingProperties) const
{
    switch (drawingProperties.colorGrouping) {
    case ColorGrouping::PhaseType:
        return getPhaseColor();
        break;
    case ColorGrouping::Thread:
        return ColorGenerator::getColor(static_cast<unsigned int>
                                        (transaction->Thread()));
        break;
    case ColorGrouping::Transaction:
    default:
        return ColorGenerator::getColor(transaction->Id());
    }
}

int Phase::getYVal(const TraceDrawingProperties &drawingProperties) const
{
    Q_UNUSED(drawingProperties)
    return transaction->Bank();
}

Qt::BrushStyle Phase::getBrushStyle() const
{
    return Qt::SolidPattern;
}

bool Phase::isSelected(traceTime time, double yVal,
                       const TraceDrawingProperties &drawingproperties) const
{
    if (span.contains(time) && (!this->isBankwise()
                                || fabs(yVal - getYVal(drawingproperties)) <= hexagonHeigth))
        return true;
    if (spanOnDataBus && spanOnDataBus->contains(time)
            && fabs(yVal - drawingproperties.yValDataBus) <= hexagonHeigth)
        return true;

    for (Timespan span : spansOnCommandBus) {
        if (span.contains(time)
                && fabs(yVal - drawingproperties.yValCommandBus) <= hexagonHeigth)
            return true;
    }

    return false;
}

Phase::PhaseSymbol Phase::getPhaseSymbol() const
{
    return PhaseSymbol::Hexagon;
}
