#include "camerapreview.h"
#include <QMessageBox>
#include <math.h> 
#include "mylogger.h"

CameraPreview::CameraPreview(QWidget *parent):cameraname(""), camera(nullptr), QWidget(parent) {
    qDebug() << "Camera preview constructor";
    label = new QLabel(cameraname);
    this->setLayout(new QVBoxLayout(this));
    this->layout()->addWidget(label);
    imgLabel = new QLabel(this);
    imgLabel->setMinimumSize(QSize(1024, 768));
    this->layout()->addWidget(imgLabel);
    QWidget *controls = new QWidget(this);

    width = new QSpinBox(controls);
    width->setMinimum(1);
    width->setMaximum(2048);
    width->setValue(width->maximum());
    connect(width, SIGNAL(textChanged(QString)), SLOT(updateWidth(QString)));

    height = new QSpinBox(controls);
    height->setMinimum(1);
    height->setMaximum(1536);
    height->setValue(height->maximum());
    connect(height, SIGNAL(textChanged(QString)), SLOT(updateHeight(QString)));

    xoffs = new QSpinBox(controls);
    xoffs->setMinimum(0);
    xoffs->setMaximum(2047);
    xoffs->setValue(0);
    connect(xoffs, SIGNAL(textChanged(QString)), SLOT(updateXoffs(QString)));

    yoffs = new QSpinBox(controls);
    yoffs->setMinimum(0);
    yoffs->setMaximum(1535);
    yoffs->setValue(0);
    connect(yoffs, SIGNAL(textChanged(QString)), SLOT(updateYoffs(QString)));

    QGridLayout *grid = new QGridLayout(controls);
    grid->addWidget(new QLabel("width", controls), 0, 0);
    grid->addWidget(width, 0, 1);

    grid->addWidget(new QLabel("height", controls), 1, 0);
    grid->addWidget(height, 1, 1);

    grid->addWidget(new QLabel("x-offset", controls), 0, 2);
    grid->addWidget(xoffs, 0, 3);

    grid->addWidget(new QLabel("y-offset", controls), 1, 2);
    grid->addWidget(yoffs, 1, 3);
    controls->setLayout(grid);
    this->layout()->addWidget(controls);
    //setPrimaryCamera(devicename);
    qDebug() << "Camera preview constructor";
    takeStill();
}


void CameraPreview::setCamera(QString &device){
    qDebug() << "update camera! ";// << device.toStdString();
    cameraname = device;
    label->setText(device);
    if (camera != NULL) {
        qDebug() << "camera is not nullptr! ";
        delete camera;
        camera = nullptr;
    }
    camera = new PylonWrapper(cameraname.toStdString());
    std::string message;
    bool success = camera->openCamera(message);
    if (!success) {
        qWarning() << "Could not open camera device!";
        qWarning() << QString::fromStdString(message);
        QMessageBox msgBox;
        QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>";
        msgBox.setText(msg);
        msgBox.exec();
    }
    takeStill();
}


void CameraPreview::takeStill() {
    qDebug() << "Take Still image!";
    if (camera != nullptr && camera->isOpen()) {
      MyImage mimg;
      bool valid = camera->grabFrame(mimg);
      if (!valid) {
          qWarning() << "Grabbing from camera failed!";
          return;
      }
      QImage img(static_cast<uchar *>(mimg.data()), mimg.width(), mimg.height(),
                 QImage::Format::Format_Grayscale8);
      QPixmap mpm = QPixmap::fromImage(img);
      this->pm = mpm;
      mpm = mpm.scaledToWidth(1024);
      setImage(mpm);
      updateROI();
    } else {
      qDebug() << "Camera is not open! Connect to camera first!";
    }
}

void CameraPreview::setImage(const QPixmap &img) {
    imgLabel->setPixmap(img);
}

void CameraPreview::updateWidth(QString s) {
    // if (xoffs->value() + width->value() > 2048) {
    //     xoffs->setValue(2048 - width->value());
    // }
    validate(width, xoffs, 2048);
    updateROI();
}

void CameraPreview::updateXoffs(QString s) {
    // if (xoffs->value() + width->value() > 2048) {
    //     width->setValue(2048 - xoffs->value());
    // }
    validate(xoffs, width, 2048);
    updateROI();
}

void CameraPreview::updateHeight(QString s) {
    // if (height->value() + yoffs->value() > 1536) {
    //     yoffs->setValue(1536 - height->value());
    // }
    validate(height, yoffs, 1536);
    updateROI();
}

void CameraPreview::updateYoffs(QString s) {
    // if (height->value() + yoffs->value() > 1536) {
    //     height->setValue(1536 - yoffs->value());
    // }
    validate(yoffs, height, 1536);
    updateROI();
}

void CameraPreview::validate(QSpinBox *origin, QSpinBox *dest, int limit){
    if (origin->value() + dest->value() > limit) {
        dest->setValue(limit - origin->value());
    }
}

void CameraPreview::updateROI(bool emitSignal) {
    QImage img = pm.toImage();
    double scaling = 1024.0 / img.width();
    img = img.scaledToWidth(1024);
    QPainter qPainter(&img);
    qPainter.setBrush(Qt::NoBrush);
    qPainter.setPen(Qt::red);
    QPen p = qPainter.pen();
    p.setWidthF(1.5);
    qPainter.setPen(p);
    int x = xoffs->value();
    int rxoffs = round(xoffs->value() * scaling);
    int ryoffs = round(yoffs->value() * scaling);
    int rwidth = round(width->value() * scaling);
    int rheight = round(height->value() * scaling);
    qPainter.drawRect(rxoffs, ryoffs, rwidth, rheight);
    bool bEnd = qPainter.end();

    QPixmap npm = QPixmap::fromImage(img);
    setImage(npm);
    if (emitSignal) {
        emit roiUpdated(xoffs->value(), yoffs->value(), width->value(), height->value());
    }
}

void CameraPreview::setSize(int w, int h) {
    width->setValue(w);
    height->setValue(h);
    validate(width, xoffs, 2048);
    validate(height, yoffs, 1536);
    updateROI(false);
}

QString CameraPreview::device(){
    return cameraname;
}

ROI CameraPreview::getRoi() {
    ROI r;
    r.x = xoffs->value();
    r.y = yoffs->value();
    r.width = width->value();
    r.height = height->value();
    r.height = r.height > 1536 ? 1536 - r.y : r.height;
    r.width = r.width > 2048 ? 2048 - r.x : r.width;
    return r;
}

CameraPreview::~CameraPreview(){
    qDebug() << "cameraPreview destructor";
    if (camera != nullptr){ 
        qDebug() << "close camera";
        // camera->closeCamera();
        delete camera;
        camera = nullptr;
    }
    qDebug() << "deleted camera";

}