---
-- @package   eg4-crank-ui
-- @file      spin-control.lua
-- @brief     Functionality related to handling spin updates.
--
-- @copyright Copyright 2019 Hanover Displays Limited.
-- @license   This program is the confidential and proprietary product of
--            Hanover Displays Limited. Any unauthorised use, reproduction or
--            transfer of this program is strictly prohibited. (Subject to
--            limited distribution and restricted disclosure only.) All
--            rights reserved.
--
--

local context

---
--- @brief  Set the spin control value.
--- @param  control - control to update
--- @param  value - value to write
---
function SetSpinControlValue(control, value)
  local scale = tonumber(gre.get_value(control..".scale")) or 1
  local text = value / scale

  local format = gre.get_value(control..".format")
  if format then
    text = string.format(format, text)
  end

  gre.set_value(
    control..".text", text,
    control..".value", value)
end

---
--- @brief  Called when the count stops changing
--- @param  callback - function for processing the new value.
---
local function StopCount(mapargs)
  if context then
    gre.timer_clear_interval(context.timer_id)

    -- Collect values
    mapargs.value = context.value
    mapargs.context_control = context.control
    context = nil

    -- Get port id from parameter, group, or screen
    mapargs.port_id = mapargs.port_id or gre.get_value(mapargs.context_group..".port_id") or gre.get_value(mapargs.context_screen..".port_id")

    -- Check if a set function exists for this component.
    local fn = mapargs.context_control:split(".")
    fn = "set_"..fn[#fn]:sub(1,-6)
    fn = _G[fn] or sbsettings[fn]
    if fn then
      fn(mapargs.value, mapargs.port_id)
    end

    -- If specified, run callback
    local callback = _G[mapargs.callback] or _G[gre.get_value(mapargs.context_control..".callback")]
    if type(callback) == "function" then
      callback(mapargs)
    end

    -- If specified, send event to backend
    local event = mapargs.event or gre.get_value(mapargs.context_control..".event")
    if event then
      SendEvent(event)
    end
  end
end

---
--- @brief  Timer callback to update the value and handle the acceleration of the updates.
---
local function UpdateValue()
  context.value = context.value + context.count_direction
  
  if context.rollover == 1 then
    if context.value < context.min then
      context.value = context.max
    elseif context.value > context.max then
      context.value = context.min
    end
  end 

  SetSpinControlValue(context.control, context.value)

  if context.repeat_count == 3 then
    gre.timer_clear_interval(context.timer_id)
    context.timer_id = gre.timer_set_interval(UpdateValue, 100)
  elseif context.repeat_count == 8 then
    gre.timer_clear_interval(context.timer_id)
    context.timer_id = gre.timer_set_interval(UpdateValue, 50)
  elseif repeat_count == 18 then
    gre.timer_clear_interval(context.timer_id)
    context.timer_id = gre.timer_set_interval(UpdateValue, 25)
  end
  context.repeat_count = context.repeat_count + 1
end

---
--- @brief  Callback to start the spin control.
--- @param  gre#context mapargs
---
function CBSpinControlPress(mapargs)

  context = {
    control = mapargs.context_control,
    value = tonumber(gre.get_value(mapargs.context_control .. ".value") or gre.get_value(mapargs.context_control .. ".text")),
    min = tonumber(mapargs.min or gre.get_value(mapargs.context_control .. ".max") or 999),
    max = tonumber(mapargs.max or gre.get_value(mapargs.context_control .. ".min") or 0),
    count_direction = tonumber(mapargs.step_value) or gre.get_value(mapargs.context_control .. ".step_value") or 1,
    rollover = tonumber(mapargs.rollover) or gre.get_value(mapargs.context_control .. ".step_rollover") or 0,
    repeat_count = 0,
    timer_id = gre.timer_set_interval(UpdateValue, 500)
  }

  local attrs = gre.get_layer_attrs(mapargs.context_layer, "x")
  local gx = attrs.x
  local attrs = gre.get_group_attrs(mapargs.context_group, "x")
  if attrs ~= nil and attrs.x ~= nil then
    gx = gx + attrs.x
  end
  local attrs = gre.get_control_attrs(context.control, "x", "width")
  local x = mapargs.context_event_data.x - attrs.x - gx
  if x < attrs.width / 2 then
    gre.set_value(context.control .. ".minus_down_alpha", 255) 
    context.count_direction = -context.count_direction
  else
    gre.set_value(context.control .. ".plus_down_alpha", 255) 
  end 

  UpdateValue()
end

---
--- @brief  Stops the spin control from updating
--- @param  gre#context mapargs
---
function CBSpinControlRelease(mapargs) 
  StopCount(mapargs)
end

---
--- @brief  Test callback for spin control updates.
---
function CBTestSpinControl(mapargs)
  print (mapargs.value)
end

-- EOF --
