#ifndef BLOCKITEM_H
#define BLOCKITEM_H

#include "blockitempin.h"
#include <QTime>


class QAD_EXPORT BlockItem: public QGraphicsObject, public PropertyStorage
{
	friend class BlockView;
	friend class BlockItemPin;
	friend class DrawTools;
	Q_OBJECT
	Q_PROPERTY(double _thickness READ thickness WRITE setThickness DESIGNABLE false SCRIPTABLE false)
	Q_PROPERTY(QRectF _selRect READ selectionRect WRITE setSelectionRect DESIGNABLE false SCRIPTABLE false)
public:
	BlockItem(QGraphicsItem * parent = 0);
	~BlockItem();

	BlockItem * copy() const;
	BlockItemPin * addPin(BlockItemPin * pin, bool update_ = true);
	BlockItemPin * addPin(Qt::Alignment align, int bus_type, const QString & text, bool update_ = true);
	void removePin(BlockItemPin * pin);
	void addDecor(QGraphicsItem * item);
	void addDecor(QGraphicsItem & item);
	void removeDecor(QGraphicsItem * item);
	QVector<BlockItemPin * > takePins();
	void clearPins();
	void clearDecors();
	QVector<BlockItemPin * > pins() const;
	QList<QGraphicsItem * > decors() const {return decors_;}
	QList<BlockBusItem * > connectedBuses() const;
	BlockItemPin * pinByText(const QString & t) const;
	BlockItemPin * pinAtBus(BlockBusItem * bus) const;
	QColor color() const {return col;}
	void setColor(QColor c) {col = c; _resize(size());}
	QSizeF size() const {return g_main.rect().size();}
	QRectF sceneRect() const;
	qreal width() const {return size().width();}
	qreal height() const {return size().height();}
	int pinsMargin() const {return pins_margin;}
	void setSize(QSizeF s) {_resize(s);}
	void setSize(qreal w, qreal h) {setSize(QSizeF(w, h));}
	void setWidth(qreal w) {setSize(QSizeF(w, size().height()));}
	void setHeight(qreal h) {setSize(QSizeF(size().width(), h));}
	void setPinsMargin(int marg) {if (marg > 1 && marg < 256) pins_margin = marg; arrangePins();}

	QByteArray saveModel();
	void loadModel(const QByteArray & data);
	QByteArray save() const;
	void load(const QByteArray & data);
	void arrangePins();

	void removeBindings(const QString & bind_name);
	void removeBindingByProperty(const QString & prop_name);
	void addBinding(const QString & prop_name, const QString & bind_name);
	void applyBinding(const QString & bind_name, const QVariant & bind_value);
	void applyBindings(const PropertyStorage & bindings);
	void setBindings(const QList<QPair<QString, QString> > & bindings);
	QList<QPair<QString, QString> > getBindings();
	QString getBindName(const QString & prop_name) const;
	QStringList getBindNames() const;
	QStringList getBindProps() const;

	enum {Type = UserType + 1};

protected:
	void _resize(QSizeF s);
	void _moveToTop(bool only_decors = false);
	int type() const {return Type;}
	QRectF boundingRect() const;
	void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
	void hoverEnterEvent(QGraphicsSceneHoverEvent * event);
	void hoverLeaveEvent(QGraphicsSceneHoverEvent * event);
	double left() const {return boundingRect().left();}
	double right() const {return boundingRect().right();}
	double top() const {return boundingRect().top();}
	double bottom() const {return boundingRect().bottom();}
	void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
	QVariant itemChange(GraphicsItemChange change, const QVariant & value);

	QGraphicsRectItem g_main, g_selection;
	int pins_margin;
	QColor col;
	QMap<Qt::Alignment, QVector<BlockItemPin * > > pins_;
	QList<QGraphicsItem * > decors_;
	QList<QPair<QString, QString> > prop_bindings; // <property_name, binding_name>

private:
	double thickness() const;
	void setThickness(double w);
	QRectF selectionRect() const;
	void setSelectionRect(const QRectF & r);

	QPropertyAnimation anim_thick, anim_sel;
	QTime t_sel;

signals:
	void blockHoverEnter(BlockItem * b);
	void blockHoverLeave(BlockItem * b);
};


inline QDataStream & operator <<(QDataStream & s, const BlockItemPin * p) {
	ChunkStream cs;
	cs << cs.chunk(1, int(p->alignment())) << cs.chunk(2, p->busType()) << cs.chunk(3, p->text()) << cs.chunk(4, p->toolTip());
	s << cs.data(); return s;}
inline QDataStream & operator >>(QDataStream & s, BlockItemPin *& p) {
	ChunkStream cs(s);
	p = new BlockItemPin();
	while (!cs.atEnd()) {
		switch (cs.read()) {
			case 1: p->setAlignment((Qt::Alignment)cs.getData<int>()); break;
			case 2: p->setBusType(cs.getData<int>()); break;
			case 3: p->setText(cs.getData<QString>()); break;
			case 4: p->setToolTip(cs.getData<QString>()); break;
		}
	}
	return s;
}


inline QDataStream & operator <<(QDataStream & s, const BlockItem * b) {s << b->save(); return s;}
inline QDataStream & operator >>(QDataStream & s, BlockItem *& b) {
	QByteArray ba; s >> ba;
	b = new BlockItem();
	b->load(ba);
	return s;
}


#endif // BLOCKITEM_H
