#include "designer_view.h"
#include <alignedtextitem.h>
#include <qvariantedit.h>
#include <QMimeData>
//#include <QOpenGLWidget>


enum SchemeElement {
	seBus = 1,
	seDecor,
	seBlock,
};


SHDesignerView::SHDesignerView(QWidget * parent): BlockView(parent) {
	//setViewport(new QOpenGLWidget());
	setAcceptDrops(true);
	setZoomWheelOnly(true);
	setBusSquareNodes(true);
	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	wavetrace.setMaximumSteps(1024);
	connect(SHCORE, SIGNAL(changed()), this, SLOT(changedDB()));
	connect(SHCORE, SIGNAL(updateFileWatcherRequest()), this, SLOT(updateFileWatcher()));
	/*
	BlockItem * b = new BlockItem();
	b->addPin(Qt::AlignLeft, 1, "p0");
	b->addPin(Qt::AlignLeft, 1, "p1");
	b->addPin(Qt::AlignLeft, 2, "p2");
	b->addPin(Qt::AlignRight, 2, "p3");
	addItem(b);
	
	b = new BlockItem();
	b->moveBy(180, 0);
	b->setSize(200, 160);
	b->addPin(new BlockItemPin(Qt::AlignLeft, 1));
	b->addPin(new BlockItemPin(Qt::AlignLeft, 1));
	b->addPin(new BlockItemPin(Qt::AlignLeft, 2));
	b->addPin(new BlockItemPin(Qt::AlignRight, 2));
	
	addItem(b);
	*/
}


SHDesignerView::~SHDesignerView() {
}


void SHDesignerView::dragEnterEvent(QDragEnterEvent * e) {
	dragMoveEvent(e);
	e->setDropAction(Qt::CopyAction);
	e->accept();
	int id = 0, source = 0;
	QByteArray ba = e->mimeData()->data(SH_MIME_BlockID);
	if (ba.isEmpty()) return;
	QDataStream(ba) >> id >> source;
	SHDatabaseStorage & storage(SHCORE->getStorage(source));
	BlockItem * nb = storage.src_blocks.value(id, 0);
	if (!nb) return;
	nb = nb->copy();
	SHCORE->prepareBlock(nb);
	setUniqueName(nb);
	nb->setPos(quantize(mapToScene(e->pos()) - QPointF(0, nb->height() / 2 - 5), gridStep()));
	setGhost(nb);
}


void SHDesignerView::dragMoveEvent(QDragMoveEvent * e) {
	bool ok = e->mimeData()->formats().contains(SH_MIME_BlockID);
	if (ok) {
		e->setDropAction(Qt::CopyAction);
		e->accept();
	}
	if (ghost())
		ghost()->setPos(quantize(mapToScene(e->pos()) - QPointF(0, ghost()->height() / 2 - 5), gridStep()));
}


void SHDesignerView::dragLeaveEvent(QDragLeaveEvent * e) {
	clearGhost();
}


void SHDesignerView::dropEvent(QDropEvent * e) {
	clearGhost();
	if (e->dropAction() != Qt::CopyAction) return;
	int id = 0, source = 0;
	QByteArray ba = e->mimeData()->data(SH_MIME_BlockID);
	if (ba.isEmpty()) return;
	QDataStream(ba) >> id >> source;
	emit newBlockRequest(id, source, e->pos());
}




QByteArray SHDesignerView::save() {
	ChunkStream cs;
	cs << cs.chunk(seBus, buses()) << cs.chunk(seDecor, decors());
	QList<BlockItem*> blockl = blocks();
	foreach (BlockItem * b, blockl) {
		ChunkStream csb;
		csb << csb.chunk(3, b->data(SH_Block_Source).toInt())
			<< csb.chunk(1, b->data(SH_Block_ID).toInt())
			<< csb.chunk(2, b->save());
		cs << cs.chunk(seBlock, csb.data());
	}
	reconnectAll();
	emit changedScheme();
	return cs.data();
}


void SHDesignerView::load(const QByteArray & data) {
	QList<BlockBusItem*> busl = buses();
	QList<BlockItem*> blockl = blocks();
	QList<QGraphicsItem*> decorl;
	qDeleteAll(busl);
	qDeleteAll(blockl);
	if (data.isEmpty()) {
		emit changedScheme();
		return;
	}
	ChunkStream cs(data), csb;
	QByteArray ba; BlockItem * block;
	while (!cs.atEnd()) {
		switch (cs.read()) {
		case seBus:
			busl = cs.getData<QList<BlockBusItem*> >();
			foreach (BlockBusItem * b, busl) {
				loadBus(b);
				addItem(b);
			}
			break;
		case seDecor:
			decorl = cs.getData<QList<QGraphicsItem*> >();
			foreach (QGraphicsItem * d, decorl) {
				d->setData(bvidType, bvitDecor);
				addItem(d);
			}
			break;
		case seBlock:
			ba = cs.getData<QByteArray>();
			csb.setSource(ba);
			int source = 0;
			block = new BlockItem();
			while (!csb.atEnd()) {
				switch (csb.read()) {
				case 3: source = csb.getData<int>(); block->setData(SH_Block_Source, source); break;
				case 1: block->setData(SH_Block_ID, csb.getData<int>()); SHCORE->getStorage(block).loadBlockModel(block); break;
				case 2: block->load(csb.getData<QByteArray>()); break;
				}
			}
			SHDatabaseStorage & storage(SHCORE->getStorage(block));
			storage.loadBlock(block, false);
			SHCORE->prepareBlock(block);
			addItem(block);
			break;
		}
	}
	reconnectAll();
	drawSceneThumb();
	thumbShow();
	emit changedScheme();
	//SHCORE->updateAllBlocksPackets(blocks());
}


void SHDesignerView::setUniqueName(BlockItem * block) {
	if (!block->isPropertyExists("name")) return;
	QList<BlockItem * > bll = blocks();
	QStringList nl;
	foreach (BlockItem * b, bll)
		if (b->isPropertyExists("name"))
			nl << b->propertyValueByName("name").toString();
	block->setPropertyValue("name", uniqueName(block->propertyValueByName("name").toString(), nl));
}


void SHDesignerView::traceBus(QPoint scene_pos_from, QPoint scene_pos_to, BlockBusItem * bus) {
	trace(scene_pos_from, scene_pos_to, bus);
}


void SHDesignerView::updateFileWatcher() {
	QStringList al = SHCORE->file_watcher.files(), nl;
	QList<BlockItem * > bll = blocks();
	//qDebug() << "Update watch list";
	foreach (BlockItem * b, bll) {
		foreach (const PropertyStorage::Property & p, b->properties())
			if (p.flags & SHS::InstallFileWatcher) {
				if (p.value.canConvert<QString>())
					nl << p.value.toString();
				else if (p.value.canConvert<QAD::File>())
					nl << p.value.value<QAD::File>().file;
				else if (p.value.canConvert<QAD::Dir>())
					nl << p.value.value<QAD::Dir>().dir;
				//qDebug() << "add" << p.name << p.value;
			}
				//
		//nl << plugin.plugin->watchFiles(b);
	}
	nl.removeDuplicates();
	nl.removeAll("");
	al.sort(); nl.sort();
	//qDebug() << " =  watch list" << al << nl;
	if (al == nl) return;
	//qDebug() << "new watch list" << nl;
	if (!al.isEmpty()) SHCORE->file_watcher.removePaths(al);
	if (!nl.isEmpty()) SHCORE->file_watcher.addPaths(nl);
	if (sender() == SHCORE) QMetaObject::invokeMethod(scene(), "selectionChanged");
}


void SHDesignerView::changedDB() {
	QList<BlockBusItem * > bul = buses();
	foreach (BlockBusItem * b, bul)
		loadBus(b);
	QList<BlockItem * > bll = blocks();
	foreach (BlockItem * b, bll) {
		SHDatabaseStorage & storage(SHCORE->getStorage(b));
		storage.loadBlock(b);
		SHCORE->prepareBlock(b);
	}
	reconnectAll();
}


void SHDesignerView::copyBlocks(QList<BlockItem * > items, QPointF offset) {
	foreach (BlockItem * b, items) {
		BlockItem * nb = new BlockItem();
		nb->setData(SH_Block_ID, b->data(SH_Block_ID).toInt());
		nb->setData(SH_Block_Source, b->data(SH_Block_Source).toInt());
		SHDatabaseStorage & storage(SHCORE->getStorage(nb));
		storage.loadBlock(nb);
		nb->properties() = b->properties();
		nb->setPos(b->pos() + offset);
		SHCORE->prepareBlock(nb);
		addItem(nb);
	}
}


void SHDesignerView::copyBuses(QList<BlockBusItem * > items, QPointF offset) {
	foreach (BlockBusItem * b, items) {
		BlockBusItem * nb = b->copy();
		SHCORE->databaseStorage().loadBus(nb);
		nb->properties() = b->properties();
		nb->movePolyline(offset);
		addItem(nb);
	}
}
