--[[
  @package    eg4-crank-ui-2
  @file       destination-list.lua
  @brief      Handles the destination browser list
]]

local BROWSE_LAYER = "destination_browse_layer"
local BROWSE_LIST_CONTROL = BROWSE_LAYER..".list"
local NAVIGATION_GROUP = BROWSE_LAYER..".navigate"

local info = {}

---
--- @brief  Trim a string to the length of the destination ..index..
--- @param  self - string to trim
--- @return trimmed string
---
function string:trim_destination_id()
  return self:sub(1, get_destination_id_len())
end

---
--- @brief  Get the height of the recent list layer
--- @return The layer height
local function get_table_height()
  return gre.get_value(BROWSE_LIST_CONTROL..".grd_height")
end
---
--- @brief  Get the number of items per page
--- @return The number of items per page
local function get_items_per_page()
  local control_height = gre.get_table_cell_attrs(BROWSE_LIST_CONTROL, 1, 1, "height").height
  return math.floor(get_table_height() / control_height + 0.5)
end

---
--- @brief  Set the navigation controls depending on the current index
local function set_navigation_controls()
  local scroll_marker_top = 0
  if info.pages > 1 then
    local height = gre.get_value(NAVIGATION_GROUP..".sep.grd_height")
    local sep = gre.get_value(NAVIGATION_GROUP..".sep.height")
    scroll_marker_top = math.floor((height - sep) * info.page / (info.pages - 1) + 0.5)
  end

  local data = {}
  data[NAVIGATION_GROUP..".sep.y"] = scroll_marker_top
  data[NAVIGATION_GROUP..".up.grd_active"] = info.page > 0
  data[NAVIGATION_GROUP..".up.alpha_disabled"] = info.page > 0 and 255 or 83
  data[NAVIGATION_GROUP..".down.grd_active"] = info.page < info.pages - 1
  data[NAVIGATION_GROUP..".down.alpha_disabled"] = (info.page < info.pages - 1) and 255 or 83
  data[NAVIGATION_GROUP..".paging.grd_hidden"] = info.pages < 2
  data[NAVIGATION_GROUP..".paging.rich_text"] = make_page_text(info.page + 1, info.pages)
  gre.set_data(data)
end

---
--- @brief  Update the destination list table.
local color_pressed
local color_normal
local color_select
function update_destination_display()
  set_navigation_controls()
  color_pressed = gre.get_value("color_list_pressed_text_option")
  color_normal = gre.get_value("color_list_text_option")
  color_select = gre.get_value("color_list_text_title")
  animate_variable(BROWSE_LIST_CONTROL..".scrolling_bind", info.page * info.items_per_page)
end

function cb_update_destination_list(mapargs)
  local data = {}
  local rows = info.items_per_page
  local index = gre.get_value(mapargs.context_control..".scrolling_bind")
  for i=1,info.items_per_page do
    local text = get_destination_list_item(index + i)
    if text == nil then rows = i - 1 break end

    -- Strip driver message from destination
    data[mapargs.context_control..".destination_id."..i..".1"] = text:sub(1, get_destination_id_len())
    data[mapargs.context_control..".text."..i..".1"] = highlight_filtered_text(text, info.last_filter_value, color_normal, color_select)
    data[mapargs.context_control..".released."..i..".1"] = data[mapargs.context_control..".text."..i..".1"]
    data[mapargs.context_control..".pressed."..i..".1"] = highlight_filtered_text(text, info.last_filter_value, color_pressed, color_pressed)
    data[mapargs.context_control..".selected."..i..".1"] = (info.selected_index == index + i) and 48 or 0
  end
  gre.set_data(data)
  gre.set_table_attrs(mapargs.context_control, { rows = rows, hidden = (rows == 0) })
end

---
--- @brief  Initialises the current destination list and filter, then requestes a
---         new destination list.
--- @param  filter - filter text or nil to clear
function cb_initialise_destination_list(filter)

  -- Determine entry to highlight
  local highlight_item = get_current_destination_id()
  if select_round_trip_active() then
    if select_round_trip_out() then
      highlight_item = select_round_trip_out()
    end
  else
    -- Highlight the last selected destination if it is not the current destination
    highlight_item = sbsettings.get_destination_local_last()
  end

  filter = filter or info.last_filter_value or ""
  local size, index = update_destination_list(selected_route_code(), filter, highlight_item)

  -- Center on previously highlighted item if present
  info.selected_index = index
  if select_round_trip_active() and not select_round_trip_out() then
    info.selected_index = nil
  end
  info.size = size
  info.items_per_page = get_items_per_page()
  info.pages = math.ceil(info.size / info.items_per_page)
  info.last_filter_value = filter

  if index == nil or index == 0 then index = 1 end
  info.page = math.floor((index - 1) / info.items_per_page)

  gre.set_value(BROWSE_LIST_CONTROL..".scrolling_bind", info.page * info.items_per_page)
  update_destination_display()
  cb_update_destination_list({ context_control = BROWSE_LIST_CONTROL })
end

---
--- @brief  Callback to perform the navigation repeat
--- @param  dir  The direction to navigate (-1 for up, 1 for down)
--- @return true if the navigation was rejected
function cb_destination_list_navigate(mapargs)
  info.page = info.page + mapargs.dir
  if info.page < 0 then
    info.page = 0
    return true
  end
  if info.page >= info.pages then
    info.page = info.pages - 1
    return true
  end
  update_destination_display()
end
