package junkutil.common;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 実行時引数をパースする
 * @author Hiroyuki Shiota
 */
public class OptGets {

	private String format;
	private Map opts = new HashMap();
	private List argList = new ArrayList();
	
	/**
	 * コンストラクタ
	 */
	private OptGets() {
	}
	
	/**
	 * 引数のフォーマットを指定するコンストラクタ。
	 * オプションに引数が欲しいときにはオプション文字の次に":"を書くこと。
	 * @param argFormat ex. "abc:"
	 */
	public OptGets(String argFormat) {
		format = argFormat;
	}

	/**
	 * 引数をパースしてオプションを得る。
	 * @param args
	 * @return オプション入りのMap
	 * @throws IllegalArgumentException
	 */
	public Map parse(String args[]) throws IllegalArgumentException {
		boolean isAllArguments = false;
		char lastC = ' ';
		//FALSEで初期化
		for (int j = 0; j < format.length(); j++) {
			char c = format.charAt(j);
			if (c != ':') {
				opts.put(Character.toString(c), Boolean.FALSE);
			} else {
				opts.put(Character.toString(lastC), null);
			}
			lastC = c;
		}
		//パース開始
		int i = 0; 
		for (; i < args.length; i++) {
			String arg = args[i];
			if (arg.equals("--")) {
				isAllArguments = true;
				i++;
				break;
			} //オプションの終わり
			if (arg.length() != 2 || !arg.startsWith("-")) break;
			char a = arg.charAt(1);
			for (int j = 0; j < format.length(); j++) {
				char c = format.charAt(j);
				boolean isNeedValue; //引数を取るオプションか？
				if (j == format.length()-1) {
					//formatの最後の文字ならば、次の文字は無い
					isNeedValue = false;
				} else {
					//次の文字が":"ならば、引数が必要
					isNeedValue = (':' == format.charAt(j+1));
				}
				if (a==c) {
					if (isNeedValue) {
						//必要なのに引数が見当たらないときはエラー
						if (i == args.length-1) throw new IllegalArgumentException();
						opts.put(Character.toString(c), args[i+1]);
						i++;
					} else {
						opts.put(Character.toString(c), Boolean.TRUE);
					}
				}
			}
		}
		for (; i < args.length; i++) {
			if (!isAllArguments && args[i].startsWith("-")) throw new IllegalArgumentException();
			argList.add(args[i]);
		}
		return opts;
	}

	/**
	 * オプションを取得する。
	 * 先にparseメソッドを呼んでおくこと。
	 * @return オプション入りのMap
	 */
	public Map getOpts() {
		return opts;
	}
	
	/**
	 * 真の引数を取得する
	 * @return オプション以外の引数のList
	 */
	public List getArgList() {
		return argList;
	}

	/**
	 * 真の引数を取得する
	 * @return オプション以外の引数のString配列
	 */
	public String [] getArgs() {
		String [] args = new String[argList.size()];
		argList.toArray(args);
		return args;
	}

}
