/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.sed;

import java.util.HashMap;
import java.util.Map;

import net.morilib.sed.cmd.SedCommands;
import net.morilib.sed.parser.SedAParser;
import net.morilib.sed.parser.SedBParser;
import net.morilib.sed.parser.SedCParser;
import net.morilib.sed.parser.SedCommentParser;
import net.morilib.sed.parser.SedCompositeParser;
import net.morilib.sed.parser.SedIParser;
import net.morilib.sed.parser.SedLabelParser;
import net.morilib.sed.parser.SedQParser;
import net.morilib.sed.parser.SedRParser;
import net.morilib.sed.parser.SedSParser;
import net.morilib.sed.parser.SedSimpleCommandParser;
import net.morilib.sed.parser.SedTParser;
import net.morilib.sed.parser.SedWParser;
import net.morilib.sed.parser.SedYParser;

/**
 * sedコマンドの束です。
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/03
 */
public class SedCommandBundle implements Cloneable {

	//
	private static final SedCommandBundle DEFAULT;

	//
	private Map<Integer, SedCommandParser> cmds;
	private Map<String, SedCommandParser> cmds2;

	static {
		Map<Integer, SedCommandParser> p;

		p = new HashMap<Integer, SedCommandParser>();
		p.put((int)'s', new SedSParser());
		p.put((int)'#', new SedCommentParser());
		p.put((int)'q', new SedQParser());
		p.put((int)'d', new SedSimpleCommandParser(SedCommands.D));
		p.put((int)'p', new SedSimpleCommandParser(SedCommands.P));
		p.put((int)'n', new SedSimpleCommandParser(SedCommands.N));
		p.put((int)'y', new SedYParser());
		p.put((int)'a', new SedAParser());
		p.put((int)'i', new SedIParser());
		p.put((int)'c', new SedCParser());
		p.put((int)'=', new SedSimpleCommandParser(SedCommands.EQ));
		p.put((int)'l', new SedSimpleCommandParser(SedCommands.L));
		p.put((int)'r', new SedRParser());
		p.put((int)'w', new SedWParser());
		p.put((int)'N', new SedSimpleCommandParser(SedCommands.NL));
		p.put((int)'P', new SedSimpleCommandParser(SedCommands.PL));
		p.put((int)'D', new SedSimpleCommandParser(SedCommands.DL));
		p.put((int)'h', new SedSimpleCommandParser(SedCommands.H));
		p.put((int)'H', new SedSimpleCommandParser(SedCommands.HL));
		p.put((int)'g', new SedSimpleCommandParser(SedCommands.G));
		p.put((int)'G', new SedSimpleCommandParser(SedCommands.GL));
		p.put((int)'x', new SedSimpleCommandParser(SedCommands.X));
		p.put((int)':', new SedLabelParser());
		p.put((int)'b', new SedBParser());
		p.put((int)'t', new SedTParser());
		p.put((int)'{', new SedCompositeParser());
		DEFAULT = new SedCommandBundle(p, false);
	}

	//
	private SedCommandBundle(Map<Integer, SedCommandParser> cmds,
			boolean dummy) {
		this.cmds = cmds;
	}

	/**
	 * 空のコマンド集を生成します。
	 */
	public SedCommandBundle() {
		this.cmds = new HashMap<Integer, SedCommandParser>();
	}

	/**
	 * コマンド集をコピーします。
	 * 
	 * @param cmds コマンド集
	 */
	public SedCommandBundle(Map<Integer, SedCommandParser> cmds) {
		this.cmds = new HashMap<Integer, SedCommandParser>(cmds);
	}

	/**
	 * デフォルトのコマンド集を生成します。
	 * 
	 * @return コマンド集
	 */
	public static SedCommandBundle newInstance() {
		return DEFAULT;
	}

	/**
	 * コマンドのパーサを得ます。
	 * 
	 * @param cmd コマンド文字
	 * @return パーサ
	 */
	public SedCommandParser get(int cmd) {
		return cmds.get(cmd);
	}

	/**
	 * 2文字以上のコマンドのパーサを得ます。
	 * 
	 * @param cmd コマンド文字列
	 * @return パーサ
	 */
	public SedCommandParser get(String cmd) {
		return cmds2.get(cmd);
	}

	/**
	 * コマンドのパーサを登録します。
	 * 
	 * @param c コマンド文字
	 * @param p パーサ
	 */
	public void put(int c, SedCommandParser p) {
		cmds.put(c, p);
	}

	/**
	 * コマンドのパーサを登録します。
	 * 
	 * @param s コマンド文字列
	 * @param p パーサ
	 */
	public void put(String s, SedCommandParser p) {
		if(s.length() == 1) {
			cmds.put((int)s.charAt(0), p);
		} else {
			cmds2.put(s, p);
		}
	}

	/**
	 * コマンドのパーサを削除します。
	 * 
	 * @param c コマンド文字
	 * @return 登録されていたパーサ
	 */
	public SedCommandParser remove(int c) {
		return cmds.remove(c);
	}

	/**
	 * コマンドのパーサを削除します。
	 * 
	 * @param s コマンド文字列
	 * @return 登録されていたパーサ
	 */
	public SedCommandParser remove(String s) {
		return cmds2.remove(s);
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	public SedCommandBundle clone() {
		return new SedCommandBundle(cmds);
	}

}
