#ifndef GRAPHICSBASEITEM_H
#define GRAPHICSBASEITEM_H

#include "itemControlHandle.h"

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

enum ShapeType
{
    T_undefined,
    T_item,
    T_group
};

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

    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 createOperationCopy() {}
    virtual void removeOperationCopy() {}
    virtual void moveOperationCopy(const QPointF&) {}
    virtual void rotateOperationCopy(const double&) {}

    virtual void resize(int,double, double, const QPointF&) {}
    virtual void move(const QPointF&) {}
    virtual void editShape(int, const QPointF&) {}

    virtual void updateCoordinate() {}

    //handle相关
    virtual int handleCount() { return m_vecHanle.count(); }
    virtual ItemControlHandle* getHandle(int nHandle)
    {
        ItemControlHandle* handle = nullptr;
        for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
        {
            if((*it)->getTag() == nHandle)
            {
                handle = (*it);
                return handle;
            }
        }
        return 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()
    {
        int nMargin = 5;
        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() - nMargin, boundRect.y() - nMargin);
                break;
            case H_top:
                (*it)->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y() - nMargin);
                break;
            case H_rightTop:
                (*it)->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() - nMargin);
                break;
            case H_right:
                (*it)->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() + boundRect.height() * 0.5 + nMargin);
                break;
            case H_rightBottom:
                (*it)->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() + boundRect.height() + nMargin);
                break;
            case H_bottom:
                (*it)->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y() + boundRect.height()+ nMargin);
                break;
            case H_leftBottom:
                (*it)->move(boundRect.x() - nMargin, boundRect.y() + boundRect.height() + nMargin);
                break;
            case H_left:
                (*it)->move(boundRect.x() - nMargin, boundRect.y() + boundRect.height() * 0.5);
                break;
            case H_rotate_leftTop:
            {
                ItemControlHandle* handle = getHandle(H_leftTop);
                if(handle)
                {
                    int nSize = handle->getSize();
                    QPointF pt = handle->pos();
                    (*it)->move(pt.x() - nSize - 1, pt.y() - nSize - 1);
                }
                else
                    (*it)->setVisible(false);

                break;
            }
            case H_rotate_rightTop:
            {
                ItemControlHandle* handle = getHandle(H_rightTop);
                if(handle)
                {
                    int nSize = handle->getSize();
                    QPointF pt = handle->pos();
                    (*it)->move(pt.x() + nSize + 1, pt.y() - nSize - 1);
                }
                else
                    (*it)->setVisible(false);

                break;
            }
            case H_rotate_rightBottom:
            {
                ItemControlHandle* handle = getHandle(H_rightBottom);
                if(handle)
                {
                    int nSize = handle->getSize();
                    QPointF pt = handle->pos();
                    (*it)->move(pt.x() + nSize + 1, pt.y() + nSize + 1);
                }
                else
                    (*it)->setVisible(false);

                break;
            }
            case H_rotate_leftBottom:
            {
                ItemControlHandle* handle = getHandle(H_leftBottom);
                if(handle)
                {
                    int nSize = handle->getSize();
                    QPointF pt = handle->pos();
                    (*it)->move(pt.x() - nSize - 1, pt.y() + nSize + 1);
                }
                else
                    (*it)->setVisible(false);

                break;
            }
            default:
                break;
            }
        }

        m_boundingRect_selected = boundRect.adjusted(-nMargin, -nMargin, nMargin, nMargin);
    }

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

protected:
    ShapeType m_type;
    QPen      m_pen;
    QBrush    m_brush;
    double    m_dWidth;
    double    m_dHeight;
    QRectF    m_boundingRect;
    QRectF    m_boundingRect_selected;//选中矩形框

    QGraphicsPathItem*  m_pOperationCopy; //图元移动和旋转时的操作副本
    QPointF             m_movingIniPos; //移动副本开始移动初始点

    QVector<ItemControlHandle*> m_vecHanle;
};

typedef AbstractShapeType<QGraphicsItem> AbstractShape;

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

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

    virtual void createOperationCopy();
    virtual void removeOperationCopy();
    virtual void moveOperationCopy(const QPointF&);
    virtual void rotateOperationCopy(const double&);
    //多边形、线段等点选创建的对象需要的函数
    virtual void addPoint(const QPointF&) {}
    virtual bool endDrawing() { return true; }

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

#endif
