#include "screenunit.h"
#include "expertwin.h"
#include <QDirIterator>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QJsonArray>
#include <QJsonObject>
#include <QLabel>
#include <QPainter>
#include <QSpinBox>

#include <QMouseEvent>

ScreenUnit::ScreenUnit(ExpertWin *expertWin, const QString &name, int x, int y, int w, int h, QWidget *parent) : QWidget{parent}, expertWin{expertWin}, name{name}, mX{x}, mY{y}, mW{w}, mH{h} {
    setGeometry(x, y, w, h);
    setMouseTracking(true);
    auto font = this->font();
    font.setPixelSize(12);
    setFont(font);

    mSidePen.setCapStyle(Qt::FlatCap);
    mSidePen.setDashPattern(QVector<qreal>{2,2});
}

void ScreenUnit::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setPen(mSidePen);
    painter.drawRect(QRectF(0.5, 0.5, width()-1, height()-1));
    painter.drawText(2, 16, name);
    painter.drawText(2, 32, "位置: "+QString::number(mX)+", "+QString::number(mY));
    painter.drawText(2, 48, "大小: "+QString::number(mW)+" x "+QString::number(mH));
    //磁条吸附时两化吸附的边
    static QPen snapPen(QColor(0x00ff00), 2);
    painter.setPen(snapPen);
    if(mLRSnap==1) painter.drawLine(QPointF(1, 0), QPointF(1, height()));
    else if(mLRSnap==2) painter.drawLine(QPointF(width()-1, 0), QPointF(width()-1, height()));
    if(mTBSnap==1) painter.drawLine(QPointF(0, 1), QPointF(width(), 1));
    else if(mTBSnap==2) painter.drawLine(QPointF(0, height()-1), QPointF(width(), height()-1));
}

void ScreenUnit::setFrmSec(const QPoint &pos) {
    if(isMaximized()) return;
    if(pos.y()<8) {
        if(pos.x()<16) setFrmSecIfNeed(Qt::TopLeftSection, Qt::SizeFDiagCursor);
        else if(pos.x()<width()-16) setFrmSecIfNeed(Qt::TopSection, Qt::SizeVerCursor);
        else setFrmSecIfNeed(Qt::TopRightSection, Qt::SizeBDiagCursor);
    } else if(pos.y()>=height()-8) {
        if(pos.x()<16) setFrmSecIfNeed(Qt::BottomLeftSection, Qt::SizeBDiagCursor);
        else if(pos.x()<width()-16) setFrmSecIfNeed(Qt::BottomSection, Qt::SizeVerCursor);
        else setFrmSecIfNeed(Qt::BottomRightSection, Qt::SizeFDiagCursor);
    } else if(pos.x()<8) {
        if(pos.y()<16) setFrmSecIfNeed(Qt::TopLeftSection, Qt::SizeFDiagCursor);
        else if(pos.y()<height()-16) setFrmSecIfNeed(Qt::LeftSection, Qt::SizeHorCursor);
        else setFrmSecIfNeed(Qt::BottomLeftSection, Qt::SizeBDiagCursor);
    } else if(pos.x()>=width()-8) {
        if(pos.y()<16) setFrmSecIfNeed(Qt::TopRightSection, Qt::SizeBDiagCursor);
        else if(pos.y()<height()-16) setFrmSecIfNeed(Qt::RightSection, Qt::SizeHorCursor);
        else setFrmSecIfNeed(Qt::BottomRightSection, Qt::SizeFDiagCursor);
    } else setFrmSecIfNeed(Qt::TitleBarArea, Qt::SizeAllCursor);
}
void ScreenUnit::mousePressEvent(QMouseEvent *e) {
    QWidget::mousePressEvent(e);
    if(e->button() != Qt::LeftButton) return;
    setFrmSec(e->pos());
    if(mFrmSec==Qt::TitleBarArea || mFrmSec==Qt::TopSection || mFrmSec==Qt::LeftSection || mFrmSec==Qt::TopLeftSection) mPressRel = mPressRel = pos() - e->globalPos();
    else if(mFrmSec==Qt::BottomRightSection) mPressRel = QPoint(width() - e->globalX(), height() - e->globalY());
    else if(mFrmSec==Qt::RightSection      ) mPressRel = QPoint(width() - e->globalX(), height()               );
    else if(mFrmSec==Qt::BottomSection     ) mPressRel = QPoint(width()               , height() - e->globalY());
    else if(mFrmSec==Qt::TopRightSection   ) mPressRel = geometry().topRight() - e->globalPos();
    else if(mFrmSec==Qt::BottomLeftSection ) mPressRel = geometry().bottomLeft() - e->globalPos();
    else if(mFrmSec==Qt::NoSection) mPressRel.setX(INT_MIN);
    if(mPressRel.x()!=INT_MIN) {
        mOtherEles.clear();
        auto parent = this->parentWidget();
        if(0 == parent) return;
        auto items = parent->children();
        foreach(auto item, items) {
            if(item==this) continue;
            auto ele = static_cast<ScreenUnit*>(item);
            mOtherEles.append(ele);
        }
    }
}

void ScreenUnit::mouseReleaseEvent(QMouseEvent *event) {
    QWidget::mouseReleaseEvent(event);
    if(Qt::LeftButton == event->button()) {
        mPressRel.setX(INT_MIN);
        clearSnap();
        foreach(auto ele, mOtherEles) ele->clearSnap();
    }
}
#define SnapSpace 6
void ScreenUnit::mouseMoveEvent(QMouseEvent *e){
    if(! (e->buttons() & Qt::LeftButton)) {
        setFrmSec(e->pos());
        return;
    }
    if(mFrmSec==Qt::NoSection || mPressRel.x()==INT_MIN) return;
    auto mousePos = e->globalPos();
    auto dstHor = mPressRel.x() + mousePos.x();
    auto dstVer = mPressRel.y() + mousePos.y();
    mLRSnap = mTBSnap = 0;
    foreach(auto ele, mOtherEles) ele->clearSnap();
    if(mFrmSec==Qt::TitleBarArea) {
        dstHor = qBound(0, dstHor, expertWin->screenWidth - width());
        dstVer = qBound(0, dstVer, expertWin->screenHeight - height());
        if(dstHor==0) mLRSnap = 1;
        else if(dstHor==expertWin->screenWidth - width()) mLRSnap = 2;
        if(dstVer==0) mTBSnap = 1;
        else if(dstVer==expertWin->screenHeight - height()) mTBSnap = 2;
        if(mLRSnap==0) foreach(ScreenUnit *ele, mOtherEles) {//左右
            if(abs(dstHor - ele->x()) < SnapSpace && ele->x() <= expertWin->screenWidth - width()) {
                dstHor = ele->x();
                mLRSnap = 1;
                ele->mLRSnap = 1;
                ele->update();
                break;
            }
            auto eleRight = ele->x() + ele->width();
            if(abs(dstHor - eleRight) < SnapSpace && eleRight <= expertWin->screenWidth - width()) {
                dstHor = eleRight;
                mLRSnap = 1;
                ele->mLRSnap = 2;
                ele->update();
                break;
            }
            auto right = dstHor + width();
            if(abs(right - ele->x()) < SnapSpace && ele->x() - width() >= 0) {
                dstHor = ele->x() - width();
                mLRSnap = 2;
                ele->mLRSnap = 1;
                ele->update();
                break;
            }
            if(abs(right - eleRight) < SnapSpace && eleRight - width() >= 0) {
                dstHor = eleRight - width();
                mLRSnap = 2;
                ele->mLRSnap = 2;
                ele->update();
                break;
            }
        }
        if(mTBSnap==0) foreach(ScreenUnit *ele, mOtherEles) {//上下
            if(abs(dstVer-ele->y()) < SnapSpace && ele->y() <= expertWin->screenHeight - height()) {
                dstVer = ele->y();
                mTBSnap = 1;
                ele->mTBSnap = 1;
                ele->update();
                break;
            }
            auto eleBtm = ele->y() + ele->height();
            if(abs(dstVer - eleBtm) < SnapSpace && eleBtm <= expertWin->screenHeight - height()) {
                dstVer = eleBtm;
                mTBSnap = 1;
                ele->mTBSnap = 2;
                ele->update();
                break;
            }
            auto btm = dstVer + height();
            if(abs(btm - ele->y()) < SnapSpace && ele->y() - height() >= 0) {
                dstVer = ele->y() - height();
                mTBSnap = 2;
                ele->mTBSnap = 1;
                ele->update();
                break;
            }
            if(abs(btm - eleBtm) < SnapSpace && eleBtm - height() >= 0) {
                dstVer = eleBtm - height();
                mTBSnap = 2;
                ele->mTBSnap = 2;
                ele->update();
                break;
            }
        }
        move(dstHor, dstVer);
        mX = qRound(dstHor / expertWin->rate);
        mY = qRound(dstVer / expertWin->rate);
        update();
    } else if(mFrmSec==Qt::BottomRightSection) {
        if(dstHor < m_handleLen) dstHor = m_handleLen;
        if(dstVer < m_handleLen) dstVer = m_handleLen;
        if(expertWin->screenWidth>0 && expertWin->screenHeight>0) {
            dstHor = qMin(dstHor, expertWin->screenWidth - x());
            dstVer = qMin(dstVer, expertWin->screenHeight - y());
        }
        resize(dstHor, dstVer);
        mW = qRound(dstHor / expertWin->rate);
        mH = qRound(dstVer / expertWin->rate);
    } else if(mFrmSec==Qt::RightSection) {
        if(dstHor < m_handleLen) dstHor = m_handleLen;
        if(expertWin->screenWidth>0 && expertWin->screenHeight>0) dstHor = qMin(dstHor, expertWin->screenWidth - x());
        auto right = x() + dstHor;
        if(right < expertWin->screenWidth-8) foreach(ScreenUnit *ele, mOtherEles) {//左右
            if(abs(right - ele->x()) < SnapSpace) {
                dstHor = ele->x() - x();
                mLRSnap = 2;
                ele->mLRSnap = 1;
                ele->update();
                break;
            }
            auto eleRight = ele->x() + ele->width();
            if(abs(right - eleRight) < SnapSpace) {
                dstHor = eleRight - x();
                mLRSnap = 2;
                ele->mLRSnap = 2;
                ele->update();
                break;
            }
        }
        resize(dstHor, mPressRel.y());
        mW = qRound(dstHor / expertWin->rate);
    } else if(mFrmSec==Qt::BottomSection) {
        if(dstVer < m_handleLen) dstVer = m_handleLen;
        if(expertWin->screenWidth>0 && expertWin->screenHeight>0) dstVer = qMin(dstVer, expertWin->screenHeight - y());
        auto btm = y() + dstVer;
        if(btm < expertWin->screenHeight-8) foreach(ScreenUnit *ele, mOtherEles) {//上下
            auto eleBtm = ele->y() + ele->height();
            if(abs(btm - ele->y()) < SnapSpace) {
                dstVer = ele->y() - y();
                mTBSnap = 2;
                ele->mTBSnap = 1;
                ele->update();
                break;
            }
            if(abs(btm - eleBtm) < SnapSpace) {
                dstVer = eleBtm - y();
                mTBSnap = 2;
                ele->mTBSnap = 2;
                ele->update();
                break;
            }
        }
        resize(mPressRel.rx(), dstVer);
        mH = qRound(dstVer / expertWin->rate);
    } else {
        auto geo = geometry();
        if(mFrmSec==Qt::LeftSection) {
            dstHor = qMin(dstHor, geo.right() - m_handleLen);
            if(dstHor < 0) dstHor = 0;
            if(dstHor > 8) foreach(ScreenUnit *ele, mOtherEles) {//左右
                if(abs(dstHor - ele->x()) < SnapSpace) {
                    dstHor = ele->x();
                    mLRSnap = 1;
                    ele->mLRSnap = 1;
                    ele->update();
                    break;
                }
                auto eleRight = ele->x() + ele->width();
                if(abs(dstHor - eleRight) < SnapSpace) {
                    dstHor = eleRight;
                    mLRSnap = 1;
                    ele->mLRSnap = 2;
                    ele->update();
                    break;
                }
            }
            geo.setLeft(dstHor);
        } else if(mFrmSec==Qt::TopSection) {
            dstVer = qMin(dstVer, geo.bottom() - m_handleLen);
            if(dstVer < 0) dstVer = 0;
            if(dstVer > 8) foreach(ScreenUnit *ele, mOtherEles) {//上下
                if(abs(dstVer - ele->y()) < SnapSpace) {
                    dstVer = ele->y();
                    mTBSnap = 1;
                    ele->mTBSnap = 1;
                    ele->update();
                    break;
                }
                auto eleBtm = ele->y() + ele->height();
                if(abs(dstVer - eleBtm) < SnapSpace) {
                    dstVer = eleBtm;
                    mTBSnap = 1;
                    ele->mTBSnap = 2;
                    ele->update();
                    break;
                }
            }
            geo.setTop(dstVer);
        } else if(mFrmSec==Qt::TopLeftSection) {
            dstHor = qMin(dstHor, geo.right() - m_handleLen);
            dstVer = qMin(dstVer, geo.bottom() - m_handleLen);
            if(dstHor < 0) dstHor = 0;
            if(dstVer < 0) dstVer = 0;
            geo.setLeft(dstHor);
            geo.setTop(dstVer);
        } else if(mFrmSec==Qt::TopRightSection) {
            dstHor = qMax(dstHor, geo.x() + m_handleLen);
            dstVer = qMin(dstVer, geo.bottom() - m_handleLen);
            if(dstHor > expertWin->screenWidth) dstHor = expertWin->screenWidth;
            if(dstVer < 0) dstVer = 0;
            geo.setRight(dstHor);
            geo.setTop(dstVer);
        } else if(mFrmSec==Qt::BottomLeftSection) {
            dstHor = qMin(dstHor, geo.right() - m_handleLen);
            dstVer = qMax(dstVer, geo.y() + m_handleLen);
            if(dstHor < 0) dstHor = 0;
            if(dstVer > expertWin->screenHeight) dstVer = expertWin->screenHeight;
            geo.setLeft(dstHor);
            geo.setBottom(dstVer);
        }
        setGeometry(geo);
        mX = qRound(geo.x() / expertWin->rate);
        mY = qRound(geo.y() / expertWin->rate);
        mW = qRound(geo.width() / expertWin->rate);
        mH = qRound(geo.height() / expertWin->rate);
    }
}
void ScreenUnit::leaveEvent(QEvent *) {
    setFrmSecIfNeed(Qt::NoSection, Qt::ArrowCursor);
    mPressRel.setX(INT_MIN);
}

void ScreenUnit::setFrmSecIfNeed(Qt::WindowFrameSection frmSec, Qt::CursorShape cursor) {
    if(mFrmSec==frmSec) return;
    mFrmSec = frmSec;
    if(cursor==Qt::ArrowCursor) unsetCursor();
    else setCursor(cursor);
}

void ScreenUnit::clearSnap() {
    if(mLRSnap==0 && mTBSnap==0) return;
    mLRSnap = mTBSnap = 0;
    update();
}
