#include "output_plot.hh"
#include "../../3rdParty/qwt/qwt_date_scale_draw.h"
#include "../../3rdParty/qwt/qwt_date_scale_engine.h"

OutputPlot::OutputPlot(QWidget* parent) :
    QwtPlot(parent),
    outputCurve_(std::make_unique<QwtPlotCurve>()),
    sma12Curve_(std::make_unique<QwtPlotCurve>()),
    tradingCurve_(std::make_unique<QwtPlotTradingCurve>()),
    topMarker_(std::make_unique<QwtPlotMarker>()),
    bottomMarker_(std::make_unique<QwtPlotMarker>()),
    outputGrid_(std::make_unique<QwtPlotGrid>())
{
    initPlot();
    initAxes();
    initCurves();
    initMarkers();
    initGrid();
}

void OutputPlot::initPlot()
{
    QFont plotTitleFont;
    plotTitleFont.setPointSize(11);
    plotTitleFont.setBold(true);

    auto plotTitle = QwtText(tr("Forecasting results"));
    plotTitle.setFont(plotTitleFont);

    setTitle(plotTitle);

    setAutoFillBackground(true);
    setPalette(Qt::white);
    setCanvasBackground(Qt::white);
    setFrameStyle(QFrame::Plain | QFrame::StyledPanel);

    auto frame = static_cast<QFrame*>(canvas());
    frame->setFrameStyle(QFrame::NoFrame);
}

void OutputPlot::initAxes()
{
    QFont axisTitleFont;
    axisTitleFont.setPointSize(11);

    QFont axisFont;
    axisFont.setPointSize(10);

    auto xBottomAxisTitle = QwtText(tr("Date and time"));
    xBottomAxisTitle.setFont(axisTitleFont);

    auto yLeftAxisTitle = QwtText(tr("Network output"));
    yLeftAxisTitle.setColor(Qt::darkBlue);
    yLeftAxisTitle.setFont(axisTitleFont);

    auto yRightAxisTitle = QwtText(tr("SMA9 value"));
    yRightAxisTitle.setColor(Qt::magenta);
    yRightAxisTitle.setFont(axisTitleFont);

    setAxisTitle(QwtPlot::xBottom, xBottomAxisTitle);
    setAxisMaxMinor(QwtPlot::xBottom, 12);
    setAxisMaxMajor(QwtPlot::xBottom, 4);
    setAxisFont(QwtPlot::xBottom, axisFont);

    setAxisScaleEngine(QwtPlot::xBottom, new QwtDateScaleEngine());
    setAxisScaleDraw(QwtPlot::xBottom, new QwtDateScaleDraw());

    setAxisTitle(QwtPlot::yLeft, yLeftAxisTitle);
    setAxisScale(QwtPlot::yLeft, -1.0, 1.0);
    setAxisFont(QwtPlot::yLeft, axisFont);

    setAxisTitle(QwtPlot::yRight, yRightAxisTitle);
    enableAxis(QwtPlot::yRight);
    setAxisAutoScale(QwtPlot::yRight);
    setAxisFont(QwtPlot::yRight, axisFont);

    axisScaleEngine(QwtPlot::yRight)->setAttribute(
        QwtScaleEngine::Floating, true);
}

void OutputPlot::initCurves()
{
    auto outputPen = outputCurve_->pen();
    outputPen.setWidth(2);
    outputPen.setColor(Qt::darkBlue);
    outputCurve_->setPen(outputPen);

    outputCurve_->setAxes(QwtPlot::xBottom, QwtPlot::yLeft);

    tradingCurve_->setMinSymbolWidth(5.0);

    QBrush bearishBrush = tradingCurve_->symbolBrush(
        QwtPlotTradingCurve::Decreasing);

    bearishBrush.setColor(Qt::red);

    tradingCurve_->setSymbolBrush(
        QwtPlotTradingCurve::Decreasing, bearishBrush);

    QBrush bullishBrush = tradingCurve_->symbolBrush(
        QwtPlotTradingCurve::Increasing);

    bullishBrush.setColor(Qt::green);

    tradingCurve_->setSymbolBrush(
        QwtPlotTradingCurve::Increasing, bullishBrush);

    tradingCurve_->setAxes(QwtPlot::xBottom, QwtPlot::yRight);

    auto sma12Pen = sma12Curve_->pen();
    sma12Pen.setWidth(2);
    sma12Pen.setColor(Qt::magenta);
    sma12Curve_->setPen(sma12Pen);

    sma12Curve_->setAxes(QwtPlot::xBottom, QwtPlot::yRight);

    sma12Curve_->attach(this);
    outputCurve_->attach(this);
    tradingCurve_->attach(this);
}

void OutputPlot::initMarkers()
{
    topMarker_->setYAxis(QwtPlot::yLeft);
    topMarker_->setLabelOrientation(Qt::Horizontal);
    topMarker_->setLineStyle(QwtPlotMarker::HLine);
    topMarker_->setLabelAlignment(Qt::AlignLeft);
    topMarker_->setVisible(false);

    QPen topMarkerPen = topMarker_->linePen();
    topMarkerPen.setColor(Qt::darkGreen);
    topMarker_->setLinePen(topMarkerPen);

    bottomMarker_->setYAxis(QwtPlot::yLeft);
    bottomMarker_->setLabelOrientation(Qt::Horizontal);
    bottomMarker_->setLineStyle(QwtPlotMarker::HLine);
    bottomMarker_->setLabelAlignment(Qt::AlignLeft);
    bottomMarker_->setVisible(false);

    QPen bottomMarkerPen = bottomMarker_->linePen();
    bottomMarkerPen.setColor(Qt::darkRed);
    bottomMarker_->setLinePen(bottomMarkerPen);

    topMarker_->attach(this);
    bottomMarker_->attach(this);
}

void OutputPlot::initGrid()
{
    QPen majorOutputPen = outputGrid_->majorPen();
    majorOutputPen.setColor(Qt::gray);
    majorOutputPen.setStyle(Qt::DashLine);
    outputGrid_->setMajorPen(majorOutputPen);
    outputGrid_->attach(this);
}

void OutputPlot::thresholdVisible(bool visible)
{
    topMarker_->setVisible(visible);
    bottomMarker_->setVisible(visible);
}

void OutputPlot::threshold(double threshold)
{
    double topTh = 1.0 - threshold;
    topMarker_->setYValue(1.0 - threshold);
    topMarker_->setLabel(QwtText("\nTh=" + QString::number(topTh)));

    double bottomTh = -1.0 + threshold;
    bottomMarker_->setYValue(bottomTh);
    bottomMarker_->setLabel(QwtText("Th=" + QString::number(bottomTh) + "\n"));
}

void OutputPlot::plotData(
    QVector<double> timeValues, QVector<double> networkOutputs,
    QVector<double> sma12Values, QVector<QwtOHLCSample> priceSamples)
{
    outputCurve_->setSamples(timeValues, networkOutputs);
    sma12Curve_->setSamples(timeValues, sma12Values);
    tradingCurve_->setSamples(priceSamples);
}

