local log = logging.new "htlatex"
local autolog = logging.new "autohtlatex"

local error_logparser = require("make4ht-errorlogparser")

local Make = Make or {}
-- this function reads the LaTeX log file and tries to detect fatal errors in the compilation
local function testlogfile(par)
 local logfile = mkutils.file_in_builddir(par.input .. ".log", par)
 local f = io.open(logfile,"r")
 if not f then
   log:warning("Make4ht: cannot open log file "..logfile)
   return 1
 end
 local content = f:read("*a")
 -- test only the end of the log file, no need to run search functions on everything
 local text = content:sub(-1256)
 f:close()
 -- parse log file for all errors in non-interactive modes
 if par.interaction~="errorstopmode" then
   -- the error log parsing can be slow, so detect errors first
   -- detect both default error messages (! msg) and -file-line-number errors (filename:lineno:msg)
   if content:match("\n!") or content:match("[^:]+%:%d+%:.+")  then
     local errors, chunks = error_logparser.parse(content)
     if #errors > 0 then
       log:error("Compilation errors in the htlatex run")
       log:error("Filename", "Line", "Message")
       for _, err in ipairs(errors) do
         log:error(err.filename or "?", err.line or "?", err.error)
         log:status(err.context)
       end
     end
   end
 end
 -- info about packages with no corresponding .4ht files
 local missing_4ht = error_logparser.get_missing_4ht_files(content)
 for _, filename in ipairs(missing_4ht) do log:info("Unsupported file: " .. filename) end
 -- test for fatal errors
 if text:match("No pages of output") or text:match("TeX capacity exceeded, sorry") or text:match("That makes 100 errors") or text:match("Emergency stop") then return 1 end
 return 0
end


-- Make this function available in the build files
Make.testlogfile = testlogfile
--env.Make:add("htlatex", "${htlatex} ${latex_par} '\\\makeatletter\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{\\g@addto@macro\\@documentclasshook{\\RequirePackage[#1,html]{tex4ht}\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{\\documentstyle[tex4ht]}}}\\makeatother\\HCode '${config}${tex4ht_sty_par}'.a.b.c.\\input ' ${input}")

-- template for calling LaTeX with tex4ht loaded
Make.latex_command = "${htlatex} --interaction=${interaction} ${build_dir_arg} ${latex_par} '\\makeatletter"..
"\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode"..
"\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else"..
"\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{"..
"\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle"..
"\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def"..
"\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{"..
"\\documentstyle[tex4ht]}}\\RequirePackage[#1,html]{tex4ht}${packages}}\\makeatother\\HCode ${tex4ht_sty_par}.a.b.c."..
"\\input \"\\detokenize{${tex_file}}\"'"

Make.plain_command = '${htlatex} --interaction=${interaction} ${build_dir_arg} ${latex_par}' ..
"'\\def\\Link#1.a.b.c.{\\expandafter\\def\\csname tex4ht\\endcsname{\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\input tex4ht.sty }}" ..
"\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else\\expandafter\\Link\\fi}" ..
"\\HCode ${tex4ht_sty_par}.a.b.c.\\input \"\\detokenize{${tex_file}}\"'"


local m = {}

function m.htlatex(par, latex_command)
 -- latex_command can be also plain_command for Plain TeX
 local command = latex_command or Make.latex_command
 local devnull = " > /dev/null 2>&1"
 if os.type == "windows" then
   command = command:gsub("'",'')
   devnull = " > nul 2>&1"
 end
 par.interaction = par.interaction or "batchmode"
 if par.builddir~="" then
     par.build_dir_arg = "--output-directory=${builddir}" % par
 else
     par.build_dir_arg = ""
 end
 if par.interaction == "batchmode" then
   command = command .. devnull
 end
 command = command % par
 log:info("LaTeX call: "..command)
 os.execute(command)
 return Make.testlogfile(par)
end

function m.httex(par)
 local newpar = {}
 for k,v in pairs(par) do newpar[k] = v end
 -- change executable name from *latex to *tex
 newpar.htlatex = newpar.htlatex:gsub("latex", "tex")
 -- plain tex command doesn't support etex extensions
 -- which are necessary for TeX4ht. just quick hack to fix this
 if newpar.htlatex == "tex" then newpar.htlatex = "etex" end
 return m.htlatex(newpar, Make.plain_command)
end


local function get_checksum(main_file, extensions, par)
 -- make checksum for temporary files
 local checksum = ""
 local extensions = extensions or {"aux", "4tc", "xref"}
 for _, ext in ipairs(extensions) do
   local filename = mkutils.file_in_builddir(main_file .. "." .. ext, par)
   local f = io.open(filename, "r")
   if f then
     local content = f:read("*all")
     f:close()
     -- make checksum of the file and previous checksum
     -- this way, we will detect change in any file
     checksum = md5.sumhexa(checksum .. content)
   end
 end
 return checksum
end

-- this function runs htlatex multiple times until the checksum of temporary files doesn't change
Make:add("autohtlatex", function(par)
 -- get checksum of temp files before compilation
 local options = get_filter_settings "autohtlatex"
 local extensions = par.auto_extensions or options.auto_extensions or {"aux", "4tc", "xref"}
 local max_compilations  = par.max_compilations or options.max_compilations or  5
 local checksum = get_checksum(par.input, extensions, par)
 local status = m.htlatex(par)
 -- stop processing on error
 if status ~= 0 then
   autolog:info("Stopping after first run, with status: " .. status)
   return status
 end
 -- get checksum after compilation
 local newchecksum = get_checksum(par.input, extensions, par)
 -- this is needed to prevent possible infinite loops
 local compilation_count = 1
 while checksum ~= newchecksum do
   -- stop processing if we reach maximum number of compilations
   if compilation_count > max_compilations then
     autolog:info("Stopping after " .. max_compilations .. " compilations")
     return status
   end
   status = m.htlatex(par)
   -- stop processing on error
   if status ~= 0 then return status end
   checksum = newchecksum
   -- get checksum after compilation
   newchecksum = get_checksum(par.input, extensions, par)
   compilation_count = compilation_count + 1
 end
 return status
end)

return m