#pragma once

#include "plugin/BasePlugin.h"
#include "device/DeviceDriver.h"
#include "context/CallerController.h"
#include "context/Context.h"
#include "datatable/TableFormat.h"
#include "device/DeviceContext.h"
#include "device/sync/SynchronizationParameters.h"

#include "context/VariableStatus.h"
#include "context/EventDefinition.h"
#include "context/FunctionDefinition.h"
#include "context/VariableDefinition.h"
#include <string>

class AbstractDeviceDriver : public BasePlugin , public DeviceDriver
{

private:
    DeviceContextPtr deviceContext;
    bool connected;
    AgString protocol;
    TableFormatPtr connectionPropertiesFormat;

public:
	AbstractDeviceDriver();
    AbstractDeviceDriver(const AgString& description, TableFormatPtr connectionPropertiesFormat);
    AbstractDeviceDriver(const AgString& description, const AgString& protocol, TableFormatPtr connectionProperties);

    AgString getPrimaryAddress();
	AgString getStatus();
	std::list<Expression>  getStatusExpressions(CallerControllerPtr aCallerController);
    void setupDeviceContext(DeviceContextPtr deviceContext) ;
    void configureDeviceAccount(DeviceContextPtr deviceContext, CallerControllerPtr caller) ;
    void accessSettingUpdated(const AgString& name);
    bool shouldSynchronize(SynchronizationParametersPtr parameters) ;
    void startSynchronization() ;
    bool isUsesConnections();
    bool isConnected();
    void connect() ;
    bool isUsesAssets();
	std::list<DeviceAssetDefinition>  readAssets();
    bool isUseDeviceSideValuesCache();

    virtual std::list<VariableDefinition>  readVariableDefinitions();
    virtual std::list<VariableDefinition>  readVariableDefinitions(std::list<DeviceAssetDefinition>  groups) ;

    virtual std::list<FunctionDefinition>  readFunctionDefinitions();
    virtual std::list<FunctionDefinition>  readFunctionDefinitions(std::list<DeviceAssetDefinition>  groups);

    virtual std::list<EventDefinition>     readEventDefinitions();
    virtual std::list<EventDefinition>     readEventDefinitions(std::list<DeviceAssetDefinition>  groups);

    virtual DataTablePtr readVariableValue(VariableDefinitionPtr vd);
    virtual void writeVariableValue(VariableDefinitionPtr vd, DataTablePtr value, DataTablePtr deviceValue);
    virtual DataTablePtr executeFunction(FunctionDefinitionPtr fd, DataTablePtr parameters);
    AgDatePtr getVariableModificationTime(const AgString& name) ;
    void updateVariableModificationTime(const AgString& name, AgDatePtr value) ;
    VariableStatusPtr getCustomVariableStatus(const AgString& name) ;
    void disconnect();
    virtual void finishSynchronization();
    void setConnected(bool connected);
    DeviceContextPtr getDeviceContext();
	DiscoveryProviderPtr createDiscoveryProvider();
	AgString getProtocol();
	TableFormatPtr getConnectionPropertiesFormat();

    TableFormatPtr createConnectionPropertiesFormat();
    VariableDefinitionPtr discoverVariable(const AgString& name, AgObjectPtr helper);
	FunctionDefinitionPtr discoverFunction(const AgString& name, AgObjectPtr helper);
    EventDefinitionPtr discoverEvent(const AgString& name, AgObjectPtr helper);	
};
