#ifndef SH_PLUGINS_H
#define SH_PLUGINS_H

#include "SH_plugin_base.h"
#include "SH_runtime.h"
#include "database_structs.h"


const QString property_configuration = "__configuration__";

class SHDesignerAPI;


class SHPluginBaseBlock: public SHPluginBase {
public:
	explicit SHPluginBaseBlock() {}
	virtual ~SHPluginBaseBlock() {}
	
	PluginType type() const {return SHPluginBase::Block;}
	QString description() const {return "Block plugin";}
	
	/// Implement to add some dynamic properties in block
	virtual PropertyStorage addProperties(const BlockItem * block, PropertyStorage cur_props = PropertyStorage()) {return PropertyStorage();}
	
	/// Implement to add buttons in the block property dialog
	virtual QList<PluginAction> addActions(const BlockItem * block) {return QList<PluginAction>();}

	/// Implement to add some properties to generating database
	virtual QList<SSPair> addDatabaseProperties(const BlockItem * block) {return QList<SSPair>();}
	
	/// Implement to enable or disable given action
	virtual bool checkAction(const BlockItem * block, const PluginAction & action) {return true;}

	/// Check block for warnings and errors
	virtual void checkBlock(BlockItem * block) {}
	
	/// Execute action from property dialog
	virtual void runAction(BlockItem * block, const PluginAction & action, const PropertyStorage & proj_props = PropertyStorage()) {}

	/// Returns desired filename for generated database
	virtual QString generatedDatabaseFile(const BlockItem * block) {return QString();}

	/// Returns desired filename for generated connection file
	virtual QString generatedConnectionFile(const BlockItem * block) {return QString();}

	/// Implement to return logic representation of block
	virtual SHS::Object createObject(const BlockItem * block) {return SHS::Object();}

	/// Apply command arguments to object model properties
	virtual void applyCommand(SHS::Object & root, SHS::Object & object, SHS::Command & command) {}

	/// Implement to create editor widget for block configuration
	virtual SHBlockWidgetBase * createEditor() {return 0;}

	/// Implement to create BlockTypes
	virtual QList<BlockType> createBlockTypes() {return QList<BlockType>();}

protected:
	void configurePin(BlockType & block, QString pin_name, QString bus_type, QString packet_plugin = QString());

};




class SHPluginBaseBus: public SHPluginBase {
public:
	explicit SHPluginBaseBus() {}
	virtual ~SHPluginBaseBus() {}
	
	PluginType type() const {return SHPluginBase::Bus;}
	QString description() const {return "Bus plugin";}
	
	/// Implement to add some dynamic properties in bus
	virtual PropertyStorage addProperties(const BlockBusItem * bus, PropertyStorage cur_props = PropertyStorage()) {return PropertyStorage();}
	
	/// Implement to add some dynamic properties to assosiated pin
	virtual PropertyStorage addPropertiesToPin(const BlockItemPin * pin, PropertyStorage cur_props = PropertyStorage()) {return PropertyStorage();}

	/// Implement to add some dynamic properties to block
	virtual PropertyStorage addPropertiesToBlock(const BlockItem * block, PropertyStorage cur_props = PropertyStorage()) {return PropertyStorage();}
	
	/// Implement to add buttons in the bus property dialog
	virtual QList<PluginAction> addActions(const BlockBusItem * bus) {return QList<PluginAction>();}
	
	/// Implement to enable or disable given action
	virtual bool checkAction(const BlockBusItem * bus, const PluginAction & action) {return true;}
	
	/// Execute action from property dialog
	virtual void runAction(BlockBusItem * bus, const PluginAction & action) {}
	
	/// Check bus for warnings and errors
	virtual void checkBus(BlockBusItem * bus) {}
	
	/// Implement to apply bus changes (add or remove connections, change block properties, etc.)
	virtual void changed(BlockBusItem * bus) {}
	
	/// Implement to enable or disable logical connection between two pins. Default Implementation returns \b true
	virtual bool isConnected(BlockItemPin * pin0, BlockItemPin * pin1) {return true;}
	
	/// Implement to returns pairs of < pin_name, pin_path > list of pathes to read on \"this_pin\" from \"other_pin\".
	/// Default Implementation returns all devices at \"this_pin\"
	virtual QList<SSPair> readPathes(BlockItemPin * this_pin, BlockItemPin * other_pin);
	
	/// Implement to returns pairs of < pin_name, pin_path > list of pathes to write from \"this_pin\" to \"other_pin\".
	/// Default Implementation returns all devices at \"this_pin\"
	virtual QList<SSPair> writePathes(BlockItemPin * this_pin, BlockItemPin * other_pin);

};




class SHPluginBasePacket: public SHPluginBase {
public:
	explicit SHPluginBasePacket() {}
	virtual ~SHPluginBasePacket() {}

	enum ReceiveResult {
		rrFailure = 0x0,
		rrParsed  = 0x1, // check is ok
		rrInvoke  = 0x2, // invoke checked command
		rrSuccess = rrParsed | rrInvoke
	};
	Q_DECLARE_FLAGS(ReceiveResults, ReceiveResult)

	PluginType type() const {return SHPluginBase::Packet;}
	QString description() const {return "Packet plugin";}

	/// Invoke before script start, after load object-tree. You can prepare command "command"
	virtual void prepareCommand(SHS::Object & root, SHS::Object & object, SHS::Command & command) {;}

	/// Returns wait packet size, -1 if no fixed size
	virtual int receiveSize() {return -1;}

	/// Try to receive packet and parse arguments from it
	/// If success "args" map to "command.user_arguments" and pass to script call
	virtual ReceiveResults receivePacket(SHS::Object & root, SHS::Object & object, SHS::Command & command, QByteArray packet, QVariantMap & args) {return rrFailure;}

	/// Make packet from command. Script arguments already merged into "command" arguments
	virtual QByteArray sendPacket(SHS::Object & root, SHS::Object & object, SHS::Command & command) {return QByteArray();}

	virtual SHPacketWidgetBase * createEditor() {return 0;}

};




class SHPluginBaseScript: public SHPluginBase {
public:
	explicit SHPluginBaseScript() {}
	virtual ~SHPluginBaseScript() {}

	PluginType type() const {return SHPluginBase::Script;}
	QString description() const {return "Script plugin";}

	/// Implement to return logic representation of plugin
	virtual SHS::Object createObject() {return SHS::Object();}

	/// Process object command. Script arguments already merged into "command" arguments
	virtual bool processCommand(SHS::Object & root, SHS::Object & object, SHS::Command & command) {return true;}

	SHS::Object object;

};




class SHPluginBaseExtra: public SHPluginBase {
public:
	explicit SHPluginBaseExtra() {}
	virtual ~SHPluginBaseExtra() {}

	PluginType type() const {return SHPluginBase::Extra;}
	QString description() const {return "Extra plugin";}

	/// Request packet to detect device by device_watcher,
	/// better use broadcast address
	virtual QString deviceWatcherRequest() {return QString();}

	/// Answer packet to detect device by device_watcher,
	/// can contain %0 argument to extract address
	virtual QString deviceWatcherAnswer() {return QString();}

	/// Designer program name for device_watcher
	virtual QString deviceWatcherDesignerName() {return QString();}

	/// Designer program path for device_watcher,
	/// without extension
	virtual QString deviceWatcherDesignerPath() {return QString();}

	/// Designer program icon for device_watcher
	virtual QIcon deviceWatcherDesignerIcon() {return QIcon();}

	SHDesignerAPI * sh_designer_api = nullptr;

};


#endif
