// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm

#include "cropshapeeditor.hpp"
#include <QPainter>
#include <QMouseEvent>
#include <QtCore/qmath.h>
#include <functional>

static const unsigned int CROSS_LARGE(4);
static const float BACK_OPACITY(0.3f);
static const int MIN_SIDE(50);
static const int WHEEL_STEP(3);

CropShapeEditor::CropShapeEditor(const QSize thumbSize, const QSize frmSize, const Crop &initCrop, QWidget *parent)
    : QWidget(parent),
      frameSize(frmSize),
      thumbnailSize(thumbSize),
      shape(cropToShape(initCrop)),
      currentLine(lineColor),
      currentFill(fillColor),
      border(QPen(lineColor, PEN_THICK, Qt::DashLine, Qt::FlatCap, Qt::MiterJoin)),
      opacity(BACK_OPACITY),
      modificationMode(ModificationMode::NoModification),
      ignoreEvent(false) {
  setAttribute(Qt::WA_Hover);
  setBackgroundRole(QPalette::Base);
  setMouseTracking(true);
  setFixedWidth(thumbSize.width());
  setFixedHeight(thumbSize.height());
  setAttribute(Qt::WA_TranslucentBackground);
}

void CropShapeEditor::onResetToDefault() {
  setDefaultCrop();
  emit notifyCropSet(getCrop());
}

const QRectF CropShapeEditor::cropToShape(const Crop &crop) const {
  const float ratio = getRatio();
  Q_ASSERT(ratio > 0);
  return QRectF(crop.crop_left / ratio, crop.crop_top / ratio, (crop.crop_right - crop.crop_left) / ratio,
                (crop.crop_bottom - crop.crop_top) / ratio);
}

CropShapeEditor::~CropShapeEditor() {}

bool CropShapeEditor::isValidCrop() const { return true; }

void CropShapeEditor::disableEdition(const bool disable) {
  ignoreEvent = disable;
  currentFill = disable ? disableColor : fillColor;
  currentLine = disable ? disableColor : lineColor;
  border.setColor(currentLine);
}

void CropShapeEditor::setLineColor(QColor color) { lineColor = color; }

QColor CropShapeEditor::getLineColor() const { return lineColor; }

void CropShapeEditor::setFillColor(QColor color) { fillColor = color; }

QColor CropShapeEditor::getFillColor() const { return fillColor; }

void CropShapeEditor::setDisableColor(QColor color) { disableColor = color; }

QColor CropShapeEditor::getDisableColor() const { return disableColor; }

void CropShapeEditor::wheelEvent(QWheelEvent *event) {
  if (ignoreEvent) {
    event->ignore();
    return;
  }
  if (getCentralArea(shape).contains(event->pos())) {
    const int delta = qAbs(event->delta()) / WHEEL_STEP;
    const int adjust = 2 * delta;
    if (event->delta() > 0) {
      shape.adjust(-delta, -delta, delta, delta);
      update();
      emit notifyCropSet(getCrop());
    } else {
      if (shape.height() - adjust > MIN_SIDE && shape.width() - adjust > MIN_SIDE) {
        shape.adjust(delta, delta, -delta, -delta);
        update();
        emit notifyCropSet(getCrop());
      }
    }
  }
}

void CropShapeEditor::showEvent(QShowEvent *event) {
  currentFill = ignoreEvent ? disableColor : fillColor;
  currentLine = ignoreEvent ? disableColor : lineColor;
  border.setColor(currentLine);
  QWidget::showEvent(event);
}

void CropShapeEditor::drawCenterCross(QPainter &painter) {
  painter.drawLine(shape.center() - QPointF(0, CROSS_LARGE), shape.center() + QPointF(0, CROSS_LARGE));
  painter.drawLine(shape.center() - QPointF(CROSS_LARGE, 0), shape.center() + QPointF(CROSS_LARGE, 0));
}

void CropShapeEditor::paintEvent(QPaintEvent *event) {
  Q_UNUSED(event);
  QPainter painter(this);
  painter.setRenderHint(QPainter::Antialiasing);
  painter.setPen(QPen(currentLine));
  drawCenterCross(painter);
  drawCropShape(painter);
}

const Crop CropShapeEditor::getCrop() const {
  const float ratio = getRatio();
  return Crop(qRound(shape.left() * ratio), qRound((shape.x() + shape.width()) * ratio), qRound(shape.top() * ratio),
              qRound((shape.y() + shape.height()) * ratio));
}

void CropShapeEditor::setCrop(const Crop &crop) {
  shape = cropToShape(crop);
  update();
  emit notifyCropSet(getCrop());
}

bool CropShapeEditor::isAutoCropSupported() const { return false; }

const QRectF CropShapeEditor::getCentralArea(const QRectF rectangle) const {
  return QRectF(rectangle.left() + SEL_OFFSET, rectangle.top() + SEL_OFFSET, rectangle.width() - SEL_OFFSET,
                rectangle.height() - SEL_OFFSET);
}

float CropShapeEditor::getRatio() const { return float(frameSize.width()) / thumbnailSize.width(); }