-- gitano.i18n
--
-- Internationalisation support for Gitano
--
-- Copyright 2016-2017 Daniel Silverstone <dsilvers@digital-scurf.org>
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
-- 1. Redistributions of source code must retain the above copyright
--    notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright
--    notice, this list of conditions and the following disclaimer in the
--    documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the author nor the names of their contributors
--    may be used to endorse or promote products derived from this software
--    without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-- SUCH DAMAGE.
--

local tongue = require "tongue"

local _util = nil
local function util()
   if _util == nil then
      _util = require "gitano.util"
   end
   return _util
end

local basepath, pluginpaths = nil, {}

local function add_plugin_path(path)
   pluginpaths[#pluginpaths+1] = path
end

local codex = nil

local function get_base_lang(lang, sublang)
   if sublang then lang = lang .. "_" .. sublang end
   local fh = io.open(util().path_join(basepath, lang .. ".parent"), "r")
   if fh then
      local parent = fh:read("*a"):gsub("\n", "")
      fh:close()
      return parent
   end
end

local function new_gitano_pack(codex, lang, sublang)
   local base = get_base_lang(lang, sublang) or (sublang and lang) or
      ((lang ~= "json" and lang ~= "en") and "en")
   if base then
      base = codex:get_langpack(base)
   end
   return tongue.langpack.create(lang, sublang, base)
end

local function base_packloader(codex, pack, fulllang)
   local chunk, err = loadfile(util().path_join(basepath, fulllang .. ".lua"))
   if chunk then
      local ok, tab = pcall(chunk)
      if ok and type(tab) == "table" then
         -- Able to load the base pack, so inject it...
         for k, v in pairs(tab) do
            pack:add_token(k, v)
         end
      end
   end
end

local function initialise()
   assert(basepath, "No basepath provided!")
   if codex then return end
   codex = tongue.codex.create(new_gitano_pack)
   codex:add_loader(base_packloader)
end

local function plugin_packloader(codex, pack, fulllang, path)
   local chunk, err = loadfile(path .. fulllang .. ".lua")
   if chunk then
      local ok, tab = pcall(chunk)
      if ok and type(tab) == "table" then
         -- Able to load the plugin pack, so inject it...
         for k, v in pairs(tab) do
            pack:add_token(k, v)
         end
      end
   end
end

local function set_langpack_path(path)
   basepath = path
   initialise()
   codex:add_loader(function(codex, pack, fulllang)
         return plugin_packloader(codex, pack, fulllang, path)
   end)
end

local activelang, activesublang, activeencoding = nil, nil, nil

local function set_category(cat)
   local env
   if cat then
      env = { LC_ALL = cat }
   end
   activeencoding, activelang = tongue.transliteration.guess(env)
   if not activelang then activelang = "en" end
   local lang, sublang = tongue.util.split_category(activelang)
   activelang, activesublang = lang, sublang
end

local function expand(token, vars)
   initialise()
   return activeencoding:touser(codex:expand(activelang, activesublang,
                                             token, vars or {}))
end

local function decode(s)
   return activeencoding:fromuser(s)
end

local function encode(s)
   return activeencoding:touser(s)
end

return {
   set_langpack_path = set_langpack_path,
   add_plugin_path = add_plugin_path,
   set_category = set_category,
   expand = expand,
   decode = decode,
   encode = encode,
}
