/*
    QAD - Qt ADvanced

    Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef BLOCKITEM_H
#define BLOCKITEM_H

#include "blockitempin.h"
#include "qad_blockview_export.h"

#include <QElapsedTimer>
#include <pivaluetree.h>


class QAD_BLOCKVIEW_EXPORT BlockItem
	: public QGraphicsObject
	, public PropertyStorage {
	friend class BlockView;
	friend class BlockItemPin;
	friend class DrawTools;
	friend class BlockEditor;
	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;
	QVector<BlockItemPin *> pinsOnSide(Qt::Alignment al) 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);
	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);
	void setHeight(qreal h);
	void setPinsMargin(int marg);

	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);
	const QList<QPair<QString, QString>> & getBindings() const;
	QString getBindName(const QString & prop_name) const;
	QStringList getBindNames() const;
	QStringList getBindProps() const;

	PIValueTree & values() { return value_tree; }

	enum {
		Type = UserType + 1
	};

protected:
	void _resize(QSizeF s);
	void _moveToTop(bool only_decors = false);
	int type() const { return Type; }
	QRectF boundingRect() const;
	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 = nullptr) {}
	QVariant itemChange(GraphicsItemChange change, const QVariant & value);
	void setHovered(bool yes);
	void procDecorShowLogic();

	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;
	QElapsedTimer t_sel;
	PIValueTree value_tree;
	bool is_hovered = false, is_blockeditor = false;

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


QDataStream & operator<<(QDataStream & s, const BlockItemPin * p);
QDataStream & operator>>(QDataStream & s, BlockItemPin *& p);


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
