#include "ImageView.h"
#include <QPainter>
#include <QDebug>
#include <QGraphicsPixmapItem>
#include <QScrollBar>
#include <QMenu>
#include <QFileDialog>
#include <QDateTime>
#include <QMessageBox>
#include <QApplication>

#define VIEW_CENTER viewport()->rect().center()
#define VIEW_WIDTH  viewport()->rect().width()
#define VIEW_HEIGHT viewport()->rect().height()


ImageView::ImageView(QWidget* parent) :
    QGraphicsView(parent),
    m_imageOffset(0, 0),
    m_bMouseTranslate(false),
    m_isDrawing(false),
    m_curDrawing(false),
    m_isCreating(false),
    m_currentPathItem(nullptr)

{
    //    m_rubberBand = nullptr;
    m_bRulerState = false;
    m_pRuleLine = nullptr;
    setScene(new QGraphicsScene(this));
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    //设置视图属性
    //setRenderHint(QPainter::SmoothPixmapTransform);
    setRenderHint(QPainter::Antialiasing);
    setMouseTracking(true);
    setDragMode(RubberBandDrag);
}

ImageView::~ImageView()
{
}

void ImageView::setPixmap(const QPixmap& newPixmap) {
    this->m_pixmap = newPixmap;
    scene()->clear();
    m_pixmapItem = scene()->addPixmap(m_pixmap);
    m_pixmapItem->setZValue(1);
    QPointF pixmapCenter(m_pixmap.width() / 2.0, m_pixmap.height() / 2.0);
    m_pixmapItem->setPos(-pixmapCenter);
    QRectF sceneRect(-pixmapCenter.x(), -pixmapCenter.y(), m_pixmap.width(), m_pixmap.height());
    scene()->setSceneRect(sceneRect);
    setSceneRect(scene()->itemsBoundingRect());
    this->resize(m_pixmap.width(), m_pixmap.height());
    m_imageOffset = QPoint(0, 0); 
    setCursor(Qt::ArrowCursor);
    update(); 
}

void ImageView::setCurPixmap(const QPixmap& newPixmap) {
    if (this->m_pixmap.isNull()) {
        this->m_pixmap = newPixmap;
        scene()->clear();
        m_pixmapItem = scene()->addPixmap(m_pixmap);
        m_pixmapItem->setZValue(1);
        QPointF pixmapCenter(m_pixmap.width() / 2.0, m_pixmap.height() / 2.0);
        m_pixmapItem->setPos(-pixmapCenter);
        QRectF sceneRect(-pixmapCenter.x(), -pixmapCenter.y(), m_pixmap.width(), m_pixmap.height());
        scene()->setSceneRect(sceneRect);
        setSceneRect(scene()->itemsBoundingRect());
        //this->resize(m_pixmap.width(), m_pixmap.height());
        m_imageOffset = QPoint(0, 0); 
        setCursor(Qt::ArrowCursor);
        update();
    }
    else {
        this->m_pixmap = newPixmap;
        m_pixmapItem->setPixmap(m_pixmap);
    }
}

void ImageView::addRuler()
{
    m_bRulerState = true;
}

void ImageView::cancelRuler()
{
    m_bRulerState = false;
}

void ImageView::paintEvent(QPaintEvent* event) {

    QGraphicsView::paintEvent(event);
    QPainter painter(viewport());
    painter.setRenderHint(QPainter::Antialiasing);
    drawCrosshair(painter);
}

void ImageView::mousePressEvent(QMouseEvent* event) {
    if (event->button() == Qt::LeftButton) {
        
        QPointF point = mapToScene(event->pos());
        if (scene()->itemAt(point, transform()) != nullptr
            && scene()->itemAt(point, transform())->type() == QGraphicsPixmapItem::Type) {
            setCursor(Qt::OpenHandCursor);
            m_bMouseTranslate = true;
            m_lastMousePos = event->pos();
        }
    }
    else if (event->button() == Qt::RightButton) {
        m_rightClickPressPos = event->pos();
        m_rightButtonPressed = true;

        if (m_bRulerState) {
            if (!m_isCreating) {
                
                m_isCreating = true;
                m_startPos = mapToScene(event->pos());
                m_pTempLine = scene()->addLine(QLineF(m_startPos, m_startPos),
                    QPen(Qt::gray, 1, Qt::DashLine));
                m_pTempLine->setZValue(2);
            }
            else {
                
                m_isCreating = false;
                QPointF endPos = mapToScene(event->pos());
                scene()->removeItem(m_pTempLine);
                delete m_pTempLine;

                RulerLineItem* ruler = new RulerLineItem(QLineF(m_startPos, endPos));
                ruler->setRulerText(tr("test ruler"));
                ruler->setZValue(2);
                scene()->addItem(ruler);
            }
        }
        event->accept();
    }
    QGraphicsView::mousePressEvent(event);
}

void ImageView::mouseMoveEvent(QMouseEvent* event) {
    if (m_isCreating && m_pTempLine) {
        QPointF currentPos = mapToScene(event->pos());
        m_pTempLine->setLine(QLineF(m_startPos, currentPos));
    }

    if (m_bMouseTranslate) {
        
        QPointF delta = event->pos() - m_lastMousePos;
        
        horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x());
        verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y());
        m_lastMousePos = event->pos();  
    }
    else if ((event->buttons() & Qt::RightButton) && m_isDrawing && m_rightButtonPressed) {
        if (!m_curDrawing && (event->pos() - m_rightClickPressPos).manhattanLength() > 5) {
            m_curDrawing = true;
            
            QPointF scenePos = mapToScene(m_rightClickPressPos);
            m_currentPath = QPainterPath(scenePos);
            m_currentPathItem = new QGraphicsPathItem();
            m_currentPathItem->setPen(QPen(Qt::red, 2));
            m_currentPathItem->setPath(m_currentPath);
            m_currentPathItem->setZValue(2);
            scene()->addItem(m_currentPathItem);
            m_drawnPaths.append(m_currentPathItem);
        }
        if (m_curDrawing && m_currentPathItem) {
            QPointF scenePos = mapToScene(event->pos());
            m_currentPath.lineTo(scenePos);
            m_currentPathItem->setPath(m_currentPath);
        }
        event->accept();
        return;
    }
    QGraphicsView::mouseMoveEvent(event);
}

void ImageView::mouseReleaseEvent(QMouseEvent* event) {
    if (event->button() == Qt::LeftButton) {
        setCursor(Qt::ArrowCursor);  
        m_bMouseTranslate = false;
    }
    else if (event->button() == Qt::RightButton && m_rightButtonPressed) {
        if (!m_curDrawing) {
            if (!m_bRulerState) {
                QMenu menu(this);
                QAction* act1 = menu.addAction(tr("save picture","保存图片"));
                QAction* act2 = menu.addAction(tr("clear drawing","清除画笔"));
                QAction* act3 = menu.addAction(tr("clear selected rulers"));

                connect(act1, &QAction::triggered, this, [this]() {
                    saveImage();
                    });
                connect(act2, &QAction::triggered, this, [this]() {
                    clearDrawnLines();
                    });
                connect(act3, &QAction::triggered, this, [this]() {
                    clearRulerLines();
                    });
                menu.exec(event->globalPos());
            }
        }
        else {
            m_currentPathItem = nullptr;
            m_curDrawing = false;
        }

        m_rightButtonPressed = false;
        event->accept();
        return;
    }
    QGraphicsView::mouseReleaseEvent(event);
}

void ImageView::wheelEvent(QWheelEvent* event)
{
    if (event->orientation() == Qt::Vertical) {
        event->ignore(); 
        return;
    }
    event->accept();
}

void ImageView::resizeEvent(QResizeEvent* event)
{
    QGraphicsView::resizeEvent(event);
    viewport()->update(); 
}

void ImageView::scrollContentsBy(int dx, int dy)
{
    QGraphicsView::scrollContentsBy(dx, dy);
    viewport()->update();  
}

void ImageView::drawCrosshair(QPainter& painter)
{
    const QRect viewRect = viewport()->rect();
    int resolutionWidth = viewRect.width();
    int resolutionHeight = viewRect.height();
    painter.setPen(QPen(QColor(139, 105, 20, 255), 1));
    
    painter.drawLine(resolutionWidth / 2, 0, resolutionWidth / 2, resolutionHeight);
   
    painter.drawLine(0, resolutionHeight / 2, resolutionWidth, resolutionHeight / 2);

    int centerX = resolutionWidth / 2;
    int centerY = resolutionHeight / 2;

    int rulerLength = viewRect.width(); 
    int tickSpacing = 5;

    
    int rulerStartXHorizontal = centerX;
    int rulerStartYHorizontal = centerY;

    for (int i = 0; i <= rulerLength / 2; i += tickSpacing) {
        int tickHeight = 0;
        if (i % (tickSpacing * 10) == 0) {
            tickHeight = 30;
        }
        else if (i % (tickSpacing * 5) == 0) { 
            tickHeight = 15;
        }
        else {
            tickHeight = 5;
        }

        painter.drawLine(rulerStartXHorizontal + i, rulerStartYHorizontal + tickHeight, rulerStartXHorizontal + i, rulerStartYHorizontal - tickHeight);
        painter.drawLine(rulerStartXHorizontal - i, rulerStartYHorizontal + tickHeight, rulerStartXHorizontal - i, rulerStartYHorizontal - tickHeight);
    }

    
    int rulerStartXVertical = centerX; 
    int rulerStartYVertical = centerY;

    for (int i = 0; i <= rulerLength / 2; i += tickSpacing) {
        int tickWidth = 0;
        if (i % (tickSpacing * 10) == 0) {
            tickWidth = 15;
        }
        else if (i % (tickSpacing * 5) == 0) { 
            tickWidth = 10;
        }
        else { 
            tickWidth = 5;
        }
        painter.drawLine(rulerStartXVertical+ tickWidth, rulerStartYVertical - i, rulerStartXVertical - tickWidth, rulerStartYVertical - i);
        painter.drawLine(rulerStartXVertical + tickWidth, rulerStartYVertical + i, rulerStartXVertical - tickWidth, rulerStartYVertical + i);
    }
}

void ImageView::saveImage()
{
    
    QString defaultFileName = QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss") + ".png";

    QString fileName = QFileDialog::getSaveFileName(
        this,
        tr("save picture"),
        QDir::homePath() + "/" + defaultFileName,
        tr("PNG  (*.png);;JPEG  (*.jpg);; (*)")
    );
    if (!fileName.isEmpty()) {
        QImage image(viewport()->size(), QImage::Format_ARGB32);
        image.fill(Qt::white);
        QPainter painter(&image);
        this->render(&painter);
        if (!image.save(fileName)) {
            QMessageBox::warning(this,tr("save failed"),tr("The picture cannot be saved to the specified path"));
        }
        else {
            QMessageBox::information(this, tr("save sucessful"),tr("The picture has been successfully saved to:") + fileName);
        }
        painter.end();
    }
}


void ImageView::clearDrawnLines()
{
    qDeleteAll(m_drawnPaths);
    m_drawnPaths.clear();

}

void ImageView::clearRulerLines()
{
    foreach(QGraphicsItem * item, scene()->selectedItems()) {
        if (nullptr == item)
            continue;
        if (dynamic_cast<RulerLineItem*>(item) != nullptr) {
            scene()->removeItem(item);
        }

    }
}