-- Document key bindings

local awful     = require("awful")
local table     = table
local ipairs    = ipairs
local pairs     = pairs
local math      = math
local string    = string
local type      = type
local modkey    = "Mod4"
local beautiful = require("beautiful")
local naughty   = require("naughty")
local capi      = {
   root = root,
   client = client
}

module("keydoc")

local doc = { }
local currentgroup = "Misc"
local orig = awful.key.new

-- Replacement for awful.key.new
local function new(mod, key, press, release, docstring)
   -- Usually, there is no use of release, let's just use it for doc
   -- if it's a string.
   if press and release and not docstring and type(release) == "string" then
      docstring = release
      release = nil
   end
   local k = orig(mod, key, press, release)
   -- Remember documentation for this key (we take the first one)
   if k and #k > 0 and docstring then
      doc[k[1]] = { help = docstring,
		    group = currentgroup }
   end

   return k
end
awful.key.new = new		-- monkey patch

-- Turn a key to a string
local function key2str(key)
   local sym = key.key or key.keysym
   local translate = {
      ["#14"] = "#",
      [" "] = "Space",
   }
   sym = translate[sym] or sym
   if not key.modifiers or #key.modifiers == 0 then return sym end
   local result = ""
   local translate = {
      [modkey] = "⊞",
      Shift    = "⇧",
      Control  = "Ctrl",
   }
   for _, mod in pairs(key.modifiers) do
      mod = translate[mod] or mod
      result = result .. mod .. " + "
   end
   return result .. sym
end

-- Unicode "aware" length function (well, UTF8 aware)
-- See: http://lua-users.org/wiki/LuaUnicode
local function unilen(str)
   local _, count = string.gsub(str, "[^\128-\193]", "")
   return count
end

-- Start a new group
function group(name)
   currentgroup = name
   return {}
end

local function markup(keys)
   local result = {}

   -- Compute longest key combination
   local longest = 0
   for _, key in ipairs(keys) do
      if doc[key] then
	 longest = math.max(longest, unilen(key2str(key)))
      end
   end

   local curgroup = nil
   for _, key in ipairs(keys) do
      if doc[key] then
	 local help, group = doc[key].help, doc[key].group
	 local skey = key2str(key)
	 result[group] = (result[group] or "") ..
	    '<span font="DejaVu Sans Mono 10" color="' .. beautiful.fg_widget_clock .. '"> ' ..
	    string.format("%" .. (longest - unilen(skey)) .. "s  ", "") .. skey ..
	    '</span>  <span color="' .. beautiful.fg_widget_value .. '">' ..
	    help .. '</span>\n'
      end
   end

   return result
end

-- Display help in a naughty notification
local nid = nil
function display()
   local strings = awful.util.table.join(
      markup(capi.root.keys()),
      capi.client.focus and markup(capi.client.focus:keys()) or {})

   local result = ""
   for group, res in pairs(strings) do
      if #result > 0 then result = result .. "\n" end
      result = result ..
	 '<span weight="bold" color="' .. beautiful.fg_widget_value_important .. '">' ..
	 group .. "</span>\n" .. res
   end
   nid = naughty.notify({ text = result,
			  replaces_id = nid,
			  hover_timeout = 0.1,
			  timeout = 30 }).id
end
