local lapp = require "lapp-mk4"
local mkutils = require "mkutils"
local m = {} -- use ugly module system for new lua versions support
local log = logging.new "mkparams"

-- these two variables will be used in the version number
-- progname will be set in get_args
m.progname = "make4ht"
-- set the version number before call to process_args()
m.version_number = "v0.1"

m.optiontext =  [[
${progname} - build system for TeX4ht
Usage:
${progname} [options] filename ["tex4ht.sty op."] ["tex4ht op."] ["t4ht op"] ["latex op"]

Available options:
 -a,--loglevel (default status) Set log level.
               possible values: debug, info, status, warning, error, fatal
 -b,--backend (default tex4ht) Backend used for xml generation.
               possible values: tex4ht or lua4ht
 -c,--config (default xhtml) Custom config file
 -d,--output-dir (default nil)  Output directory
 -B,--build-dir (default nil)  Build directory
 -e,--build-file (default nil)  If build file is different than `filename`.mk4
 -f,--format  (default html5)  Output file format
 -h,--help  Display this message
 -j,--jobname (default nil)  Set the jobname
 -l,--lua  Use lualatex for document compilation
 -m,--mode (default default) Switch which can be used in the makefile
 -n,--no-tex4ht Disable dvi file processing with the tex4ht command
 -s,--shell-escape Enables running external programs from LaTeX
 -u,--utf8  [obsolete] The document is generated in UTF8 encoding by default
 -v,--version  Display version number
 -x,--xetex Use xelatex for document compilation
]]

-- test if the current command line argument should be passed to tex4ht, t4ht or latex
local function is_escapedargument(arg)
 -- we need to ignore make4ht options which can be used without filename, ie --version and --help
 local ignored_options = {["-h"]=true, ["--help"]=true, ["-v"] = true, ["--version"]=true}
 if ignored_options[arg] then return false end
 -- in other cases, match if the argument starts with "-" character
 return arg:match("^%-.+")
end
local function get_args(parameters, optiontext)
       local parameters = parameters or {}
       parameters.progname = parameters.progname or "make4ht"
 parameters.issue_tracker = parameters.issue_tracker or "https://github.com/michal-h21/make4ht/issues"
       parameters.postparams = parameters.postparams or ""
       local optiontext = optiontext or m.optiontext
       parameters.postfile = parameters.postfile or ""
       optiontext = optiontext .. parameters.postparams ..[[  <filename> (string) Input file name

Positional optional arguments:
 ["tex4ht.sty op."]  Additional parameters for tex4ht.sty
 ["tex4ht op."]      Options for tex4ht command
 ["t4ht op"]         Options for t4ht command
 ["latex op"]        Additional options for LaTeX

Documentation:                  https://tug.org/applications/tex4ht/mn.html
Issue tracker for tex4ht bugs:  https://puszcza.gnu.org.ua/bugs/?group=tex4ht
Issue tracker for ${progname} bugs: ${issue_tracker}
 ]] .. parameters.postfile
 -- we can pass arguments for tex4ht and t4ht after filename, but it will confuse lapp, thinking that these
 -- options are for make4ht. this may result in execution error or wrong option parsing
 -- as fix, add a space before options at the end (we need to stop to add spaces as soon as we find
 -- nonempty string which doesn't start with - it will be filename or tex4ht.sty options
 if #arg > 1 then -- do this only if more than one argument is used
   for i=#arg,1,-1 do
     local current = arg[i]
     if is_escapedargument(arg[i]) then
       arg[i] = " ".. arg[i]
     -- empty parameter
     elseif current == "" then
     else
       break
     end
   end
 end
       --print("--------------\n" .. optiontext .."--------------\n")
       return lapp(optiontext % parameters)
end

--- get outptut file format and list of extensions from --format option string
local function get_format_extensions(format_string)
 local format, rest = format_string:match("^([a-zA-Z0-9]+)(.*)")
 local extensions = {}
 -- it is possible to pass only the extensions
 rest = rest or format_string
 rest:gsub("([%+%-])([^%+^%-]+)",function(typ, name)
   table.insert(extensions, {type = typ, name = name})
 end)
 return format, extensions
end


-- try to make safe filename
local function escape_filename(input)
 -- quoting don't work on Windows, so we will just
 if os.type == "windows" then
   return '"' .. input .. '"'
 else
   -- single quotes are safe in Unix
   return "'" .. input .. "'"
 end
end

-- detect if user specified -jobname in arguments to the TeX engine
-- or used the --jobname option for make4ht
local function handle_jobname(input, args)
 -- parameters to the TeX engine
 local latex_params = {}
 local latex_cli_params = args[4] or ""
 -- use the jobname as input name if it is specified
 local jobname = args.jobname ~="nil" and args.jobname or nil
 if jobname or not latex_cli_params:match("%-jobname") then
   -- prefer jobname over input
   input = jobname or input
   -- we must strip out directories from jobname when full path to document is given
   input = input:match("([^%/^%\\]+)$")
   -- input also cannot contain spaces, replace them with underscores
   input = input:gsub("%s", "_")
   table.insert(latex_params,"-jobname=".. escape_filename(input))
 else
   -- when user specifies -jobname, we must change name of the input file,
   -- in order to be able to process correct dvi file with tex4ht and t4ht
   local newinput
   -- first contains quotation character or first character of the name
   local first, rest = latex_cli_params:match("%-jobname%s*=?%s*(.)(.*)")
   if first=='"' then
     newinput=rest:match('([^"]+)')
   elseif first=="'" then
     newinput=rest:match("([^']+)")
   elseif type(first)== "string" then
     -- if the jobname is unquoted, it cannot contain space
     -- join the first character and rest
     rest = first.. rest
     newinput = rest:match("([^ ]+)")
   end
   if newinput then
     input = newinput
   end
 end
 --
       table.insert(latex_params, latex_cli_params)
 return latex_params, input
end

local function tex_file_not_exits(tex_file)
 -- try to find the input file, return false if we cannot find it
 return not (kpse.find_file(tex_file, "tex") or kpse.find_file(tex_file .. ".tex", "tex"))
end

-- use standard input instead of file if the filename is just `-`
-- return the filename and status if it is a tmp name
local function handle_input_file(filename)
 -- return the original file name if it isn't just dash
 if filename ~= "-" then return filename, false end
 -- generate the temporary name. the added extension is important
 local tmp_name = os.tmpname()
 local contents = io.read("*all")
 local f = io.open(tmp_name, "w")
 f:write(contents)
 f:close()
 return tmp_name, true
end

local function process_args(args)
       local function get_inserter(args,tb)
               return function(key, value)
                       --local v = args[key] and value or ""
                       local v = ""
                       if args[key] then v = value end
                       table.insert(tb,v)
               end
       end

 -- set error log level
 logging.set_level(args.loglevel)
 -- the default LaTeX --interaction parameter
 local interaction = "batchmode"
 if args.loglevel == "debug" then
   interaction = "errorstopmode"
 end

 if args.version ==true then
   print(string.format("%s version %s", m.progname, m.version_number))
   os.exit()
 end

       local outdir = ""
       local packages = ""

       if  args["output-dir"] ~= "nil" then
               outdir =  args["output-dir"]  or ""
               outdir = outdir:gsub('\\','/')
               outdir = outdir:gsub('/$','')
       end

       local builddir = ""

       if  args["build-dir"] ~= "nil" then
               builddir =  args["build-dir"]  or ""
               builddir = builddir:gsub('\\','/')
               builddir = builddir:gsub('/$','')
       end

 -- make4ht now requires UTF-8 output, because of DOM filters
 -- numeric entites are expanded to Unicode characters. These
 -- characters would be displayed incorrectly in 8 bit encodings.

 args.utf8 = true

       if args.backend == "lua4ht" then
               args.lua = true
               args.xetex = nil
               args.utf8 = true
               args["no-tex4ht"] = true
               packages = packages .."\\RequirePackage{lua4ht}"
       end


       local compiler = args.lua and "dvilualatex" or args.xetex and "xelatex --no-pdf" or "latex"
 local tex_file, is_tmp_file = handle_input_file(args.filename)
 -- test if the file exists
 if not is_tmp_file and tex_file_not_exits(tex_file) then
   log:warning("Cannot find input file: " .. tex_file)
 end
       local input = mkutils.remove_extension(tex_file)
 -- the output file name can be influneced using -jobname parameter passed to the TeX engine
       local latex_params, input = handle_jobname(input, args)
       local insert_latex = get_inserter(args,latex_params)
       insert_latex("shell-escape","-shell-escape")
       --table.insert(latex_params,args["shell-escape"] and "-shell-escape")


       local t4sty = args[1] or ""
       -- test if first option is custom config file
       local cfg_tmp = t4sty:match("([^,^ ]+)")
       if cfg_tmp and cfg_tmp ~= args.config then
               local fn = cfg_tmp..".cfg"
               local f = io.open(fn,"r")
               if f then
                       args.config = cfg_tmp
                       f:close()
               end
       end
       --[[if args[1] and args[1] ~= "" then
       t4sty = args[1]
       else
       --]]
       -- Different behaviour from htlatex
       local utf = args.utf8 and ",charset=utf-8" or ""
       t4sty = args.config .. "," .. t4sty .. utf
       --end

       local tex4ht = ""
 local dvi= args.xetex and "xdv" or "dvi"
       if args[2] and args[2] ~="" then
               tex4ht = args[2]
       else
               tex4ht = args.utf8 and " -cmozhtf -utf8" or ""
       end
 -- set the correct extension for tex4ht if xetex is used
 if args.xetex then tex4ht = tex4ht .. " -.xdv" end

       local t4ht = args[3] or ""

       local mode = args.mode or "default"

       local build_file = input.. ".mk4"

       if args["build-file"] and args["build-file"] ~= "nil" then
               build_file = args["build-file"]
       end

 local outformat, extensions
 if args["format"] and arg["format"] ~= "nil" then
   outformat, extensions = get_format_extensions(args["format"])
 end

       local parameters = {
               htlatex = compiler
               ,input=input
       ,tex_file=tex_file
               ,packages=packages
               ,latex_par=table.concat(latex_params," ")
               --,config=ebookutils.remove_extension(args.config)
               ,tex4ht_sty_par=t4sty
               ,tex4ht_par=tex4ht
               ,t4ht_par=t4ht
               ,mode = mode
   ,dvi = dvi
   ,build_file = build_file
   ,output_format = outformat
   ,extensions = extensions
   ,is_tmp_file = is_tmp_file
   ,interaction = interaction
               --,t4ht_dir_format=t4ht_dir_format
       }
       if outdir then parameters.outdir = outdir end
       if builddir then parameters.builddir = builddir end
       log:info("Output dir: "..outdir)
       log:info("Compiler: "..compiler)
       log:info("Latex options: ".. table.concat(latex_params," "))
       log:info("tex4ht.sty: "..t4sty)
       log:info("tex4ht: "..tex4ht)
       log:info("build_file: ".. build_file)
 if outformat~="nil" then
   log:info("Output format: ".. outformat)
   for _, ex in ipairs(extensions) do
     log:info("Extension: ".. ex.type .. ex.name)
   end
 end
       return parameters
end
m.get_args = get_args
m.get_format_extensions = get_format_extensions
m.process_args = process_args
return m