-- texdoclib-cli.tlu: command line interfaces for texdoc
--
-- The TeX Live Team, GPLv3, see texdoclib.tlu for details

-- dependencies
local texdoc = {
    const = require 'texdoclib-const',
    util = require 'texdoclib-util',
    config = require 'texdoclib-config',
    search = require 'texdoclib-search',
    view = require 'texdoclib-view',
}

-- shortcuts
local M = {}
local C = texdoc.const
local err_print = texdoc.util.err_print

--------------------------   parsing options   --------------------------

-- modified Alternative GetOpt
-- cf. http://lua-users.org/wiki/AlternativeGetOpt
local function getopt(arg, options)
    local tmp = nil
    local tab = {}
    local saved_arg = {table.unpack(arg)}

    for k, v in ipairs(saved_arg) do
        if string.sub(v, 1, 2) == '--' then
            table.remove(arg, 1)
            local x = string.find(v, '=', 1, true)
            if x then
                table.insert(tab, {string.sub(v, 3, x - 1), string.sub(v, x+1)})
            else
                table.insert(tab, {string.sub(v, 3), true})
            end

        elseif string.sub(v, 1, 1) == '-' then
            table.remove(arg, 1)
            local y = 2
            local l = string.len(v)
            local jopt

            while (y <= l) do
                jopt = string.sub(v, y, y)

                if string.find(options, jopt, 1, true) then
                    if y < l then
                        tmp = string.sub(v, y + 1)
                        y = l
                    else
                        table.remove(arg, 1)
                        tmp = saved_arg[k + 1]
                    end

                    -- check the existence of an argument
                    if not tmp then
                        err_print('error',
                            'Option -%s requires an argument.', jopt)
                        os.exit(C.exit_error)
                    end

                    if string.match(tmp, '^%-') then
                        table.insert(tab, {jopt, false})
                    else
                        table.insert(tab, {jopt, tmp})
                    end
                else
                    table.insert(tab, {jopt, true})
                end
                y = y + 1
            end

        else
            if tmp then tmp = nil else break end
        end
    end

    return tab
end

local function parse_options()
    local curr_arg
    local cl_config = {}

    local function insert_cl_config(key, val, opt_name)
        table.insert(cl_config, {key, val, opt_name})
    end

    -- actual parsing
    opts = getopt(arg, 'cd')

    for _, tp in ipairs(opts) do
        local k, v = tp[1], tp[2]
        if #k == 1 then
            curr_arg = '-' .. k
        else
            curr_arg = '--' .. k
        end

        -- action
        if (curr_arg == '-h') or (curr_arg == '--help') then
            return true, 'help', cl_config
        elseif (curr_arg == '-V') or (curr_arg == '--version') then
            return true, 'version', cl_config
        elseif (curr_arg == '-f') or (curr_arg == '--files') then
            return true, 'files', cl_config
        elseif curr_arg == '--just-view' then
            return true, 'view', cl_config

        -- mode
        elseif (curr_arg == '-w') or (curr_arg == '--view') then
            insert_cl_config('mode', 'view', curr_arg)
        elseif (curr_arg == '-m') or (curr_arg == '--mixed') then
            insert_cl_config('mode', 'mixed', curr_arg)
        elseif (curr_arg == '-l') or (curr_arg == '--list') then
            insert_cl_config('mode', 'list', curr_arg)
        elseif (curr_arg == '-s') or (curr_arg == '--showall') then
            insert_cl_config('mode', 'showall', curr_arg)

        -- interaction
        elseif (curr_arg == '-I') or (curr_arg == '--nointeract') then
            insert_cl_config('interact_switch', 'false', curr_arg)
        elseif (curr_arg == '-i') or (curr_arg == '--interact') then
            insert_cl_config('interact_switch', 'true', curr_arg)

        -- output format
        elseif (curr_arg == '-M') or (curr_arg == '--machine') then
            insert_cl_config('machine_switch', 'true', curr_arg)

        -- config
        elseif curr_arg == '-c' then
            insert_cl_config(v, nil, curr_arg)

        -- debug
        elseif (curr_arg == '-d') or (curr_arg == '--debug') then
            if v == true then v = 'all' end
            insert_cl_config('debug_list', v, curr_arg)
        elseif curr_arg == '-D' then
            insert_cl_config('debug_list', 'all', curr_arg)

        -- verbosity
        elseif (curr_arg == '-q') or (curr_arg == '--quiet') then
            insert_cl_config('verbosity_level', C.min_verbosity, curr_arg)
        elseif (curr_arg == '-v') or (curr_arg == '--verbose') then
            insert_cl_config('verbosity_level', C.max_verbosity, curr_arg)

        -- having trouble
        else
            err_print('error', 'unknown option: ' .. curr_arg)
            err_print('error', C.error_msg)
            return false
        end
    end

    return true, action, cl_config
end

--------------------------   process execution   --------------------------

-- handling actions
local function do_action(action)
    if action == 'help' then
        texdoc.util.print_usage()
        os.exit(C.exit_ok)
    elseif action == 'version' then
        print(string.format(
            '%s %s (%s)', C.progname, C.version, C.release_date) ..
            '\n\n' .. C.copyright_msg)
        os.exit(C.exit_ok)
    elseif action == 'files' then
        print(texdoc.util.w32_path(C.fullname) .. ' ' .. C.version)
        texdoc.config.show_config_files(true)
        os.exit(C.exit_ok)
    elseif action == 'view' then
        if not arg[1] then
            err_print('error', 'Missing file operand to --just-view.')
            err_print('error', C.error_msg)
            os.exit(C.exit_usage)
        end
        texdoc.view.view_file(arg[1])
        os.exit(C.exit_ok)
    end
end

-- the main loop
local function do_texdoc()
    texdoc.search.init_databases()

    for _, docname in ipairs(arg) do
        -- do we have more then one argument?
        local multiarg = not not arg[2]
        -- get results
        local doclist = texdoc.search.get_doclist(docname)
        -- deliver results to the user
        texdoc.view.deliver_results(docname, doclist, multiarg)
    end
end

--------------------------   the main function   --------------------------

function M.exec()
    -- parsing command line options
    local ok, action, cl_config = parse_options()

    if not ok then
        os.exit(C.exit_usage)
    end

    -- setup config and alias
    texdoc.config.setup_config_and_alias(cl_config)

    -- special action
    do_action(action)

    -- do we actually have arguments?
    if not arg[1] then
        err_print('error', 'No action specified.')
        err_print('error', C.error_msg)
        os.exit(C.exit_usage)
    end

    -- the main feature
    do_texdoc()

    os.exit(C.exit_ok)
end

return M

-- vim: ft=lua:
