#ifndef SHDESIGNERCORE_H
#define SHDESIGNERCORE_H

#include <QDockWidget>
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlRecord>
#include <QSqlQuery>
#include <QSqlDriver>
#include <QSqlError>
#include <QSqlQueryModel>
#include <QFileSystemWatcher>
#include <QThread>
#include <QQueue>
#include <QImage>
#include <qpiconfig.h>
#include "schemeprocess.h"
#include "server_data_generator.h"
#include "SH_plugins_manager.h"
#include "database_storage.h"
#include "SHDesignerAPI.h"

const char SH_MIME_BlockID[] = "SHDesignerBlockID";

QT_BEGIN_NAMESPACE

#define SHCORE (SHDesignerCore::instance())

class SHDesignerCore: public QObject {
	Q_OBJECT
	friend class SHDesigner;
public:
	explicit SHDesignerCore();
	~SHDesignerCore();

	enum StorageSource {
		sDatabase,
		sPlugins
	};

	struct Editor {
		Editor() {base = 0; main_widget = 0; center = 0;}
		static Editor make(SHBlockWidgetBase * e);
		SHBlockWidgetBase * base;
		QWidget * main_widget;
		QWidget * center;
		QList<QAction*> menus;
		QList<QDockWidget*> docks;
	};

	static SHDesignerCore * instance();
	static QSqlDatabase & database() {return instance()->base;}
	static void transaction() {instance()->base.transaction();}
	static void commit() {instance()->base.commit();}
	static bool isDefaultDBOpened();
	
	void setProjectsDir(QString d);
	void setDatabasesDir(QString d);
	void setDatabaseFile(QString d);
	PropertyStorage parseDefaultProperties(const QStringList & props);
	QDir projectsDir() const {return QDir(projects_dir);}
	QDir databasesDir() const {return QDir(databases_dir);}

	QDir currentProjectDir() const {return QDir(current_project_dir);}
	void setCurrentProject(const QString & p);

	void loadPropertiesFromFile(const QString & filename, QMap<uint, PropertyStorage> & props);
	void savePropertiesToFile  (const QString & filename, QMap<uint, PropertyStorage> & props);

	void deleteEditor(int id);
	void deleteEditors();
	Editor * blockEditor(BlockItem * block);

	void prepareBlock(BlockItem * block);
	void assignPinTypes(BlockItem * bi, const BlockType & block);

	SHPluginBaseBlock * blockPlugin(BlockItem * block);
	SHPluginBaseBlock * blockPlugin(const QString & plugin_name);
	SHPluginBaseScript * scriptPlugin(BlockItem * block);
	SHPluginBaseScript * scriptPlugin(const QString & plugin_name);
	SHPluginBaseBus * busPlugin(BlockBusItem * bus);
	SHPluginBaseBus * busPlugin(int type);
	SHPluginBaseBus * busPlugin(const QString & plugin_name);
	SHPluginBasePacket * packetPlugin(BlockItemPin * pin);
	SHPluginBasePacket * defaultPacketPlugin();
	uint packetPluginID(BlockItemPin * pin);
	SHPluginBase * packetGateway(BlockItem * block);
	uint packetGatewayID(BlockItem * block);
	//SHPluginBase * packetPlugin(BlockItem * block);
	void pluginBlockAction(BlockItem * block, const SHPluginBase::PluginAction &action);
	void pluginBusAction(BlockBusItem * bus, const SHPluginBase::PluginAction &action);

	SHDatabaseStorage & databaseStorage();
	SHDatabaseStorage & getStorage(int source);
	SHDatabaseStorage & getStorage(BlockItem * item);

	static void prepareObject(SHS::Object & o, BlockItem * block);
	static void mergeObject(SHS::Object & src, const SHS::Object & in);
	static void actualizeProjectProperties(PropertyStorage & ps);

	static void writeConnectionFile(const BlockItem * block , const QString &file);

	PIMap<int, Editor> plugin_editors;
	QMap<QString, QString> io_prefixes;
	PropertyStorage default_project_properties, default_block_properties, default_bus_properties, default_pin_properties;
	PropertyStorage project_properties;
	SHSchemeProcess sprocess;
	SHServerDataGenerator dbgenerator;
	QFileSystemWatcher file_watcher;
	QString current_project_name, current_project_dir;
	SHDesignerAPI plugins_api;
	
private:
	typedef QPair<QString, QString> SSPair;
	//QVector<SSPair> tables;
	SHDatabaseStorage storage, storage_plugins;
	QSqlDatabase base;//, work_base;
	QString databases_dir, projects_dir;
	
private slots:
	void updateByFileWatcher();
	
public slots:
	void fileChanged(QString f);
	void reloadDB();
	void reloadPlugins();
	
signals:
	void changed();
	void changedPlugins();
	void changedBlockPackets();
	void changedPluginsProperties();
	void updateFileWatcherRequest();
	void databaseResaveRequest();
	
};

QT_END_NAMESPACE

#endif // SHDESIGNERCORE_H
