#ifndef BLOCKVIEW_H
#define BLOCKVIEW_H

#include <QGraphicsView>
#include <QGraphicsScene>
#include <QPainter>
#include <QPixmap>
#include <QMouseEvent>
#include <QDebug>
#include <QTime>
#include <QPropertyAnimation>
#include "blockviewwavetrace.h"
#include "blockbusitem.h"

QT_BEGIN_HEADER

QT_BEGIN_NAMESPACE

class BlockView: public QGraphicsView
{
	Q_OBJECT
	Q_ENUMS(SelectionMode)

	Q_PROPERTY(bool gridVisible READ isGridVisible WRITE setGridVisible)
	Q_PROPERTY(bool snapToGrid READ isSnapToGrid WRITE setSnapToGrid)
	Q_PROPERTY(QPen gridPen READ gridPen WRITE setGridPen)
	Q_PROPERTY(double gridStep READ gridStep WRITE setGridStep)
	Q_PROPERTY(double gridPointsWidth READ gridPointsWidth WRITE setGridPointsWidth)
	Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
	Q_PROPERTY(bool postMoveConnect READ isPostMoveConnectEnabled WRITE setPostMoveConnectEnabled)
	Q_PROPERTY(bool connectByMouse READ isConnectByMouseEnabled WRITE setConnectByMouseEnabled)
	Q_PROPERTY(bool navigationEnabled READ isNavigationEnabled WRITE setNavigationEnabled)
	Q_PROPERTY(bool traceConsiderBuses READ isTraceConsiderBuses WRITE setTraceConsiderBuses)
	Q_PROPERTY(bool pinMulticonnect READ isPinMulticonnectEnabled WRITE setPinMulticonnectEnabled)
	Q_PROPERTY(bool miniMap READ isMiniMapEnabled WRITE setMiniMapEnabled)
	
	Q_PROPERTY(double _thumb READ _thumb WRITE _setThumb DESIGNABLE false SCRIPTABLE false)

public:
	BlockView(QWidget * parent = 0);
	BlockView(QGraphicsScene * scene, QWidget * parent = 0);
	~BlockView();

	enum SelectionMode {
		NoSelection,
		SingleSelection,
		MultiSelection
	};
	
	QPen gridPen() const {return grid_pen;}
	bool isGridVisible() const {return grid_visible;}
	bool isSnapToGrid() const {return grid_snap;}
	bool isPostMoveConnectEnabled() const {return pm_connect;}
	bool isNavigationEnabled() const {return navigation;}
	bool isConnectByMouseEnabled() const {return m_connect;}
	bool isTraceConsiderBuses() const {return m_trace_with_buses;}
	bool isPinMulticonnectEnabled() const {return m_pin_mc;}
	bool isMiniMapEnabled() const {return minimap;}
	double gridStep() const {return grid_step;}
	double gridPointsWidth() const {return grid_points;}
	SelectionMode selectionMode() const {return smode;}
	void setSelectionMode(SelectionMode mode) {smode = mode;}
	
	void addItems(QList<QGraphicsItem * > items) {foreach (QGraphicsItem * i, items) addItem(i);}
	QList<BlockBusItem * > buses() const;
	QList<BlockBusItem * > wrongConnectedBuses() const;
	QList<BlockItem * > blocks() const;
	QList<QGraphicsItem * > decors() const;
	BlockBusItem * connectionBus(BlockItem * b0, BlockItem * b1) const;
	QList<BlockBusItem * > connectionBuses(BlockItem * b0, BlockItem * b1) const;
	bool connectPins(BlockItemPin * p0, BlockItemPin * p1);

protected:
	void _init();
	void _updateBack();
	bool eventFilter(QObject * o, QEvent * e);
	void stopTimer(int & tid);
	void restartTimer(int & tid, int msecs);
	void timerEvent(QTimerEvent * e);
	void wheelEvent(QWheelEvent * event);
	void mousePressEvent(QMouseEvent * event);
	void mouseMoveEvent(QMouseEvent * event);
	void keyPressEvent(QKeyEvent * event);
	void resizeEvent(QResizeEvent * event);
	void scrollContentsBy(int dx, int dy);
	void drawBackground(QPainter * painter, const QRectF & rect);
	void drawThumb();
	void drawSceneThumb();
	void thumbHide();
	void thumbShow();
	void restoreSelState();
	void saveSelState();
	void applySelRect(QGraphicsSceneMouseEvent * me);
	void applyGridStep();
	void trace(QPointF scene_pos_from, QPointF scene_pos_to, BlockBusItem * bus);
	void clearBusStates();
	void matchBus();
	bool connectTmpToBus(BlockBusItem* bus);
	void markPins(int bus_type);
	void unmarkPins(bool to_normal = false);
	void moveBuses(const QList<QGraphicsItem * > & items, QPointF dp);
	double _thumb() const {return _talpha;}
	void scrollFromThumb();
	
	virtual void loadBus(BlockBusItem * bus) {}
	virtual void copyBlocks(QList<BlockItem * > items, QPointF offset) {}
	
	QGraphicsScene * scene_;
	QGraphicsRectItem sel_rect;
	QGraphicsItem * mm_ci;
	QList<QGraphicsItem * > sel_items;
	QList<BlockItem * > copy_items;
	BlockBusItem tmp_bus, * match_bus, * bus_from;
	BlockViewWavetrace wavetrace;
	QPoint press_point, screen_point, thumb_press;
	QPointF scene_point, trace_from, last_trace_from, trace_to, copy_dp;
	QRect thumb_sr, thumb_vr;
	QSizeF thumb_size;
	QPen grid_pen;
	SelectionMode smode;
	QImage im_scene;
	QWidget widget_thumb;
	Qt::KeyboardModifiers mm_mods;
	QPropertyAnimation thumb_anim;
	int timer_thumb, thumb_hide_delay;
	bool mm_drag, new_bus, new_branch, moved, mm_cancel, iconnect, mm_copy, mm_thumb;
	bool grid_visible, grid_snap, pm_connect, navigation, m_connect, m_trace_with_buses, m_pin_mc, minimap;
	double grid_step, grid_points, cur_scl, _talpha, thumb_scl;

protected slots:
	void getPinMC(bool * v) {if (v) *v = m_pin_mc;}
	void adjustThumb();
	void newBranch(BlockBusItem * item);
	void newBranchTrace(BlockBusItem * item, QPointF to);
	void newBranchAccept(BlockBusItem * item);
	void newBranchCancel();
	void removedBus(QObject * o);
	void removedBlock(QObject * o);
	void removeJunk();
	void _setThumb(double v);

public slots:
	void setGridPen(const QPen & pen) {grid_pen = pen; _updateBack();}
	void setGridVisible(bool yes) {grid_visible = yes; _updateBack();}
	void setSnapToGrid(bool yes) {grid_snap = yes;}
	void setGridStep(double step) {grid_step = step; applyGridStep(); _updateBack();}
	void setGridPointsWidth(double width_) {grid_points = width_; _updateBack();}
	void setPostMoveConnectEnabled(bool on) {pm_connect = on;}
	void setNavigationEnabled(bool on) {navigation = on;}
	void setConnectByMouseEnabled(bool on) {m_connect = on;}
	void setTraceConsiderBuses(bool on) {m_trace_with_buses = on;}
	void setPinMulticonnectEnabled(bool on) {m_pin_mc = on;}
	void setMiniMapEnabled(bool on) {minimap = on;}
	
	void zoom(double factor);
	void zoomIn() {zoom(1.2);}
	void zoomOut() {zoom(1. / 1.2);}
	void zoomReset();
	
	void reconnectAll();
	void selectNone();
	void selectAll();
	void removeSelected();
	void removeAll();
	void clearSelection();
	void addItem(QGraphicsItem * item);

signals:
	void blockDoubleClicked(BlockItem * );
	void busDoubleClicked(BlockBusItem * );
	void actionEvent(BlockItemBase::Action action, QList<QGraphicsItem * > items);
	void blockRemoved(BlockItem * item);
	void connectionsChanged();

};

QT_END_NAMESPACE

QT_END_HEADER

#endif // BLOCKVIEW_H
