#include "eobject.h"
#include "eobjectattr.h"
#include <QGraphicsSceneMouseEvent>

eObject::eObject(InteractiveType type, QGraphicsItem *parent) : QGraphicsObject(parent),
    m_interactiveType(type),
    m_movable(false),
    m_handleLen(10),
    m_rLimit(INVALID_RECT) {
    setGeometry(0, 0, 100, 100);
    init();
}

eObject::eObject(QRectF rect, InteractiveType type, QGraphicsItem *parent) : QGraphicsObject(parent),
    m_interactiveType(type),
    m_movable(false),
    m_handleLen(10),
    m_rLimit(INVALID_RECT) {
    setGeometry(rect);
    init();
}

eObject::eObject(const QJsonObject &json, InteractiveType type, QGraphicsItem *parent) : QGraphicsObject(parent),
    m_interactiveType(type),
    m_movable(false),
    m_handleLen(10),
    m_rLimit(INVALID_RECT) {
    setZValue(json["order"].toInt());
    setGeometry(QRectF(json["x"].toInt(), json["y"].toInt(),
                       json["w"].toInt(), json["h"].toInt()));
    init();
}

void eObject::init(){
    qDebug()<<"eObject::init()";
    setInteractiveType(m_interactiveType);

    m_handlePen.setBrush(QBrush(QColor::fromRgb(0, 255, 0)));
    m_handlePen.setWidth(1);

    QVector<qreal> dashes;
    qreal space = 2;
    qreal solid = 2;
    dashes << solid << space << solid <<space;
    m_borderPen.setBrush(QBrush(QColor::fromRgb(0, 255, 0)));
    m_borderPen.setDashPattern(dashes);
    m_borderPen.setWidth(1);

    connect(this, SIGNAL(sPlayBQ()), this, SLOT(playElectment()), Qt::BlockingQueuedConnection);
    connect(this, SIGNAL(sStopBQ()), this, SLOT(stopElectment()), Qt::BlockingQueuedConnection);


}
void eObject::setInteractiveType(InteractiveType type){
qDebug()<<"eObject::setInteractiveType(InteractiveType)";
    m_interactiveType = type;
    GraphicsItemFlags flag = flags();
    if(Dynamic == m_interactiveType) {
        flag |= ItemIsMovable;
        flag |= ItemIsSelectable;
        flag &= ~ItemIsFocusable;
    } else {
        flag &= ~ItemIsMovable;
        flag &= ~ItemIsSelectable;
        flag &= ~ItemIsFocusable;
    }
    setFlags(flag);
}

QWidget* eObject::wAttr(){
    qDebug()<<"eObject::wAttr()";
    m_wAttr = new eObjectAttr(geometry(), rLimit());
    connect(this, SIGNAL(geometryChanged(const QRectF &)), m_wAttr, SLOT(onAttrSetting(const QRectF &)));
    connect(m_wAttr, SIGNAL(sAttrChanged(const QRectF &)), this, SLOT(onAttrChanged(const QRectF &)));
    void(QComboBox::*currentIndexChanged)(int) = &QComboBox::currentIndexChanged;
    connect(m_wAttr->borderFd, currentIndexChanged, this, [this](int idx){
        //m_wAttr->borderFd->itemIcon(idx).data_ptr().;
    });
    return m_wAttr;
}

QJsonObject eObject::elementJson() const {
    qDebug()<<"eObject::elementJson()";
    QJsonObject oRoot;
    QRectF r = geometry();
    oRoot["order"] = zValue();
    oRoot["x"] = (int)r.x();
    oRoot["y"] = (int)r.y();
    oRoot["w"] = (int)r.width();
    oRoot["h"] = (int)r.height();
    return oRoot;
}

void eObject::setRLimit(const QRectF &r) {
    qDebug()<<"eObject::setRLimit(QRectF)";
    if(isSelected()) m_wAttr->setRLimit(r);

    if(m_rLimit != INVALID_RECT) {
        qreal  mx, my, mw, mh;
        qreal scale_w = r.width()  / m_rLimit.width();
        qreal scale_h = r.height() / m_rLimit.height();
        mx = std::round(x() * scale_w);
        my = std::round(y() * scale_h);
        mw = std::round(m_w * scale_w);
        mh = std::round(m_h * scale_h);
        setPos(mx, my);
        m_w = mw;
        m_h = mh;
        adjustHandle();
        geometryChanged(geometry());
    }
    m_rLimit = r;
}

void eObject::onAttrChanged(const QRectF &rect){
    qDebug()<<"eObject::onAttrChanged(QRectF)";
    setGeometry(rect);
}


QRectF eObject::boundingRect() const {
    int m2 = m_handleLen * 2;
    return QRectF(-m_handleLen, -m_handleLen, m_w+m2, m_h+m2);
}
//绘制选中和未选中的区域边框
void eObject::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
    //qDebug()<<"eObject::paint(QPainter, QStyleOptionGraphicsItem)";
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->save();
    //绘制边框
    QPixmap img("borders/M8_8.bmp");
    int borderWidth = img.height();
    QBrush brush(img);

    QPainterPath path(QPointF(0, 0));
    path.lineTo(m_w, 0);
    path.lineTo(m_w - borderWidth, borderWidth);
    path.lineTo(borderWidth, borderWidth);
    path.closeSubpath();
    painter->fillPath(path, brush);

    QTransform transform;
    transform.rotate(90);
    brush.setTransform(transform);
    path = QPainterPath(QPointF(m_w, 0));
    path.lineTo(m_w, m_h);
    path.lineTo(m_w - borderWidth, m_h - borderWidth);
    path.lineTo(m_w - borderWidth, borderWidth);
    path.closeSubpath();
    painter->fillPath(path, brush);

    transform.rotate(90);
    brush.setTransform(transform);
    path = QPainterPath(QPointF(m_w, m_h));
    path.lineTo(0, m_h);
    path.lineTo(borderWidth, m_h - borderWidth);
    path.lineTo(m_w - borderWidth, m_h - borderWidth);
    path.closeSubpath();
    painter->fillPath(path, brush);

    transform.rotate(90);
    brush.setTransform(transform);
    path = QPainterPath(QPointF(0, m_h));
    path.lineTo(0, 0);
    path.lineTo(borderWidth, borderWidth);
    path.lineTo(borderWidth, m_h - borderWidth);
    path.closeSubpath();
    painter->fillPath(path, brush);


    if(isSelected()) {
        QPainterPath pRect;
        pRect.addRect(rect());
        m_borderPen.setBrush(QBrush(QColor::fromRgb(0, 255, 0)));
        painter->setPen(m_borderPen);
        painter->drawPath(pRect);
        QPainterPath pHandle;
        pHandle.addRect(m_rLT);
        pHandle.addRect(m_rT);
        pHandle.addRect(m_rRT);
        pHandle.addRect(m_rL);
        pHandle.addRect(m_rR);
        pHandle.addRect(m_rLB);
        pHandle.addRect(m_rB);
        pHandle.addRect(m_rRB);
        painter->setPen(m_handlePen);
        painter->drawPath(pHandle);
    } else {
        m_borderPen.setBrush(QBrush(QColor::fromRgb(0, 125, 0)));
        QPainterPath pRect;
        pRect.addRect(rect());
        painter->setPen(m_borderPen);
        painter->drawPath(pRect);
    }

    //磁条吸附时两化吸附的边
    QPen  CitiePen=QPen(QColor::fromRgb(0, 255, 0),1,Qt::SolidLine);
    painter->setPen(CitiePen);
    //if(bMousePress)
    {
        if (bLeftCitie) {
            painter->setPen(CitiePen);
            //painter->drawLine(QPointF(rect().x(),rect().y()-100),QPointF(rect().x(),rect().bottom()+100));
            painter->drawLine(QPointF(rect().topLeft()),QPointF(rect().bottomLeft()));
        }
        if (bTopCitie) {
            painter->setPen(CitiePen);
            painter->drawLine(QPointF(rect().topLeft()),QPointF(rect().topRight()));
        }
        if (bRightCitie) {
            painter->setPen(CitiePen);
            painter->drawLine(QPointF(rect().topRight()),QPointF(rect().bottomRight()));
        }
        if (bBottomCitie) {
            painter->setPen(CitiePen);
            painter->drawLine(QPointF(rect().bottomLeft()),QPointF(rect().bottomRight()));
        }
    }
//    QPen(const QBrush &brush,
//            qreal width,
//            Qt::PenStyle style = Qt::SolidLine,
//            Qt::PenCapStyle cap = Qt::SquareCap,
//            Qt::PenJoinStyle join = Qt::BevelJoin);
//    QPen pen(Qt::green, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);


      //painter->drawLine(QPointF(rect().bottomLeft()),QPointF(rect().bottomRight()));
      painter->restore();
}

void eObject::mousePressEvent(QGraphicsSceneMouseEvent *event){
    if(Qt::LeftButton == event->button()) {

        m_hDir = handleDir(event->pos());
        m_pOrg = pointToParent(event->pos());
        m_rOrg = geometry();
        m_movable = true;
        bMousePress=true;

    }
    QGraphicsItem::mousePressEvent(event);
}

void eObject::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
    bMousePress=false;

    if(Qt::LeftButton == event->button()) {
        m_hDir = NONE;
        m_movable = false;
        bLeftCitie=false;
        bRightCitie=false;
        bTopCitie=false;
        bBottomCitie=false;
        m_keyPressId++;
        emit sigCiTie(false,m_keyPressId);

    }
    QGraphicsItem::mouseReleaseEvent(event);
}

void eObject::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
    if(false == m_movable) return;

    qreal  cx, cy, cw, ch;
    qreal  mx, my, mw, mh;
    QPointF ePos = pointToParent(event->pos());
    QPointF absoluteOfs = ePos - m_pOrg;

    mx = m_rOrg.x();
    my = m_rOrg.y();
    mw = m_w;
    mh = m_h;

    if(m_hDir != NONE) {
        prepareGeometryChange();

        switch(m_hDir) {
        case LT:
            cx = m_rOrg.x() + absoluteOfs.x();
            cy = m_rOrg.y() + absoluteOfs.y();
            if(m_rOrg.right()  - cx < m_handleLen) cx = m_rOrg.right()  - m_handleLen;
            if(m_rOrg.bottom() - cy < m_handleLen) cy = m_rOrg.bottom() - m_handleLen;
            mx = cx;
            my = cy;
            if(m_rLimit != INVALID_RECT) {
                if(mx < 0) mx = 0;
                if(my < 0) my = 0;
            }
            mw = m_rOrg.right()  - mx;
            mh = m_rOrg.bottom() - my;
            break;

        case T:
            cy = m_rOrg.y() + absoluteOfs.y();
            if(m_rOrg.bottom() - cy < m_handleLen) cy = m_rOrg.bottom() - m_handleLen;
            my = cy;
            if(m_rLimit != INVALID_RECT) {
                if(my < 0) my = 0;
            }
            mh = m_rOrg.bottom() - my;
            break;

        case RT:
            cy = m_rOrg.y()     + absoluteOfs.y();
            cw = m_rOrg.width() + absoluteOfs.x();
            if(m_rOrg.bottom() - cy < m_handleLen) cy = m_rOrg.bottom() - m_handleLen;
            if(cw < m_handleLen) cw = m_handleLen;
            my = cy;
            mw = cw;
            if(m_rLimit != INVALID_RECT) {
                if(my < 0) my = 0;
                if(mx + mw > m_rLimit.width()) mw = m_rLimit.width() - mx;
            }
            mh = m_rOrg.bottom() - my;
            break;

        case L:
            cx = m_rOrg.x() + absoluteOfs.x();
            if(m_rOrg.right() - cx < m_handleLen) cx = m_rOrg.right()  - m_handleLen;
            mx = cx;
            if(m_rLimit != INVALID_RECT) {
                if(mx < 0) mx = 0;
            }
            mw = m_rOrg.right() - mx;
            break;

        case R:
            cw = m_rOrg.width() + absoluteOfs.x();
            if(cw < m_handleLen) cw = m_handleLen;
            mw = cw;
            if(m_rLimit != INVALID_RECT) {
                if(mx + mw > m_rLimit.width()) mw = m_rLimit.width() - mx;
            }
            break;

        case LB:
            cx = m_rOrg.x() + absoluteOfs.x();
            ch = m_rOrg.height() + absoluteOfs.y();
            if(m_rOrg.right() - cx < m_handleLen) cx = m_rOrg.right()  - m_handleLen;
            if(ch < m_handleLen) ch = m_handleLen;
            mx = cx;
            if(m_rLimit != INVALID_RECT) {
               if(mx < 0) mx = 0;
            }
            mw = m_rOrg.right() - mx;
            mh = ch;
            if(m_rLimit != INVALID_RECT) {
                if(my + mh > m_rLimit.height()) mh = m_rLimit.height() - my;
            }
            break;

        case B:
            ch = m_rOrg.height() + absoluteOfs.y();
            if(ch < m_handleLen) ch = m_handleLen;
            mh = ch;
            if(m_rLimit != INVALID_RECT) {
                if(my + mh > m_rLimit.height()) mh = m_rLimit.height() - my;
            }
            break;

        case RB:
            cw = m_rOrg.width()  + absoluteOfs.x();
            ch = m_rOrg.height() + absoluteOfs.y();
            if(cw < m_handleLen) cw = m_handleLen;
            if(ch < m_handleLen) ch = m_handleLen;
            mw = cw;
            mh = ch;
            if(m_rLimit != INVALID_RECT) {
                if(mx + mw > m_rLimit.width())  mw = m_rLimit.width()  - mx;
                if(my + mh > m_rLimit.height()) mh = m_rLimit.height() - my;
            }
            break;

        default:
            break;
        }

        setPos(mx, my);
        m_w = mw;
        m_h = mh;
        adjustHandle();
        updateGeometry(m_rOrg);
        rectChanged(rect());
    } else {
        mx = m_rOrg.x() + absoluteOfs.x();
        my = m_rOrg.y() + absoluteOfs.y();
        if(m_rLimit != INVALID_RECT) {
            if(mx < 0) mx = 0;
            if(my < 0) my = 0;
            if(mx + mw > m_rLimit.width())  mx = m_rLimit.width()  - mw;
            if(my + mh > m_rLimit.height()) my = m_rLimit.height() - mh;
        }
        setPos(mx, my);
    }

    geometryChanged(geometry());
    if(bMousePress)
    {

        emit sigCiTie(true,m_hDir);

    }
}

void eObject::setBrightBianLeft(bool b){
qDebug()<<"eObject::setBrightBianLeft(bool)";
    //if(bMousePress)
//    {
//        bLeftCitie=b;

//    }
//    else {
//        bLeftCitie=false;
//    }
    bLeftCitie=b;
    updateGeometry();

}
void eObject::setBrightBianRight(bool b){
qDebug()<<"eObject::setBrightBianRight(bool)";
//    if(bMousePress)
//    {
//        bRightCitie=b;

//    }
//    else {
//        bRightCitie=false;
//    }
    bRightCitie=b;
    updateGeometry();

}
void eObject::setBrightBianTop(bool b){
qDebug()<<"eObject::setBrightBianTop(bool)";
//    if(bMousePress)
//    {
//        bTopCitie=b;

//    }
//    else {
//        bTopCitie=false;
//    }
    bTopCitie=b;
    updateGeometry();

}
void eObject::setBrightBianbottom(bool b){
qDebug()<<"eObject::setBrightBianbottom(bool)";
//    if(bMousePress)
//    {
//        bBottomCitie=b;

//    }
//    else {
//        bBottomCitie=false;
//    }
    bBottomCitie=b;
    updateGeometry();

}






void eObject::setGeometry(const QRectF &r){
    qDebug()<<"eObject::setGeometry(QRectF)";
    if(r != geometry()) {
        prepareGeometryChange();
        setPos(r.x(), r.y());
        m_w = r.width();
        m_h = r.height();
        adjustHandle();
        emit rectChanged(rect());
    }
}

void eObject::updateGeometry(){
    qDebug()<<"eObject::updateGeometry()";
    QRectF r = geometry();
    qreal x, y, w, h;
    x = r.x() - m_handleLen;
    y = r.y() - m_handleLen;
    w = r.width()  + m_handleLen * 2;
    h = r.height() + m_handleLen * 2;
    r = QRectF(x, y, w, h);
    if(nullptr != scene()) {
        scene()->update(r);
    }
    emit requestUpdate(r);
}

void eObject::updateGeometry(const QRectF &gC, const QRectF &gL){
    qDebug()<<"eObject::updateGeometry(QRectF,QRectF)";
    qreal x, y, w, h;
    QRectF gCur, gLast;
    x = gC.x() - m_handleLen;
    y = gC.y() - m_handleLen;
    w = gC.width()  + m_handleLen * 2;
    h = gC.height() + m_handleLen * 2;
    gCur = QRectF(x, y, w, h);
    x = gL.x() - m_handleLen;
    y = gL.y() - m_handleLen;
    w = gL.width()  + m_handleLen * 2;
    h = gL.height() + m_handleLen * 2;
    gLast = QRectF(x, y, w, h);
    qreal l = (gCur.left()   < gLast.left())   ? gCur.left()   : gLast.left();
    qreal t = (gCur.top()    < gLast.top())    ? gCur.top()    : gLast.top();
    qreal r = (gCur.right()  > gLast.right())  ? gCur.right()  : gLast.right();
    qreal b = (gCur.bottom() > gLast.bottom()) ? gCur.bottom() : gLast.bottom();
    QRectF gFlash = QRectF(QPointF(l, t), QPointF(r, b));
    if(nullptr != scene()) {
        scene()->update(gFlash);
    }
    emit requestUpdate(gFlash);
}

QPointF eObject::pointToParent(const QPointF &p){
    qDebug()<<"eObject::pointToParent(QPointF)";
    qreal px, py;
    px = p.x() + x();
    py = p.y() + y();
    return QPointF(px, py);
}

eObject::HANDLE_DIR eObject::handleDir(const QPointF &p){
    qDebug()<<"eObject::handleDir(QPointF)";
    HANDLE_DIR hDir = NONE;
    if(isSelected()) {
        if(m_rLT.contains(p))      hDir = LT;
        else if(m_rT.contains(p))  hDir = T;
        else if(m_rRT.contains(p)) hDir = RT;
        else if(m_rL.contains(p))  hDir = L;
        else if(m_rR.contains(p))  hDir = R;
        else if(m_rLB.contains(p)) hDir = LB;
        else if(m_rB.contains(p))  hDir = B;
        else if(m_rRB.contains(p)) hDir = RB;
    }
    return hDir;
}
//拖拽的虚线矩形
void eObject::adjustHandle(){
    qDebug()<<"eObject::adjustHandle()";
    const QRectF &r = rect();
    //左上角
    m_rLT = QRectF(r.left() - m_handleLen/2,
                   r.top() - m_handleLen/2,
                   m_handleLen, m_handleLen);
    //上中
    m_rT  = QRectF(r.center().x() - m_handleLen / 2,
                   r.top() - m_handleLen/2,
                   m_handleLen, m_handleLen);
    //右上角
    m_rRT = QRectF(r.right()-m_handleLen/2,
                   r.top() - m_handleLen/2,
                   m_handleLen, m_handleLen);
    //左中
    m_rL  = QRectF(r.left() - m_handleLen/2,
                   r.center().y() - m_handleLen / 2,
                   m_handleLen, m_handleLen);
    //右中
    m_rR  = QRectF(r.right()-m_handleLen/2,
                   r.center().y() - m_handleLen / 2,
                   m_handleLen, m_handleLen);
    //左下角
    m_rLB = QRectF(r.left() - m_handleLen/2,
                   r.bottom()-m_handleLen / 2,
                   m_handleLen, m_handleLen);
    //中下
    m_rB  = QRectF(r.center().x() - m_handleLen / 2,
                   r.bottom()-m_handleLen / 2,
                   m_handleLen, m_handleLen);
    //右下角
    m_rRB = QRectF(r.right()-m_handleLen / 2,
                   r.bottom()-m_handleLen / 2,
                   m_handleLen, m_handleLen);
}


QString eObject::getFileMd5(QString filePath){
    qDebug()<<"eObject::getFileMd5(QString)";
    QFile localFile(filePath);

    if (!localFile.open(QFile::ReadOnly))
    {
        qDebug() << "file open error.";
        return 0;
    }

    QCryptographicHash ch(QCryptographicHash::Md5);

    quint64 totalBytes = 0;
    quint64 bytesWritten = 0;
    quint64 bytesToWrite = 0;
    quint64 loadSize = 1024 * 4;
    QByteArray buf;

    totalBytes = localFile.size();
    bytesToWrite = totalBytes;

    while (1)
    {
        if(bytesToWrite > 0)
        {
            buf = localFile.read(qMin(bytesToWrite, loadSize));
            ch.addData(buf);
            bytesWritten += buf.length();
            bytesToWrite -= buf.length();
            buf.resize(0);
        }
        else
        {
            break;
        }

        if(bytesWritten == totalBytes)
        {
            break;
        }
    }

    localFile.close();
    QByteArray md5 = ch.result();
    QString strRes="";
    strRes.append(md5.toHex());
    return strRes;
}
