#include "graph.h"

Graph::Graph(QObject *parent) : QCustomPlot() {
  this->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
  this->legend->setVisible(true);
  this->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop |
                                                            Qt::AlignLeft);
  this->axisRect()->setRangeZoomAxes(
      0, this->axisRect()->axis(QCPAxis::AxisType::atLeft));
  this->axisRect()->setRangeDragAxes(
      0, this->axisRect()->axis(QCPAxis::AxisType::atLeft));

  this->axisRect()->axis(QCPAxis::AxisType::atLeft)->setNumberPrecision(3);

  this->raw = nullptr;
  this->rawR = nullptr;
  this->rawG = nullptr;
  this->rawB = nullptr;

  this->c1 = this->addGraph();
  this->c1->setPen(QPen(Qt::black));
  this->c1->removeFromLegend();

  this->c2 = this->addGraph();
  this->c2->setPen(QPen(QColor(50, 50, 50)));
  this->c2->removeFromLegend();

  this->x1 = 0;
  this->x2 = 0;
  this->c1enabled = false;
  this->c2enabled = false;

  // range check
  connect(this->axisRect()->axis(QCPAxis::AxisType::atLeft),
          SIGNAL(rangeChanged(QCPRange)), this, SLOT(rangeChanged(QCPRange)));
}

void Graph::catchLine(Image &img, uint32_t line) {
  if (img.getHeight() <= line) {
    return;
  }
  if (img.getColors()) {
    if (this->rawR == nullptr) {
      this->rawR = this->addGraph();
      this->rawR->setPen(QPen(Qt::red));
      this->rawR->setName("R");
    }
    if (this->rawB == nullptr) {
      this->rawB = this->addGraph();
      this->rawB->setPen(QPen(Qt::blue));
      this->rawB->setName("B");
    }
    if (this->rawG == nullptr) {
      this->rawG = this->addGraph();
      this->rawG->setPen(QPen(Qt::green));
      this->rawG->setName("G");
    }
    QVector<double> x;
    QVector<double> red;
    QVector<double> green;
    QVector<double> blue;
    this->scaleMax = 0;
    this->scaleMin = 256;
    // clear
    if (this->raw != nullptr) {
      this->removeGraph(this->raw);
      delete (this->raw);
      this->raw = nullptr;
    }
    double tmp = 0;
    uint32_t val;
    // add data to graph
    for (uint32_t i = 0; i < img.getWidth(); i++) {
      val = img(r, i, line);
      red.append(val);
      red.append(val);
      if (val < this->scaleMin) {
        this->scaleMin = val;
      }
      if (val > this->scaleMax) {
        this->scaleMax = val;
      }
      val = img(g, i, line);
      green.append(val);
      green.append(val);
      if (val < this->scaleMin) {
        this->scaleMin = val;
      }
      if (val > this->scaleMax) {
        this->scaleMax = val;
      }
      val = img(b, i, line);
      blue.append(val);
      blue.append(val);
      if (val < this->scaleMin) {
        this->scaleMin = val;
      }
      if (val > this->scaleMax) {
        this->scaleMax = val;
      }
      x.append(tmp);
      tmp++;
      x.append(tmp);
      // offset to plot correctly
      tmp += 0.0000001;
    }
    // set data
    this->rawR->setData(x, red);
    this->rawG->setData(x, green);
    this->rawB->setData(x, blue);
    this->rescaleRGB();
  } else {
    if (this->raw == nullptr) {
      this->raw = this->addGraph();
      this->raw->setPen(QPen(Qt::red));
      this->raw->setName("Gray");
    }
    QVector<double> x;
    QVector<double> y;
    double tmp = 0;
    // clear
    if (this->rawR != nullptr) {
      this->removeGraph(this->rawR);
      delete (this->rawR);
      this->rawR = nullptr;
    }
    if (this->rawG != nullptr) {
      this->removeGraph(this->rawG);
      delete (this->rawG);
      this->rawG = nullptr;
    }
    if (this->rawB != nullptr) {
      this->removeGraph(this->rawB);
      delete (this->rawB);
      this->rawB = nullptr;
    }
    // add data to graph
    for (uint32_t i = 0; i < img.getWidth(); i++) {
      y.append(img(i, line));
      y.append(img(i, line));
      x.append(tmp);
      tmp++;
      x.append(tmp);
      // offset to plot correctly
      tmp += 0.0000001;
    }
    this->raw->setData(x, y);
    this->raw->rescaleAxes();
  }
  // replot
  this->xAxis->setRange(0, img.getWidth());
  this->replot();
}

void Graph::home() {
  if (this->raw != nullptr) {
    this->raw->rescaleAxes();
  }
  if (this->rawR != nullptr) {
    this->rescaleRGB();
  }
  this->replot();
}

void Graph::rangeChanged(QCPRange range) {
  if (range.upper > 255) {
    this->axisRect()->axis(QCPAxis::AxisType::atLeft)->setRangeUpper(255);
  }
  if (range.lower < 0) {
    this->axisRect()->axis(QCPAxis::AxisType::atLeft)->setRangeLower(0);
  }
}

void Graph::rescaleRGB() {
  this->axisRect()
      ->axis(QCPAxis::AxisType::atLeft)
      ->setRangeUpper(this->scaleMax);
  this->axisRect()
      ->axis(QCPAxis::AxisType::atLeft)
      ->setRangeLower(this->scaleMin);
}

void Graph::cursor1Enabled(int state) {
  QVector<double> x;
  QVector<double> y;
  if (state > 1) {
    this->c1enabled = true;
    x.append(this->x1 + 0.5);
    x.append(this->x1 + 0.5);
    y.append(0);
    y.append(255);
  } else {
    this->c1enabled = false;
  }
  this->c1->setData(x, y);
  this->replot();
}

void Graph::cursor2Enabled(int state) {
  QVector<double> x;
  QVector<double> y;
  if (state > 1) {
    this->c2enabled = true;
    x.append(this->x2 + 0.5);
    x.append(this->x2 + 0.5);
    y.append(0);
    y.append(255);
  } else {
    this->c2enabled = false;
  }
  this->c2->setData(x, y);
  this->replot();
}

void Graph::cursor1x(int pos) {
  this->x1 = pos;
  if (c1enabled) {
    QVector<double> x;
    QVector<double> y;
    x.append(this->x1 + 0.5);
    x.append(this->x1 + 0.5);
    y.append(0);
    y.append(255);
    this->c1->setData(x, y);
    this->replot();
  }
}

void Graph::cursor2x(int pos) {
  this->x2 = pos;
  if (c2enabled) {
    QVector<double> x;
    QVector<double> y;
    x.append(this->x2 + 0.5);
    x.append(this->x2 + 0.5);
    y.append(0);
    y.append(255);
    this->c2->setData(x, y);
    this->replot();
  }
}
