--[[

	Lua-based partial reimplementation of Python's
      optparse [2-3] command-line parsing module.

SYNOPSIS

  local OptionParser = require "pythonic.optparse" . OptionParser
  local opt = OptionParser{usage="%prog [options] [gzip-file...]",
                           version="foo 1.23", add_help_option=false}
  opt.add_option{"-h", "--help", action="store_true", dest="help",
                 help="give this help"}
  opt.add_option{
    "-f", "--force", dest="force", action="store_true",
    help="force overwrite of output file"}

  local options, args = opt.parse_args()

  if options.help then opt.print_help(); os.exit(1) end
  if options.force then print 'f' end
  for _, name in ipairs(args) do print(name) end
      
DESCRIPTION

  This library provides a command-line parsing[1] similar to Python optparse [2-3].

  Note: Python also supports getopt [4].

STATUS
  
  This module is fairly basic but could be expanded.
  
API

  See source code and also compare to Python's docs [2,3] for details because
  the following documentation is incomplete.
  
  opt = OptionParser {usage=usage, version=version, add_help_option=add_help_option}
  
    Create command line parser.
  
  opt.add_options{shortflag, longflag, action=action, metavar=metavar, dest=dest, help=help}
  
    Add command line option specification.  This may be called multiple times.
 
  opt.parse_args() --> options, args
  
    Perform argument parsing.
 
DEPENDENCIES

  None (other than Lua 5.1 or 5.2)
  
REFERENCES

  [1] http://lua-users.org/wiki/CommandLineParsing
  [2] http://docs.python.org/lib/optparse-defining-options.html
  [3] http://blog.doughellmann.com/2007/08/pymotw-optparse.html
  [4] http://docs.python.org/lib/module-getopt.html

LICENSE

  (c) 2008-2011 David Manura.  Licensed under the same terms as Lua (MIT).

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  (end license)

 --]]
 
return function(t)
	local usage = t.usage
	--local version = t.version
	
	local o = {}
	local option_descriptions = {}
	local option_of = {}

	function o.add_option(optdesc)
		option_descriptions[#option_descriptions+1] = optdesc
		for _,v in ipairs(optdesc) do
			option_of[v] = optdesc
		end
	end
	
	local function split(inputstr, seperator)
		if seperator == nil then
			seperator = "%s"
		end
		local out={}
		local i=1
		for substring in string.gmatch(inputstr, "([^"..seperator.."]+)") do
			out[i] = substring
			i = i + 1
		end
		return out
	end
	
	function o.parse_args(arg)
		-- expand options (e.g. "--input=file" -> "--input", "file")
		local arg = split(arg)
		for i=#arg,1,-1 do local v = arg[i]
			local flag, val = v:match('^(%-%-%w+)=(.*)')
			if flag then
			arg[i] = flag
			table.insert(arg, i+1, val)
			end
		end
		
		local options = {}
		local args = {}
		local i = 1
		while i <= #arg do local v = arg[i]
			local optdesc = option_of[v]
			if optdesc then
			local action = optdesc.action
			local val
			if action == 'store' or action == nil then
				i = i + 1
				val = arg[i]
				if not val then return false, 'option requires an argument ' .. v end
			elseif action == 'store_true' then
				val = true
			elseif action == 'store_false' then
				val = false
			end
			options[optdesc.dest] = val
			else
			if v:match('^%-') then return false, 'invalid option ' .. v end
			args[#args+1] = v
			end
			i = i + 1
		end
		if options.help then
			return false, o.print_help()
		end
		return true, options, args
	end
	
	local function flags_str(optdesc)
		local sflags = {}
		local action = optdesc.action
		for _,flag in ipairs(optdesc) do
			local sflagend
			if action == nil or action == 'store' then
				local metavar = optdesc.metavar or optdesc.dest:upper()
				sflagend = #flag == 2 and ' ' .. metavar or  '=' .. metavar
			else
				sflagend = ''
			end
			sflags[#sflags+1] = flag .. sflagend
		end
		return table.concat(sflags, ', ')
	end
	
	function o.print_help()
		local helpout = "Usage: " .. usage .. "\n\n" .. "Options:\n"
		local maxwidth = 0
		for _,optdesc in ipairs(option_descriptions) do
			maxwidth = math.max(maxwidth, #flags_str(optdesc))
		end
		for _,optdesc in ipairs(option_descriptions) do
			helpout = helpout .. "  " .. ('%-'..maxwidth..'s  '):format(flags_str(optdesc)) .. optdesc.help .. "\n"
		end
		return helpout
	end
	
--	if t.add_help_option == nil or t.add_help_option == true then
--		o.add_option{"--help", action="store_true", dest="help", help="show this help message and exit"}
--	end
	return o
end