#ifndef GRAPHICSBASEITEM_H
#define GRAPHICSBASEITEM_H

#include "itemControlHandle.h"

#include <QObject>
#include <QGraphicsItem>
#include <QGraphicsSceneMouseEvent>
#include <QPen>

//基类采用模板形式，QGraphicsItem是默认值,也可以是别的类型，比如QGraphicsItemGroup，这样不同的基类继承可以共用一些高层的行为定义
template <typename BaseType = QGraphicsItem>
class AbstractShapeType : public BaseType
{
public:
    explicit AbstractShapeType(QGraphicsItem *parent = 0)
        : BaseType(parent)
    {
        m_pen = QPen(Qt::NoPen);
        m_brush = QBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8));
        m_dWidth = m_dHeight = 0;
        m_pMovingCopy = nullptr;
    }

    virtual ~AbstractShapeType()
    {
        for (size_t i = 0; i < m_vecHanle.size(); i++)
        {
            ItemControlHandle* pHandle = m_vecHanle[i];
            if (pHandle)
            {
                delete pHandle;
                pHandle = nullptr;
            }
        }
    }

public:
    QPen pen() { return m_pen; }
    void setPen(const QPen &pen) { m_pen = pen; }
    QColor penColor() { return m_pen.color(); }
    void setPenColor(const QColor &color) { m_pen.setColor(color); }

    QBrush brush() { return m_brush; }
    void setBrush(const QBrush &brush) { m_brush = brush; }
    QColor brushColor() { return m_brush.color(); }
    void setBrushColor(const QColor &color) { m_brush.setColor(color); }

    double width() { return m_dWidth; }
    void setWidth(double width)
    {
        m_dWidth = width;
        updateCoordinate();
    }

    double height() { return m_dHeight; }
    void setHeight(double height)
    {
        m_dHeight = height;
        updateCoordinate();
    }

    int collidesWithHandle(const QPointF& point)
    {
        for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
        {
            QPointF pt = (*it)->mapFromScene(point);
            if((*it)->contains(pt))
                return (*it)->getTag();
        }
        return HandleTag::H_none;
    }

    //移动副本相关
    virtual void createMovingCopy() {};
    virtual void removeMovingCopy() {};
    virtual void moveMovingCopy(const QPointF&) {};

    virtual void resize(int,double, double, const QPointF&) {}
    virtual void move(const QPointF& point) { Q_UNUSED(point); }

    virtual void updateCoordinate() {}

    //handle相关
    virtual void setHandleVisible(bool bVisible)
    {
        for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
        {
            if(bVisible)
                (*it)->show();
            else
                (*it)->hide();
        }
    }
    virtual QPointF getSymmetricPointPos(int nHandle) //获取对称点的坐标位置，缩放的时候需要以对称点为锚点
    {
        QPointF pt;
        //编号从1开始，因此下标需要-1
        switch (nHandle)
        {
        case H_leftTop:
            pt = m_vecHanle.at(H_rightBottom - 1)->pos();
            break;
        case H_top:
            pt = m_vecHanle.at(H_bottom - 1)->pos();
            break;
        case H_rightTop:
            pt = m_vecHanle.at(H_leftBottom - 1)->pos();
            break;
        case H_right:
            pt = m_vecHanle.at(H_left - 1)->pos();
            break;
        case H_rightBottom:
            pt = m_vecHanle.at(H_leftTop - 1)->pos();
            break;
        case H_bottom:
            pt = m_vecHanle.at(H_top - 1)->pos();
            break;
        case H_leftBottom:
            pt = m_vecHanle.at(H_rightTop - 1)->pos();
            break;
        case H_left:
            pt = m_vecHanle.at(H_right - 1)->pos();
            break;
        default:
            break;
        }

        return pt;
    }
    virtual void updateHandles()
    {
        const QRectF& boundRect = this->boundingRect();
        for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
        {
            switch ((*it)->getTag()) {
            case H_leftTop:
                (*it)->move(boundRect.x(), boundRect.y());
                break;
            case H_top:
                (*it)->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y());
                break;
            case H_rightTop:
                (*it)->move(boundRect.x() + boundRect.width(), boundRect.y());
                break;
            case H_right:
                (*it)->move(boundRect.x() + boundRect.width(), boundRect.y() + boundRect.height() * 0.5);
                break;
            case H_rightBottom:
                (*it)->move(boundRect.x() + boundRect.width(), boundRect.y() + boundRect.height());
                break;
            case H_bottom:
                (*it)->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y() + boundRect.height());
                break;
            case H_leftBottom:
                (*it)->move(boundRect.x(), boundRect.y() + boundRect.height());
                break;
            case H_left:
                (*it)->move(boundRect.x(), boundRect.y() + boundRect.height() * 0.5);
                break;
            default:
                break;
            }
        }
    }

protected:
    virtual QRectF boundingRect() const { return m_boundingRect; }
    virtual QPainterPath shape()
    {
        QPainterPath path;
        return path;
    }

protected:
    QPen     m_pen;
    QBrush   m_brush;
    double   m_dWidth;
    double   m_dHeight;
    QRectF   m_boundingRect;

    QGraphicsPathItem*  m_pMovingCopy; //图元移动时的副本
    QPointF             m_movingIniPos; //移动副本开始移动初始点

    QVector<ItemControlHandle*> m_vecHanle;
};

class GraphicsBaseItem : public QObject, public AbstractShapeType<QGraphicsItem>
{
     Q_OBJECT

public:
    GraphicsBaseItem(QGraphicsItem *parent);
    virtual ~GraphicsBaseItem();

    virtual void createMovingCopy();
    virtual void removeMovingCopy();
    virtual void moveMovingCopy(const QPointF&);

protected:
    virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange, const QVariant&);
    virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent*);
};

#endif
