/* vim: ts=4 sw=4 sts=4 fenc=utf-8 ff=unix :
 * =============================================================================
 *  options
 *
 *  Copyright (C) 2002 - 2008 by kei-n
 *  URL : http://sys0tem.homelinux.com/
 *
 * =============================================================================
 */
module sal.util.options;



/**
 * 起動引数を解析するクラス.
 */
public
class Options
{

	/**
	 * Options を構築します.
	 * ここで指定した Delegate は、
	 * 未知のオプションが指定された際に実行されます.
	 *
	 * Params:
	 *  dg = 未知のオプションが指定された際に実行される関数
	 */
	public
	this(void delegate(in string opt) dg)
	{
		this.optArgFuncs["unknown"] = dg;
	}


	/**
	 * 引数を解析し、登録されている適切な関数を実行します.
	 *
	 * Params:
	 *  args = 起動引数
	 * Return:
	 *  オプション以外の引数
	 */
	public
	string[] analysis(char[][] args)
	{
		string[] others;
		bool ck;
		for (int i = 1; i < args.length; i++)
		{
			if (args[i][0] != '-')
			{	// - で始まらない場合はオプションではない
				others ~= cast(string) args[i];
			}
			else
			{	// オプション解析
				ck = checkOptions(cast(string) args[i]);
				if (!ck && (i < args.length - 1))
				{
					ck = checkArgOptions(
							cast(string) args[i],
							cast(string) args[i + 1]);
					if (ck) { i++; }
				}
				if (!ck)
				{	// 未知のオプション
					this.optArgFuncs["unknown"](cast(string) args[i]);
				}
			}
		}
		return others;
	}


	/**
	 * 起動引数に指定された際に実行される関数を登録します.
	 *
	 * Params:
	 *  name = 起動引数 (例 --help)
	 *  dg   = 関数
	 */
	public
	void addFunc(in string name, void delegate() dg)
	{
		
		optFuncs[name] = dg;
	}


	/**
	 * 起動引数に指定された際に実行される関数を登録します.
	 *
	 * Params:
	 *  name = 起動引数 (例 -f)
	 *  dg   = 関数
	 */
	public
	void addFunc(in string name, void delegate(in string opt) dg)
	{
		optArgFuncs[name] = dg;
	}


	/**
	 * オプションをチェックします.
	 *
	 * Params:
	 *  arg = オプション文字列
	 * Return:
	 *  true/false (オプションが存在した/存在しない)
	 */
	private
	bool checkOptions(in string arg)
	{
		void delegate() *dg;
		dg = (arg in optFuncs);
		if (dg is null)
		{
			return false;
		}
		(*dg)();
		return true;
	}


	/**
	 * オプションをチェックします.
	 *
	 * Params:
	 *  arg1 = オプション文字列
	 *  arg2 = オプション引数文字列
	 * Return:
	 *  true/false (オプションが存在した/存在しない)
	 */
	private
	bool checkArgOptions(in string arg1, in string arg2)
	{
		void delegate(in string opt) *dg;
		dg = (arg1 in optArgFuncs);
		if (dg is null)
		{
			return false;
		}
		(*dg)(arg2);
		return true;
	}


	private
	{
		void delegate()[string]              optFuncs;
		void delegate(in string opt)[string] optArgFuncs;
	}
}

