#include <QMessageBox>
#include <QFileDialog>
#include <QInputDialog>
#include <QStatusBar>
#include <QTimer>
#include <picrypt.h>
#include <qpiconfig.h>
#include <piqt.h>
#include <aboutwindow.h>
#include <qad_locations.h>
#include "device_designer.h"
#include "SH_plugin_widgets.h"
#include "SH_plugins.h"
#include "SH_plugins_manager.h"


DeviceDesigner::DeviceDesigner(): EMainWindow(), Ui::DeviceDesigner(), PIObject() {
	initAbout();
	setupUi(this);
	setRecentMenu(menuOpen_recent);
	statusBar()->addPermanentWidget(widgetDevice, 1);
	editor = 0;
	session.setFile(QAD::userPath(QAD::ltConfig, "session_device_designer"));
	session.addEntry(this);
	session.load();
	QMenu * menu_ed = new QMenu(this);
	RUNTIME->plugins_manager->localInterface().loadPlugins();
	QString filter_all;
	auto pl = RUNTIME->plugins_manager->localInterface().getPlugins(SHPluginBase::Block);
	for (const auto & p: pl) {
		SHPluginBaseBlock * plugin = (SHPluginBaseBlock * )p.plugin;
		SHBlockWidgetBase * e = plugin->createEditor();
		if (!e) continue;
		e->plugin = plugin;
		e->device = widgetDevice;
		editors << Editor::make(e);
		connect(e->interface(), SIGNAL(changed()), this, SLOT(changed()));
		QString ext = e->fileExtension().toLower();
		if (!ext.isEmpty()) {
			if (!extensions.contains(ext)) {
				extensions[ext] = editors.size() - 1;
				if (!load_filters.isEmpty()) {
					load_filters.append(";;");
					filter_all.append(" ");
				}
				filter_all.append("*." + e->fileExtension());
				load_filters.append(QString("%1(*.%2)").arg(plugin->name(), e->fileExtension()));
			} else
				qDebug() << "Extension" << ext << "conflict," << plugin->name() << "ignored";
		}
		QAction * a = menu_ed->addAction(plugin->name() + " ...", this, [this](){
			QApplication::setOverrideCursor(Qt::WaitCursor);
			assignEditor(sender()->property("_index").toInt());
			reset();
			QApplication::restoreOverrideCursor();
		});
		a->setProperty("_index", editors.size() - 1);
	}
	if (!load_filters.isEmpty())
		load_filters.prepend(";;");
	load_filters.prepend(QString("%1(%2)").arg(tr("All"), filter_all));
	actionNew_for->setMenu(menu_ed);
	ribbon = new Ribbon(this);
}


DeviceDesigner::~DeviceDesigner() {
	session.save();
	session.clear();
}


void DeviceDesigner::closeEvent(QCloseEvent *) {
	assignEditor(-1);
	for (auto e: editors) {
		if (!e.main_widget) continue;
		if (e.center && (e.center != e.main_widget))
			((QMainWindow*)e.main_widget)->setCentralWidget(e.center);
		if (e.main_widget) delete e.main_widget;
	}
}


void DeviceDesigner::savingSession(QPIConfig & conf) {
	conf.setValue("recent_files", recentFiles());
}


void DeviceDesigner::loadingSession(QPIConfig & conf) {
	setRecentFiles(conf.getValue("recent_files").toStringList());
}


void DeviceDesigner::initAbout() {
	Q_INIT_RESOURCE(shared);
	ADD_ABOUT_VERSION(SHS);
	AboutWindow::addVersion("Ui sync", QString::number(SHS_UISYNC_VERSION));
	ADD_ABOUT_VERSION(QAD);
	AboutWindow::addVersion("Qt", qVersion());
	ADD_ABOUT_VERSION(PIP);
	AboutWindow::addVersion("sodium", PI2QString(PICrypt::version()));
	ADD_ABOUT_BUILD_INFO(SHS);
}


bool DeviceDesigner::procArgs(const QStringList & args, bool check) {
	if (args.size() <= 1) return false;
	QString dev;
	int addr = -1;
	for (int i = 1; i < args.size(); ++i) {
		if (args[i] == "-d") {
			++i;
			if (i < args.size()) {
				dev = args[i];
				if (!dev.isEmpty() && !check)
					setDevice(dev);
			}
			continue;
		}
		if (args[i] == "-a") {
			++i;
			if (i < args.size()) {
				addr = args[i].toInt();
				if (addr >= 0 && !check)
					setAddress(addr);
			}
			continue;
		}
		if (!check) {
			loadFile(args[i]);
			continue;
		}
		return true;
	}
	return false;
}


void DeviceDesigner::assignEditor(int index) {
	Editor * ne = 0;
	if (index >= 0) ne = &(editors[index]);
	actionSave->setEnabled(ne);
	actionSave_as->setEnabled(ne);
	if (editor) {
		editor->base->saveSession();
		if (ne) {if (editor == ne) return;}
		if (editor->center) {
			layoutCenter->removeWidget(editor->center);
			editor->center->hide();
			//editor->center->setParent(0);
		}
		foreach (auto * d, editor->docks) removeDockWidget(d);
		foreach (auto * m, editor->menus) menuBar()->removeAction(m);
	}
	editor = ne;
	if (!editor) return;
	if (widgetDevice->isOpened()) on_widgetDevice_opened();
	else on_widgetDevice_closed();
	if (editor->center) {
		layoutCenter->addWidget(editor->center);
		editor->center->show();
	}
	for (auto * d: editor->docks) addDockWidget((Qt::DockWidgetArea)(d->property("_area_").toInt()), d);
	for (auto * m: editor->menus)  {
		menuBar()->insertAction(menuHelp->menuAction(), m);
	}
	ribbon->init();
	editor->base->loadSession();
}


void DeviceDesigner::unchange() {
	setChanged(false);
}


void DeviceDesigner::showAbout() {
	AboutWindow::show();
}


void DeviceDesigner::loadFile(const QString & fp) {
	load(fp);
}


void DeviceDesigner::showMain() {
	show();
	procArgs(qApp->arguments());
	QTimer::singleShot(0, this, SLOT(unchange()));
}


void DeviceDesigner::reset(bool full) {
	if (!editor) return;
	editor->base->reset();
	setWindowTitle(tr("Device Designer - Untitled[*]"));
	setChanged(false);
	file_name.clear();
}


bool DeviceDesigner::load(const QString & path) {
	QFile f(path);
	if (!f.open(QIODevice::ReadOnly)) return false;
	QString ext = QFileInfo(path).completeSuffix().toLower();
	int ind = extensions.value(ext, -1);
	if (ind < 0) {
		QMessageBox::critical(this, "Device Designer", tr("Can`t find plugin for extension \"%1\"!").arg(ext));
		return false;
	}
	setWindowTitle(tr("Device Designer - %1[*]").arg(QFileInfo(path).fileName()));
	QApplication::setOverrideCursor(Qt::WaitCursor);
	assignEditor(ind);
	bool ret = editor->base->load(f.readAll());
	QApplication::restoreOverrideCursor();
	setChanged(false);
	file_name = path;
	return ret;
}


bool DeviceDesigner::save(const QString & path) {
	if (!editor) return false;
	QFile f(path);
	if (!f.open(QIODevice::ReadWrite)) return false;
	f.resize(0);
	f.write(editor->base->save());
	setChanged(false);
	file_name = path;
	return true;
}


QString DeviceDesigner::loadFilter() {
	return load_filters;
}


QString DeviceDesigner::saveFilter() {
	if (!editor) return QString();
	return tr("%1(*.%2)").arg(editor->base->plugin->name(), editor->base->fileExtension());
}


void DeviceDesigner::on_widgetDevice_opened() {
	if (!editor) return;
	editor->base->deviceOpened();
}


void DeviceDesigner::on_widgetDevice_closed() {
	if (!editor) return;
	editor->base->deviceClosed();
}


void DeviceDesigner::on_widgetDevice_readed(QByteArray data) {
	if (!editor) return;
	editor->base->deviceReaded(data);
}


void DeviceDesigner::anotherAppMessage(QByteArray data) {
	QStringList args = qDeserialize<QStringList>(data, QDataStream::Qt_5_13);
	if (args.isEmpty()) return;
	activateWindow();
	raise();
	setFocus();
	if (procArgs(args, true)) {
		if (QMessageBox::question(this, windowTitle(), "Open new file?", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) != QMessageBox::Yes)
			return;
	}
	procArgs(args);
}


DeviceDesigner::Editor DeviceDesigner::Editor::make(SHBlockWidgetBase * e) {
	Editor ret;
	ret.base = e;
	ret.main_widget = e->widget();
	if (!ret.main_widget) return ret;
	ret.center = ret.main_widget;
	QMainWindow * mw = qobject_cast<QMainWindow*>(ret.main_widget);
	if (mw) {
		ret.center = mw->centralWidget();
		ret.docks = mw->findChildren<QDockWidget*>();
		for (auto * d: ret.docks)
			d->setProperty("_area_", (int)(mw->dockWidgetArea(d)));
		if (mw->menuBar()) ret.menus = mw->menuBar()->actions();
	}
	return ret;
}
