local M = {}

local mkutils = require "mkutils"

local log = logging.new "xtpipes"
-- find if tex4ht.jar exists in a path
local function find_tex4ht_jar(path)
 local jar_file = path .. "/tex4ht/bin/tex4ht.jar"
 return mkutils.file_exists(jar_file)
end

-- return value of TEXMFROOT variable if it exists and if tex4ht.jar can be located inside
local function get_texmfroot()
 -- user can set TEXMFROOT environmental variable as the last resort
 local root_directories = {kpse.var_value("TEXMFROOT"), kpse.var_value("TEXMFDIST"), os.getenv("TEXMFROOT")}
 for _, root in ipairs(root_directories) do
   if root then
     if find_tex4ht_jar(root) then return root end
     -- TeX live locates files in texmf-dist subdirectory, but Miktex doesn't
     local path = root .. "/texmf-dist"
     if find_tex4ht_jar(path) then return path end
   end
 end
end

-- Miktex doesn't seem to set TeX variables such as TEXMFROOT
-- we will try to find the TeX root using trick with locating package in TeX root
-- there is a danger that this file is located in TEXMFHOME, the location will fail then
local function find_texmfroot()
 local tex4ht_path = kpse.find_file("tex4ht.sty")
 if tex4ht_path then
   local path = tex4ht_path:gsub("/tex/generic/tex4ht/tex4ht.sty$","")
   if find_tex4ht_jar(path) then return path end
 end
 return nil
end

function M.get_selfautoparent()
 return get_texmfroot() or find_texmfroot()
end

local function replace_lg_file()
 -- xtpipes expects the lg file to be placed in the current working dir, but with the --build option,
 -- it is saved in the build dir. So we need to copy that file to the place where it is expected.
 local params = Make.params
 local basename = params.input
 local lg_name = basename .. ".lg"
 local lg_in_builddir = mkutils.file_in_builddir(lg_name,params)
 if lg_name ~= lg_in_builddir and mkutils.file_exists(lg_in_builddir) then
   log:info("Creating temporary lg_file", lg_name)
   mkutils.cp(lg_in_builddir, lg_name)
   return true, lg_name
 end
 -- don't copy the Lg file if --build_fir option isn't used
 return false, lg_name
end

function M.get_xtpipes(selfautoparent)
 -- make pattern using TeX distro path
 local pattern = string.format('java -classpath "%s/tex4ht/bin/tex4ht.jar" xtpipes -i "%s/tex4ht/xtpipes/" -o "${outputfile}" "${filename}"', selfautoparent, selfautoparent)
 -- call xtpipes on a temporary file
 local matchfunction =  function(filename)
   -- move the matched file to a temporary file, xtpipes will write it back to the original file
   local basename = mkutils.remove_extension(filename)
   local tmpfile = basename ..".tmp"
   local remove, lg_filename = replace_lg_file()
   mkutils.mv(filename, tmpfile)
   local command = pattern % {filename = tmpfile, outputfile = filename}
   log:info("execute: " ..command)
   local status, output = mkutils.execute(command)
   -- remove temporary lg file if it was created
   if remove then os.remove(lg_filename) end
   if status > 0 then
     -- if xtpipes failed to process the file, it may mean that it was bad-formed xml
     -- we can try to make it well-formed using Tidy
     local tidy_command = 'tidy -utf8 -xml -asxml -q -o "${filename}" "${tmpfile}"' % {tmpfile = tmpfile, filename = filename}
     log:warning("Xtpipes failed")
     -- show_level 1 is debug mode, which prints command output as well
     -- we need this condition to prevent multiple instances of the output
     if logging.show_level > 1 then
       print(output)
     end
     log:warning("Trying HTML tidy")
     log:debug(tidy_command)
     local status, output = os.execute(tidy_command)
     if status > 0 then
       -- if tidy failed as well, just use the original file
       -- it will probably produce corrupted ODT file though
       log:warning("Tidy failed as well")
       if logging.show_level > 1 then
         print(output)
       end
       mkutils.mv(tmpfile, filename)
     end
   end
 end
 return matchfunction
end

-- This function moves the last added file matching function to the first place
-- in the execution order. This ensures that filters are executed in the
-- correct order.
function M.move_matches(make)
 local matches = make.matches
 local last = matches[#matches]
 table.insert(matches, 1, last)
 matches[#matches] = nil
end

M.get_texmfroot = get_texmfroot
M.find_texmfroot = find_texmfroot
M.find_tex4ht_jar = find_tex4ht_jar
return M