#include "blockview.h"

#include <QApplication>
#include <piqt.h>


BlockBusItem::BlockBusItem(bool temp): QGraphicsObject(), PropertyStorage() {
	temp_ = temp;
	_init();
	if (!temp)
		setData(bvidType, bvitBus);
	else
		hide();
}


BlockBusItem::BlockBusItem(const BlockBusItem & other): QGraphicsObject(), PropertyStorage() {
	temp_ = false;
	_init();
	setData(bvidType, bvitBus);
	setPen(other.pen());
	setBrush(other.brush());
	setBusType(other.busType());
	square_node  = other.square_node;
	max_ep       = other.max_ep;
	pol          = other.pol;
	segments     = other.segments;
	im_bus       = other.im_bus;
	im_end       = other.im_end;
	im_bus_scale = other.im_bus_scale;
	im_end_scale = other.im_end_scale;
	updateGeometry();
}


void BlockBusItem::_init() {
	setZValue(1.);
	setBusType(-1);
	setAcceptHoverEvents(true);
	ph.setColor(Qt::blue);
	ph.setJoinStyle(Qt::MiterJoin);
	bh.setColor(Qt::blue);
	bh.setStyle(Qt::SolidPattern);
	pu = pa = pr = ph;
	bu = ba = br = bh;
	grid_step    = 10.;
	pu.setWidth(1);
	pu.setColor(Qt::black);
	bu.setColor(Qt::black);
	pa.setColor(Qt::darkGreen);
	ba.setColor(Qt::darkGreen);
	pr.setColor(Qt::darkRed);
	br.setColor(Qt::darkRed);
	pn.setColor(Qt::gray);
	pn.setStyle(Qt::DashLine);
	if (temp_) {
		pu.setStyle(Qt::DashLine);
		pu.setColor(Qt::darkGray);
		bu.setColor(Qt::darkGray);
	}
	setPen(pu);
	setBrush(bu);
	square_node = false;
	max_ep      = 0;
	selPoint = selSegment = state_ = -1;
	pen_width                      = 2.;
	point_size                     = 3.;
	im_bus_scale = im_end_scale = 1.;
	moved = deleted = mark_in = mark_out = new_segment = mm_cancel = lm_point = false;
	anim_point_size.setTargetObject(this);
	anim_point_size.setPropertyName("pointSize");
	anim_point_size.setStartValue(0);
	anim_point_size.setEasingCurve(QEasingCurve::OutQuad);
	anim_point_size.setEndValue(point_size);
	anim_point_size.setDuration(200);
}


void BlockBusItem::reconnect() {
	if (temp_) return;
	if (!scene()) return;
	if (scene()->views().isEmpty()) return;
	qobject_cast<BlockView *>(scene()->views().back())->reconnectAll();
}


bool BlockBusItem::sceneEvent(QEvent * e) {
	if (temp_) return QGraphicsObject::sceneEvent(e);
	switch (e->type()) {
	case QEvent::GraphicsSceneHoverEnter: hoverEnterEvent((QGraphicsSceneHoverEvent *)e); break;
	case QEvent::GraphicsSceneHoverMove: hoverMoveEvent((QGraphicsSceneHoverEvent *)e); break;
	case QEvent::GraphicsSceneHoverLeave: hoverLeaveEvent((QGraphicsSceneHoverEvent *)e); break;
	case QEvent::GraphicsSceneMousePress: mousePressEvent((QGraphicsSceneMouseEvent *)e); break;
	case QEvent::GraphicsSceneMouseMove: mouseMoveEvent((QGraphicsSceneMouseEvent *)e); break;
	case QEvent::GraphicsSceneMouseRelease: mouseReleaseEvent((QGraphicsSceneMouseEvent *)e); break;
	default: break;
	}
	return QGraphicsObject::sceneEvent(e);
}


int BlockBusItem::addPoint(const QPointF & point, bool update) {
	int ei = pol.indexOf(point);
	if (ei >= 0) return ei;
	if (selSegment < 0 || selSegment >= pol.size() - 1) return -1;
	pol << quantize(nearestPointOnLine(pol[segments[selSegment].first], pol[segments[selSegment].second], point), grid_step);
	selPoint = pol.size() - 1;
	segments << QPair<int, int>(selPoint, segments[selSegment].second);
	segments[selSegment].second = selPoint;
	selSegment                  = -1;
	updateGeometry();
	if (scene() != 0 && update) scene()->update();
	return pol.size() - 1;
}


int BlockBusItem::segmentPointPair(int point, int * seg) const {
	for (int i = 0; i < segments.size(); ++i) {
		if (segments[i].first == point) {
			if (seg) *seg = i;
			return segments[i].second;
		}
		if (segments[i].second == point) {
			if (seg) *seg = i;
			return segments[i].first;
		}
	}
	if (seg) *seg = -1;
	return -1;
}


void BlockBusItem::removePoint(int index) {
	if (index < 0 || index > pol.size() - 1) return;
	int sc = 0, fs = -1, ss = -1;
	for (int i = 0; i < segments.size(); ++i)
		if (segments[i].first == index || segments[i].second == index) {
			sc++;
			if (fs < 0)
				fs = i;
			else
				ss = i;
		}
	int ei(0);
	switch (sc) {
	case 1: segments.removeAt(fs); break;
	case 2:
		if (segments[ss].first == index)
			ei = segments[ss].second;
		else
			ei = segments[ss].first;
		if (segments[fs].first == index)
			segments[fs].first = ei;
		else
			segments[fs].second = ei;
		segments.removeAt(ss);
		break;
	default: return;
	}
	pol.remove(index);
	for (int i = 0; i < segments.size(); ++i) {
		if (segments[i].first >= index) segments[i].first--;
		if (segments[i].second >= index) segments[i].second--;
	}
	selPoint = -1;
	checkDelete();
	updateGeometry();
	if (scene() != 0) scene()->update();
}


void BlockBusItem::removeSegment(int index) {
	if (index < 0 || index > segments.size() - 1) return;
	int pif = segments[index].first, pis = segments[index].second;
	if (pif > pis) qSwap<int>(pif, pis);
	int scf = 0, scs = 0;
	for (int i = 0; i < segments.size(); ++i) {
		if (segments[i].first == pif || segments[i].second == pif) scf++;
		if (segments[i].first == pis || segments[i].second == pis) scs++;
	}
	if (scs <= 2) removePoint(pis);
	if (scf <= 2) removePoint(pif);
	if (scs <= 2 || scf <= 2) selSegment = -1;
	if (scene() != 0) scene()->update();
}


void BlockBusItem::appendPoint(const QPointF & p) {
	pol << p;
	if (pol.size() > 1) segments << QPair<int, int>(pol.size() - 2, pol.size() - 1);
	updateGeometry();
}


void BlockBusItem::appendPoint(qreal x, qreal y) {
	appendPoint(QPointF(x, y));
}


void BlockBusItem::clear() {
	pol.clear();
	segments.clear();
	updateGeometry();
}


void BlockBusItem::movePolyline(const QPointF & dp) {
	pol.translate(dp);
	prepareGeometryChange();
}


void BlockBusItem::movePoint(int index, const QPointF & dp) {
	pol[index] += dp;
	prepareGeometryChange();
}


void BlockBusItem::setWidth(const double & w) {
	pen_width = w;
	update();
}


void BlockBusItem::setColor(const QColor & c) {
	pu.setColor(c);
	bu.setColor(c);
	update();
}


void BlockBusItem::setSquareNodes(bool yes) {
	square_node = yes;
	update();
}


void BlockBusItem::markAsInput() {
	mark_in  = true;
	mark_out = false;
}


void BlockBusItem::markAsOutput() {
	mark_in  = false;
	mark_out = true;
}


void BlockBusItem::unmark() {
	mark_in = mark_out = false;
}


void BlockBusItem::simplify(bool full) {
	int pcnt = pol.size();
	for (int s = 0; s < segments.size(); ++s) {
		if (pol[segments[s].first] != pol[segments[s].second]) continue;
		int ti = segments[s].first, fi = segments[s].second;
		segments.removeAt(s);
		pol.remove(fi);
		for (int i = 0; i < segments.size(); ++i) {
			if (segments[i].first == fi) segments[i].first = ti;
			if (segments[i].second == fi) segments[i].second = ti;
			if (segments[i].first > fi) segments[i].first--;
			if (segments[i].second > fi) segments[i].second--;
		}
	}
	if (full) {
		QList<int> segs;
		for (int p = 0; p < pol.size(); ++p) {
			if (pointSegmentsCount(p, &segs) != 2) continue;
			int s0 = segs[0], s1 = segs[1];
			QPointF cp = pol[p], sp[2];
			for (int i = 0; i < 2; ++i) {
				if (segments[segs[i]].first == p)
					sp[i] = pol[segments[segs[i]].second];
				else
					sp[i] = pol[segments[segs[i]].first];
			}
			QLineF l0(sp[0], cp), l1(cp, sp[1]);
			if (qAbs(l0.angle() - l1.angle()) > 0.1) continue;
			if (segments[s0].first == p) {
				if (segments[s1].first == p)
					segments[s0].first = segments[s1].second;
				else
					segments[s0].first = segments[s1].first;
			} else {
				if (segments[s1].first == p)
					segments[s0].second = segments[s1].second;
				else
					segments[s0].second = segments[s1].first;
			}
			segments.removeAt(s1);
			pol.remove(p);
			for (int i = 0; i < segments.size(); ++i) {
				if (segments[i].first >= p) segments[i].first--;
				if (segments[i].second >= p) segments[i].second--;
			}
			p = -1;
		}
	}
	if (pcnt == pol.size()) return;
	updateGeometry();
}


bool BlockBusItem::hasNullSegment() const {
	for (int s = 0; s < segments.size(); ++s) {
		if (pol[segments[s].first] == pol[segments[s].second]) return true;
	}
	return false;
}


void BlockBusItem::adjustLine() {}


int BlockBusItem::endpointCount() const {
	return endpoints().size();
}


QList<BlockItem *> BlockBusItem::connectedBlocks() const {
	QList<BlockItemPin *> pins = connections_.values();
	QSet<BlockItem *> ret;
	foreach(BlockItemPin * p, pins)
		ret << p->parent();
	return ret.values();
}


QList<BlockItemPin *> BlockBusItem::connectedPins() const {
	return connections_.values();
}


BlockBusItem::PointInfo BlockBusItem::pointInfo(QPointF pos) const {
	PointInfo ret;
	int pi = -1, si = -1;
	testPoint(pos, &pi, &si);
	if (pi < 0 && si < 0) return ret;
	if (si >= 0) {
		ret.type = PointInfo::Type::Segment;
	} else {
		if (endpoints().contains(pi)) {
			ret.type = PointInfo::Type::Endpoint;
			ret.pin  = connections_.value(pi, nullptr);
		} else
			ret.type = PointInfo::Type::Node;
	}
	return ret;
}


void BlockBusItem::setBusState(bool state) {
	int s = state ? 1 : 0;
	if (state_ == s) return;
	state_ = s;
	update();
}


void BlockBusItem::clearBusState() {
	if (state_ == -1) return;
	state_ = -1;
	update();
}


QByteArray BlockBusItem::save() const {
	ChunkStream cs;
	cs.add(1, busType()).add(2, busName()).add(3, width()).add(4, pen()).add(5, brush());
	cs.add(6, pol).add(7, segments).add(8, props).add(9, im_bus_scale).add(10, im_end_scale);
	cs.add(11, piqSerialize(value_tree));
	return cs.data();
}


void BlockBusItem::load(const QByteArray & data) {
	clear();
	if (data.isEmpty()) return;
	ChunkStream cs(data);
	while (!cs.atEnd()) {
		switch (cs.read()) {
		case 1: setBusType(cs.getData<int>()); break;
		case 2: setBusName(cs.getData<QString>()); break;
		case 3: setWidth(cs.getData<double>()); break;
		case 4: setPen(cs.getData<QPen>()); break;
		case 5: setBrush(cs.getData<QBrush>()); break;
		case 6: pol = cs.getData<QPolygonF>(); break;
		case 7: segments = cs.getData<QList<QPair<int, int>>>(); break;
		case 8: props = cs.getData<QList<BlockItem::Property>>(); break;
		case 9: im_bus_scale = cs.getData<double>(); break;
		case 10: im_end_scale = cs.getData<double>(); break;
		case 11: value_tree = piqDeserialize<PIValueTree>(cs.getData<QByteArray>()); break;
		}
	}
	updateGeometry();
}


BlockBusItem * BlockBusItem::copy() const {
	return new BlockBusItem(*this);
}


void BlockBusItem::saveState() {
	segments_s = segments;
	ends_ind_s = ends_ind;
	ends_s     = ends;
	pol_s      = pol;
}


void BlockBusItem::restoreState() {
	segments = segments_s;
	ends_ind = ends_ind_s;
	ends     = ends_s;
	pol      = pol_s;
}


void BlockBusItem::updateGeometry() {
	ends = endpoints();
	ends_ind.clear();
	for (int e = 0; e < ends.size(); ++e) {
		int ce = ends[e];
		for (int s = 0; s < segments.size(); ++s) {
			if (segments[s].first == ce) {
				ends_ind << QPair<int, int>(segments[s].first, segments[s].second);
				break;
			}
			if (segments[s].second == ce) {
				ends_ind << QPair<int, int>(segments[s].second, segments[s].first);
				break;
			}
		}
	}
	reconnect();
	prepareGeometryChange();
}


bool BlockBusItem::checkDelete() {
	if (pol.size() >= 2 && segments.size() >= 1) return false;
	deleteLater();
	return true;
}


void BlockBusItem::emitAction(BlockItemBase::Action a) {
	qobject_cast<BlockView *>(scene()->views().back())->schemeAction(a, QList<QGraphicsItem *>() << this);
	qobject_cast<BlockView *>(scene()->views().back())->connectionsChanged();
}


QVector<int> BlockBusItem::endpoints() const {
	QVector<int> counts(pol.size(), 0), ret;
	for (int i = 0; i < segments.size(); ++i) {
		counts[segments[i].first]++;
		counts[segments[i].second]++;
	}
	for (int i = 0; i < counts.size(); ++i) {
		if (counts[i] == 1) ret << i;
	}
	return ret;
}


QVector<int> BlockBusItem::endpointLine(int ep, double angle) const {
	QVector<int> ret;
	int seg = -1;
	int np = segmentPointPair(ep, &seg), pp = np;
	if (ep < 0 || np < 0) return ret;
	if (pol[np] == pol[ep]) return ret;
	QLineF l(pol[ep], pol[np]);
	// qDebug() << "first" << l.angle() << angle << (l.angle() != angle);
	if (qAbs(l.angle() - angle) > 0.1) return ret;
	// qDebug() << "check next" << segments.size();
	for (int i = 0; i < segments.size(); ++i) {
		// qDebug() << i << np << pointSegmentsCount(np);
		if (np < 0) break;
		if (pointSegmentsCount(np) != 2) break;
		if (i > 0) {
			QLineF l(pol[pp], pol[np]);
			// qDebug() << i << l.angle() << angle;
			if (qAbs(l.angle() - angle) > 0.1) break;
		}
		ret << np;
		pp = np;
		np = neighborSegmentPoint(np, &seg);
	}
	return ret;
}


int BlockBusItem::pointSegmentsCount(int point, QList<int> * segs) const {
	int ret = 0;
	if (segs) segs->clear();
	for (int i = 0; i < segments.size(); ++i)
		if (segments[i].first == point || segments[i].second == point) {
			ret++;
			if (segs) segs->append(i);
		}
	return ret;
}


int BlockBusItem::neighborSegmentPoint(int point, int * seg) const {
	if (point < 0 || !seg) return -1;
	for (int i = 0; i < segments.size(); ++i) {
		if (i == *seg) continue;
		if (segments[i].first == point) {
			*seg = i;
			return segments[i].second;
		}
		if (segments[i].second == point) {
			*seg = i;
			return segments[i].first;
		}
	}
	return -1;
}


void BlockBusItem::testPoint(QPointF pos, int * sel_point, int * sel_segment, bool for_trace) const {
	for (int i = 0; i < pol.size(); ++i) {
		if ((pol[i] - pos).manhattanLength() <= (for_trace ? 5. : 10.)) { // Point
			*sel_point   = i;
			*sel_segment = -1;
			return;
		}
	}
	for (int i = 0; i < segments.size(); ++i) {
		if (distPointToLine(pol[segments[i].first], pol[segments[i].second], pos) <= (for_trace ? 5. : 7.)) { // Segment
			*sel_point   = -1;
			*sel_segment = i;
			return;
		}
	}
	*sel_point   = -1;
	*sel_segment = -1;
}


void BlockBusItem::hoverEnterEvent(QGraphicsSceneHoverEvent * e) {
	tt = bus_name + (bus_name.isEmpty() ? "" : "\n\n") +
	     tr("Add point: Ctrl + LeftClick\n"
	        "Remove point\\segment: Ctrl + RightClick\n"
	        "Remove connection: Shift + RightClick\n"
	        "Move point\\segment: Shift + LeftPress\n"
	        "Change trace mode: press Shift, when mouse move");
}


void BlockBusItem::hoverMoveEvent(QGraphicsSceneHoverEvent * e) {
	if (temp_) return;
	QPointF sp = e->scenePos();
	int pp     = selPoint;
	int ps     = selSegment;
	bool empt  = !(selPoint >= 0 || selSegment >= 0);
	testPoint(sp, &selPoint, &selSegment);
	BlockView * bv = 0;
	if (!scene()->views().isEmpty()) {
		bv = qobject_cast<BlockView *>(scene()->views().back());
	}
	if ((selPoint >= 0 && pp != selPoint) || (selSegment >= 0 && ps != selSegment)) {
		if (bv) {
			if (bv->isBlockAnimationEnabled()) {
				setPointSize(0);
				anim_point_size.start();
			}
		} else
			setPointSize(anim_point_size.endValue().toDouble());
	}

	if (selPoint >= 0 || selSegment >= 0) {
		if (empt) {
			QList<BlockItemPin *> pins = connectedPins();
			foreach(BlockItemPin * p, pins) {
				p->animAccept();
			}
		}
		setToolTip(tt);
		update();
		if (bv) bv->cur_bus = this;
		return;
	}
	if (bv) bv->cur_bus = 0;
	setToolTip(QString());
	QList<QGraphicsItem *> il = scene()->items(sp, Qt::ContainsItemBoundingRect, Qt::DescendingOrder), bil;
	bil << this;
	for (int i = 0; i < il.size(); ++i) {
		QGraphicsItem * b = il[i];
		if ((b->data(bvidType).toInt() == bvitBus) && b != this) {
			int tp = -1, ts = -1;
			((BlockBusItem *)b)->testPoint(sp, &tp, &ts);
			if (tp >= 0 || ts >= 0) {
				foreach(QGraphicsItem * b2, bil)
					b2->stackBefore(b);
				break;
			}
			bil << b;
		}
	}
	update();
}


void BlockBusItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * e) {
	if (temp_) return;
	selPoint = selSegment = -1;
	setPen(pu);
	setBrush(bu);
	setToolTip(QString());
	anim_point_size.stop();
	BlockView * bv = 0;
	if (!scene()->views().isEmpty()) bv = qobject_cast<BlockView *>(scene()->views().back());
	if (bv && (QApplication::mouseButtons() == 0)) bv->cur_bus = 0;
	update();
	QGraphicsObject::hoverLeaveEvent(e);
}


void BlockBusItem::mousePressEvent(QGraphicsSceneMouseEvent * e) {
	if (temp_) return;
	lp = quantize(e->scenePos(), grid_step);
	if (e->button() != Qt::RightButton) bpol = pol;
	BlockView * bv = 0;
	if (!scene()->views().isEmpty()) {
		bv = qobject_cast<BlockView *>(scene()->views().back());
	}
	if (bv) {
		if (selPoint >= 0 || selSegment >= 0) bv->cur_bus = this;
	}
	if (new_segment) {
		qobject_cast<BlockView *>(scene()->views().back())->newBranchCancel();
	}
	new_segment = false;
	if ((selPoint < 0 || selPoint > pol.size() - 1) && (selSegment < 0) && e->modifiers().testFlag(Qt::ShiftModifier)) {
		QGraphicsObject::mousePressEvent(e);
		return;
	}
	int btncnt = 0;
	if ((e->button() == Qt::LeftButton) && e->modifiers().testFlag(Qt::ShiftModifier)) {
		if (endpoints().contains(selPoint)) qobject_cast<BlockView *>(scene()->views().back())->startBusPointMove(bus_type);
	}
	if (e->buttons().testFlag(Qt::LeftButton)) btncnt++;
	if (e->buttons().testFlag(Qt::RightButton)) btncnt++;
	if (e->buttons().testFlag(QT_MID_BUTTON)) btncnt++;
	if (btncnt > 0) mm_mods = e->modifiers();
	if (btncnt >= 2 && e->button() == Qt::RightButton) {
		// qDebug() << "bus revert";
		mm_cancel = true;
		moved     = false;
		pol       = bpol;
		prepareGeometryChange();
		return;
	}
	if (e->buttons().testFlag(Qt::LeftButton) && e->modifiers().testFlag(Qt::NoModifier)) {
		if (selSegment >= 0)
			press_pos =
				quantize(nearestPointOnLine(pol[segments[selSegment].first], pol[segments[selSegment].second], e->scenePos()), grid_step);
		else {
			if (selPoint >= 0)
				press_pos = pol[selPoint];
			else
				return;
		}
		if (max_ep >= 2) {
			if (endpointCount() >= max_ep)
				if (pointSegmentsCount(selPoint) >= 2 || selSegment >= 0) return;
		}
		qobject_cast<BlockView *>(scene()->views().back())->newBranch(this);
		new_segment = true;
		return;
	}
	if (e->buttons().testFlag(Qt::RightButton) && e->modifiers().testFlag(Qt::ShiftModifier)) {
		deleteLater();
	}
	if (e->modifiers().testFlag(Qt::ControlModifier)) {
		// qDebug() << "remove" << selPoint << selSegment;
		if (e->buttons().testFlag(Qt::RightButton)) {
			if (selPoint >= 0 && selPoint <= pol.size() - 1) {
				removePoint(selPoint);
				simplify();
				if (!checkDelete()) emitAction(BlockItemBase::BusPointRemove);
				return;
			}
			if (selSegment >= 0 && selSegment <= segments.size() - 1) {
				removeSegment(selSegment);
				simplify();
				if (!checkDelete()) emitAction(BlockItemBase::BusSegmentRemove);
				return;
			}
		}
		if (e->buttons().testFlag(Qt::LeftButton) && selSegment >= 0) {
			if (addPoint(e->scenePos()) >= 0) emitAction(BlockItemBase::BusPointAdd);
			return;
		}
	}
	if (e->buttons().testFlag(Qt::RightButton)) {
		if (deleted) return;
		deleted = true;
	}
}


void BlockBusItem::mouseMoveEvent(QGraphicsSceneMouseEvent * e) {
	if (temp_ || mm_cancel) return;
	if (((selPoint < 0 || selPoint > pol.size() - 1) && (selSegment < 0)) && !new_segment && mm_mods.testFlag(Qt::ShiftModifier)) {
		QGraphicsObject::mouseMoveEvent(e);
		return;
	}
	BlockView * bv = 0;
	if (!scene()->views().isEmpty()) {
		bv = qobject_cast<BlockView *>(scene()->views().back());
	}
	qp = quantize(e->scenePos(), grid_step);
	lp = qp - lp;
	if (e->buttons().testFlag(Qt::LeftButton) && mm_mods.testFlag(Qt::NoModifier) && new_segment) {
		if (bv) qobject_cast<BlockView *>(scene()->views().back())->newBranchTrace(this, e->scenePos());
		return;
	}
	if (new_segment) {
		new_end = qp;
		prepareGeometryChange();
	} else {
		if (e->buttons().testFlag(Qt::LeftButton)) {
			lm_point = selPoint >= 0;
			if (selPoint >= 0 && selPoint <= pol.size() - 1) pol[selPoint] += lp;
			if (selSegment >= 0 && selSegment <= segments.size() - 1) {
				pol[segments[selSegment].first] += lp;
				pol[segments[selSegment].second] += lp;
			}
			moved = true;
			prepareGeometryChange();
		}
	}
	lp = qp;
}


void BlockBusItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * e) {
	mm_mods    = Qt::KeyboardModifiers();
	int btncnt = 0;
	if (e->buttons().testFlag(Qt::LeftButton)) btncnt++;
	if (e->buttons().testFlag(Qt::RightButton)) btncnt++;
	if (e->buttons().testFlag(QT_MID_BUTTON)) btncnt++;
	if (btncnt == 0) mm_cancel = false;
	if (new_segment) {
		qobject_cast<BlockView *>(scene()->views().back())->newBranchAccept(this);
		simplify();
		updateGeometry();
		selPoint = selSegment = -1;
		emitAction(BlockItemBase::BusAdd);
	}
	if (moved) {
		simplify(false);
		if (lm_point) {
			emitAction(BlockItemBase::BusPointMove);
		} else {
			reconnect();
			emitAction(BlockItemBase::BusSegmentMove);
		}
	}
	moved = new_segment = false;
	QGraphicsObject::mouseReleaseEvent(e);
}


void BlockBusItem::paint(QPainter * p, const QStyleOptionGraphicsItem * o, QWidget * w) {
	ph.setWidthF(pen_width + point_size / 2.);
	pu.setWidthF(pen_width);
	pa.setWidthF(pen_width);
	pr.setWidthF(pen_width);
	pn.setWidthF(pen_width);
	if (pol.size() < 2) return;
	if (selPoint >= 0 || selSegment >= 0) {
		p->setPen(pa);
		p->setBrush(ba);
	} else {
		p->setPen(pu);
		p->setBrush(bu);
	}
	if (im_bus.isNull()) {
		QPen _pen(p->pen());
		for (int i = 0; i < segments.size(); ++i) {
			_pen.setWidthF(pen_width);
			_pen.setCapStyle(Qt::SquareCap);
			p->setPen(_pen);
			p->drawLine(pol[segments[i].first], pol[segments[i].second]);
			if (pointSegmentsCount(segments[i].first) > 2) {
				_pen.setWidthF(pen_width * 1.8 + 2.);
				_pen.setCapStyle(square_node ? Qt::SquareCap : Qt::RoundCap);
				p->setPen(_pen);
				p->drawPoint(pol[segments[i].first]);
			}
		}
		p->setPen(_pen);
	} else {
		QBrush br;
		br.setTextureImage(im_bus);
		for (int i = 0; i < segments.size(); ++i) {
			QPointF sp(pol[segments[i].first]), ep(pol[segments[i].second]);
			QTransform tf;
			tf.translate(sp.x(), sp.y());
			tf.rotate(-QLineF(sp, ep).angle());
			tf.translate(0., -im_bus.height() / 2. * im_bus_scale);
			tf.scale(im_bus_scale, im_bus_scale);
			p->save();
			p->setTransform(tf, true);
			p->setPen(Qt::NoPen);
			p->setBrush(br);
			p->drawRect(QRectF(0., 0., QLineF(sp, ep).length() / qMax<double>(im_bus_scale, 1E-3), im_bus.height()));
			p->restore();
		}
	}
	if (!im_end.isNull()) {
		for (int i = 0; i < ends_ind.size(); ++i) {
			QPointF sp = pol[ends_ind[i].first], ep = pol[ends_ind[i].second];
			QTransform tf;
			tf.translate(sp.x(), sp.y());
			tf.rotate(-QLineF(sp, ep).angle());
			tf.translate(-pen_width, -im_end.height() / 2. * im_end_scale);
			tf.scale(im_end_scale, im_end_scale);
			p->save();
			p->setTransform(tf, true);
			p->drawImage(0, 0, im_end);
			p->restore();
		}
	}
	if (state_ >= 0) {
		if (state_ == 0) {
			pr.setWidthF(pen_width + 1.);
			p->setPen(pr);
		} else if (state_ == 1) {
			pa.setWidthF(pen_width + 1.);
			p->setPen(pa);
		}
		p->setOpacity(0.5);
		for (int i = 0; i < segments.size(); ++i) {
			p->drawLine(pol[segments[i].first], pol[segments[i].second]);
		}
		p->setOpacity(1.);
	}
	if (!im_bus.isNull() && (selPoint >= 0 || selSegment >= 0)) {
		p->setPen(pa);
		p->setBrush(ba);
		for (int i = 0; i < segments.size(); ++i) {
			p->drawLine(pol[segments[i].first], pol[segments[i].second]);
		}
	}
	if (selPoint >= 0) {
		p->save();
		p->setPen(ph);
		p->setBrush(bh);
		p->translate(pol[selPoint]);
		p->drawEllipse(QPointF(0, 0), point_size, point_size);
		p->restore();
	}
	if (selSegment >= 0) {
		p->save();
		p->setPen(ph);
		p->drawLine(pol[segments[selSegment].first], pol[segments[selSegment].second]);
		p->restore();
	}
}


void BlockBusItem::setPointSize(double s) {
	point_size = s;
	update();
}


QRectF BlockBusItem::boundingRect() const {
	QPolygonF p(pol);
	if (new_segment) p << new_end;
	return enlargedRect(p.boundingRect(), 0, 0, 10.f);
}
