-- --- T2-COPYRIGHT-NOTE-BEGIN ---
-- This copyright note is auto-generated by ./scripts/Create-CopyPatch.
-- 
-- T2 SDE: misc/lua/sde/getopt.lua
-- Copyright (C) 2005 - 2006 The T2 SDE Project
-- Copyright (C) 2005 - 2006 Juergen "George" Sawinski
-- 
-- More information can be found in the files COPYING and README.
-- 
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License. A copy of the
-- GNU General Public License can be found in the file COPYING.
-- --- T2-COPYRIGHT-NOTE-END ---

-- TODO:
--  - add boolean option argument types
--  - maybe other types needed ?

-- DESCRIPTION:
--   opts,args,err = getopt(arg-list, option-definition)
--     Parses the "arg-list" according to "option-definition" and
--     returns the parsed options "opts", additional arguments "args" and
--     possibly an error.
--    
--     Option definition format:
--        key         Option key (e.g. key = "help")
--        option      String or list of options (e.g. option = {"-h", "--help"})
--        default     Default value (e.g. default = false)
--        argument    This option has no argument (ARG.none), a required
--                    argument (ARG.required) or an optional argument (ARG.optional)
--        flag        The option is flagged: 
--                         number (OPT.number)
--                         incremental (OPT.incremental)
--  Example: see below

ARG = { 
	none = 0, 
	required = 1,
	optional = 2 
}

OPT = {
	none = 0,
	string = 0,
	number = 1,
	--boolean = 2,	
	incremental = 10,
}

function getopt(args,def)
	local opt = {}
	local arg = {}
	local nargs = table.getn(args)

	-- first pass: defaults
	for _,d in pairs(def) do
		if d.default ~= nil then 
			opt[d.key] = d.default
		end
	end

	-- Second pass: parse arguments
	local i=1 
	repeat
		for _,d in pairs(def) do
			local found = false
			
			-- FIXME is there some shorter version for this:
			if type(d.option) == "string" then
				if d.option == args[i] then found=true end
			else
				for k=1,table.getn(d.option) do
					if d.option[k] == args[i] then
						found = true
					end
				end
			end
			
			-- process option and arguments
			if found then
				local val = true
				local nextisopt = false
				local havearg = false
				
				-- check if next is an argument (not option)
				if args[i+1] and string.sub(args[i+1],1,1) == "-" then
					nextisopt = true
				end
				
				-- option argument ?
				if nextisopt and d.argument == ARG.required then
					return nil, nil, "Missing option argument for `" .. args[i] .. "'"
				end
				
				if not nextisopt and
					(d.argument == ARG.required 
						or d.argument == ARG.optional) then
					args[i] = nil 
					i = i+1
					
					val = args[i]
					
					havearg = true
				end

				-- flags ?
				if d.flag then
					if d.flag == OPT.number then
						val = tonumber(val)
					elseif d.flag == OPT.incremental then
						val = opt[d.key] + 1
					end
				end

				-- finally assign value
				opt[d.key] = val

				-- remove key from list (see third pass)
				args[i] = nil
			end
		end
	i=i+1
	until i>nargs

	-- Third pass: check option, sort arguments
	for i=1,nargs do
		if args[i] then
			if string.sub(args[i],1,1) == "-" then
				return nil, nil, "Unrecognized option `" .. args[i] .. "'"
			else
				table.insert(arg, args[i])
			end
		end
	end

	-- done
	return opt,arg
end


-- EXAMPLE
if false then
	opt,arg,err = getopt(arg, {
		{
			key      = "help",
			option   = { "-h", "-help", "--help" },
		},
		{
			key      = "verbose",
			option   = { "-v", "-verbose", "--verbose" },
			default  = 0,
			flag     = OPT.incremental
		},
	})

	if not opt then
		print "ERR:"
		print(err)
		os.exit(-1)
	end

	print "OPTS:"
	for k,v in pairs(opt) do
		print("",k,v)
	end

	print "ARGS:"
	for k,v in pairs(arg) do
		print("",k,v)
	end
end
