Logger:Info("-- download_handler_5.lua: init optional modules")

-- load modules
local sdamanager = require("sdamanager_module")
local monitoring = require("monitoring_module")
local datalogger = require("datalogger_module")
local timeserver = require("timemanager_module")
local recording = require("recording_module")
local usc = require("usc_module")

-- defines
local KimParameterInterfaceObjectId = 40960
local kimInterfaceObject = PropertyService:GetInterfaceObjectByTypeAndInstance(KimParameterInterfaceObjectId, 1)

local coDptPropertyData = kimInterfaceObject:GetPropertyById(64):GetValue()
-- local dptFlagsPropertyData = kimInterfaceObject:GetPropertyById(66):GetValue()
-- local ipParameterPropertyData = kimInterfaceObject:GetPropertyById(68):GetValue()
local numberParameterProperty = kimInterfaceObject:GetPropertyById(69)
local kimParameterPropertyData = kimInterfaceObject:GetPropertyById(71):GetValue(0,10)
local kimAppIdPropertyData = kimInterfaceObject:GetPropertyById(72):GetValue()
local timezoneIdPropertyData = kimInterfaceObject:GetPropertyById(73):GetValue()

-- set the configuration as KnxDevice channel parameter set for the web UI
local configuration = {}

-- usage statistics client config
local uscConfig = {}

-- local helper functions
function GetTextParam(num)
	return AppPrg1Data:GetAsString((num -1) * 128)
end

function GetCoDpt(num)
	local dptMainType = coDptPropertyData:GetAsUInt16((num -1) * 4 )
	local dptSubType = coDptPropertyData:GetAsUInt16((num -1) * 4 + 2 )
	return dptMainType, dptSubType
end

-- sdamanager module
-- order from PDB description; use 0 to disable a CO
sdamanager.CO.vpnAccessCo		= 0
sdamanager.CO.vpnAccessStatusCo	= 0
sdamanager.CO.vpnCurrentStateCo	= 0

sdamanager.AddCosToMap()
local sdaManagerAppConfig = {}
uscConfig["sdamanager"] = sdaManagerAppConfig
sdaManagerAppConfig.GeneralRemoteAccessAfterRestart = numberParameterProperty:GetValue(0,1):GetAsUInt(3,1)
sdaManagerAppConfig.ResidentRemoteAccessAfterRestart = numberParameterProperty:GetValue(1,1):GetAsUInt(3,1)
sdaManagerAppConfig.InstallerRemoteAccessAfterRestart = numberParameterProperty:GetValue(2,1):GetAsUInt(3,1)
sdamanager.Configure(sdaManagerAppConfig)
table.insert(configuration, "SdaService")

-- timeserver module
local timeServerAppConfig = {}
uscConfig["timeserver"] = timeServerAppConfig
timeServerAppConfig.EnabledBool = kimParameterPropertyData:GetAsUInt(3,1) == 1
timeServerAppConfig.SendTimeInterval = kimParameterPropertyData:GetAsUInt(4,1)
timeServerAppConfig.SendDateInterval = kimParameterPropertyData:GetAsUInt(5,1)
timeServerAppConfig.TimezonePDBId = timezoneIdPropertyData:GetAsUInt(0,2)
timeserver.Configure(timeServerAppConfig)
if timeServerAppConfig.EnabledBool then
	timeserver.AddCosToMap()
    table.insert(configuration, "TimeServer")
end

-- datalogger module
local dataLoggerAppConfig = {}
uscConfig["datalogger"] = dataLoggerAppConfig
dataLoggerAppConfig.EnabledBool = kimParameterPropertyData:GetAsUInt(6,1) == 1
dataLoggerAppConfig.LoggingFormat = kimParameterPropertyData:GetAsUInt(7,1)
dataLoggerAppConfig.BufferType = kimParameterPropertyData:GetAsUInt(8,1)
datalogger.Configure(dataLoggerAppConfig)
if dataLoggerAppConfig.EnabledBool then
	datalogger.AddCosToMap()
	table.insert(configuration, "DataLogger")
end

-- monitoring module (notification)
local monitoringAppConfig = {}
uscConfig["monitoring"] = monitoringAppConfig
monitoringAppConfig.EnabledBool = false
monitoringAppConfig.NumberOfNotifications = 0
local numVal = numberParameterProperty:GetValue(4,1):GetAsUInt32()
local floatingPointSeparator = (numVal >> 24) & 1
local numberOfNotifications = 50

Logger:Info(string.format("-- add %d notification COs", numberOfNotifications))
local notificationStartCo = 101
local thresholdBaseMapping = {[0] = 1000, [1] = 100, [2] = 10, [3] = 1, [4] = 0.1, [5] = 0.01, [6] = 0.001}
local textParamOffset = 5
for channelNumber = 1, numberOfNotifications do
	local co = notificationStartCo + channelNumber - 1
	local groupObjectDescriptor = GroupValueService:GetGroupObjectDescriptor(co)
	if not groupObjectDescriptor:IsCommunicationEnabled() then
		Logger:Info("Skip notification " .. channelNumber .. " because communication not enabled")
	else
		monitoringAppConfig.EnabledBool = true
    monitoringAppConfig.NumberOfNotifications = monitoringAppConfig.NumberOfNotifications + 1
		local textParam = 1 + textParamOffset * (channelNumber-1);
		local numParamIdx = channelNumber + 5 -1	
		local numParamValue  = numberParameterProperty:GetValue(numParamIdx, 1):GetAsUInt32()
		local thresholdBase = thresholdBaseMapping[(numParamValue >> 28) & 15] -- 15 -> 4bit
		local thresholdValue = (numParamValue >> 16) & 4095  -- 4095 -> 12bit
		local dptMainType, dptSubType = GetCoDpt(co)
		local dpt = string.format(dptSubType < 100 and "%d.%03d" or "%d.%d", dptMainType, dptSubType)
		
		local config = {}
		if dptMainType == 1 then
			config.DptId = 0
		elseif dptMainType == 5 and dptSubType == 1 then
			config.DptId = 1
		elseif dptMainType == 5 then
			config.DptId = 2
		elseif dptMainType == 9 then
			config.DptId = 3
		elseif dptMainType == 16 then
			config.DptId = 4
		end
		
		config.FloatingPointSeparator = floatingPointSeparator
		
		config.Subject = 		GetTextParam(textParam + 0 )
		config.Text = 			GetTextParam(textParam + 1 )
		config.Filter = 		GetTextParam(textParam + 2 )
		if dptMainType == 1 then
			if config.Filter == "0" then
				config.Filter = 2
			elseif config.Filter == "1" then
				config.Filter = 1
			else
				config.Filter = 0
			end
		end
		config.AttachmentURL = 	        GetTextParam(textParam + 3 )
		config.Category =               GetTextParam(textParam + 4 )
		config.NotifyOnlyOnChange =     (numParamValue & 1) == 1   -- true or false
		config.Priority =               (numParamValue >> 8) & 255 --  255 -> 8bit
		if config.NotifyOnlyOnChange == 1 and dptMainType ~= 1 then
			config.Threshold = thresholdValue * thresholdBase + .0
		end

		helper.LogConfiguration("Notification " .. channelNumber, config)

		helper.AddAssociatedCoToMap(co, "CW", dpt, string.format("%s:Monitoring-%d:InputValue", deviceUrn_base, channelNumber))
    	monitoring.CreateNotificationDefiniton(channelNumber, config);
	end
end
if monitoringAppConfig.EnabledBool then
	table.insert(configuration, "Notification")
end
monitoring.Configure(monitoringAppConfig)

-- no recording module
local recordingAppConfig = {}
uscConfig["recording"] = recordingAppConfig
recordingAppConfig.EnabledBool = false
recordingAppConfig.NumberOfRecordings = 0
recording.ConfigureAppChannel(recordingAppConfig)

-- fill the KNX-Device-1 with the loaded configuration
local channel = device:AddChannel("KNX-Device-1")
channel:AddParameterSet("Application", "Configuration", table.concat(configuration,","))

-- collect and send usage statistics data
usc.CollectData(uscConfig) 
usc.TriggerSendingData()

Logger:Info("-- S89default_knxdownload start / enable ApplicationProgram2 and restart knxstack if changed")
os.execute("/etc/init.d/S89default_knxdownload start")

Logger:Info("-- download_handler_5.lua: done")
