package org.postgresforest.tool.util;

//import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;

/**
 * コマンド構文解析クラス.
 * コマンドの構文解析の実行し、コマンドタイプを判別。
 * 各コマンドタイプにあわせて、テーブルを取り出す。
 */
public class CommandParser {

	//コマンド・キーワードID
	public static final int NONE = -1; //解析不可
	public static final int CREATE_INSTANCE = 10;
	public static final int DROP_INSTANCE = 11;
	public static final int SHOW_INSTANCE = 12;
	public static final int SET_INSTANCE_UP = 13;
	public static final int SET_INSTANCE_DOWN = 14;
	public static final int CREATE_GSC = 20;
	public static final int DROP_GSC = 21;
	public static final int SHOW_GSC = 22;
	public static final int DUMP_GSC = 23;
	public static final int RESTORE_GSC = 24;
	public static final int CHECK_GSC = 25;
	public static final int CREATE_DB = 30;
	public static final int DROP_DB = 31;
	public static final int RESTORE_DB = 32;
	public static final int SHOW_DB = 33;
	public static final int CREATE_DBINSTANCE = 34;
	public static final int DROP_DBINSTANCE = 35;
	public static final int CREATE_USER = 41;
	public static final int DROP_USER = 42;
	public static final int SHOW_USER = 43;
	public static final int CREATE_CONFIG = 50;
	public static final int DROP_CONFIG = 51;
	public static final int SHOW_CONFIG = 52;
	public static final int SET_CONFIG = 53;
	public static final int REPLICATE_CONFIG = 54;
	public static final int CREATE_HASH = 60;
	public static final int DROP_HASH = 61;
	public static final int SHOW_HASH = 62;
	public static final int SHOW_BROKENLOG = 70;
	public static final int CLEAR_BROKENLOG = 71;

	public static final int OPEN_DB = 100;
	public static final int CLOSE_DB = 101;
	public static final int SHOW_TABLE = 110;
	public static final int PART_TABLE = 111;
	public static final int PART_TABLE2 = 112;
	public static final int UNPART_TABLE = 113;
	public static final int SHOW_TABLE_COLUMN = 114;
	public static final int REPART_TABLE = 115;
	public static final int SET_PRIORITY = 120;
	public static final int SHOW_PRIORITY = 121;
	public static final int SHOW_HELP = 99;
	public static final int SHOW_HELPCOMMAND = 999;
	public static final int COMMENT_SQL = 500;
	public static final int COMMENT_SHELL = 501;

	
	protected static final int CHECK = 1;
	protected static final int CLOSE = 2;
	protected static final int REPLICATE = 3;
	protected static final int CREATE = 4;
	protected static final int DROP = 5;
	protected static final int DUMP = 6;
	protected static final int CLEAR = 7;
	protected static final int OPEN = 8;
	protected static final int PART = 9;
	protected static final int RESTORE = 10;
	protected static final int SET = 11;
	protected static final int SHOW = 12;
	protected static final int UNPART = 13;
	protected static final int HELP = 14;
	protected static final int ADD = 15;
	protected static final int DELETE = 16;
	protected static final int REPART = 17;

	// DML
/*
	protected static final int SELECT = 31;
	protected static final int UPDATE = 32;
	protected static final int DELETE = 33;
	protected static final int INSERT = 34;
	protected static final int COPY = 35;
*/	
	protected static final int BROKENLOG = 51;
	protected static final int CONFIG = 53;
	protected static final int DB = 54;
	protected static final int GSC = 55;
	protected static final int HASH = 56;
	protected static final int INSTANCE = 57;
	protected static final int PRIORITY = 58;
	protected static final int TABLE = 59;	
	protected static final int TABLE2 = 60;	
	protected static final int USER = 61;
	protected static final int DBINSTANCE = 62;	

	protected static final int UP = 100;
	protected static final int DOWN = 101;
	protected static final int COMMAND = 110;
	protected static final int WITH = 120;
	

	protected static final int PASS = 201;
	protected static final int DBAUTH = 202;
	protected static final int USRAUTH = 203;
	protected static final int CONFIGNAME = 210;
	protected static final int DESCRIPT = 211;
	protected static final int CACHEREFRESH = 212;
	protected static final int RETRYCOUNT = 213;
	protected static final int DETECTTIMEOUT = 214;
	protected static final int DISTRIBUTE = 215;
	protected static final int PARTMODE = 216;
	protected static final int SYNCMODE = 217;
	protected static final int HASHNAME = 230;
	protected static final int REST = 231;
	protected static final int SERVID = 232;
	protected static final int PARTNO = 233;
	
	
	protected int m_type = NONE;
	protected ArrayList m_table = null;
	protected ArrayList m_db = null;
	protected ArrayList m_dbOption = null;
	protected ArrayList m_dumpFile = null;
	protected ArrayList m_host = null;
	protected ArrayList m_port = null;
	protected ArrayList m_server = null;
	protected ArrayList m_serverStatus = null;
	protected ArrayList m_gscName = null;
	protected ArrayList m_user = null;
	protected ArrayList m_pass = null;
	protected ArrayList m_configName = null;
	protected ArrayList m_paramName = null;
	protected ArrayList m_paramValue = null;
	protected ArrayList m_hashName = null;
	protected ArrayList m_hashDescript = null;
	protected ArrayList m_hashFile = null;
	protected ArrayList m_keyCol = null;
	protected ArrayList m_partCnt = null;
	protected ArrayList m_restore = null;
	protected ArrayList m_partNo = null;
	protected ArrayList m_part2No = null;
	protected ArrayList m_part2NoList = null;

	protected String m_replaceWord = null;

	private boolean isHelpCommand = false;
	
	private static final char LEFT_PARENTHESIS = '(';
	private static final char RIGHT_PARENTHESIS = ')';
	private static final char COMMA = ',';
	private static final char EQUAL = '=';
	
	
	/** コマンド・キーワードIDと文字列マッピングテーブル */
	protected static final CommandMap commandSet = new CommandMap();

	// コマンド判別用のマップ初期化

	static {
		commandSet.put("check", CHECK); //$NON-NLS-1$
		commandSet.put("clear", CLEAR); //$NON-NLS-1$
		commandSet.put("close", CLOSE); //$NON-NLS-1$
		commandSet.put("replicate", REPLICATE); //$NON-NLS-1$
		commandSet.put("create", CREATE); //$NON-NLS-1$
		commandSet.put("drop", DROP); //$NON-NLS-1$
		commandSet.put("dump", DUMP); //$NON-NLS-1$
		commandSet.put("help", HELP); //$NON-NLS-1$
		commandSet.put("open", OPEN); //$NON-NLS-1$
		commandSet.put("part", PART); //$NON-NLS-1$
		commandSet.put("repart", REPART); //$NON-NLS-1$
		commandSet.put("restore", RESTORE); //$NON-NLS-1$
		commandSet.put("set", SET); //$NON-NLS-1$
		commandSet.put("show", SHOW); //$NON-NLS-1$
		commandSet.put("unpart", UNPART); //$NON-NLS-1$
		commandSet.put("add", ADD); //$NON-NLS-1$
		commandSet.put("delete", DELETE); //$NON-NLS-1$
/*
		commandSet.put("select", SELECT);
		commandSet.put("update", UPDATE);
		commandSet.put("insert", INSERT);
		commandSet.put("delete", DELETE);
		commandSet.put("copy", COPY);
*/		
		commandSet.put("brokenlog", BROKENLOG); //$NON-NLS-1$
		commandSet.put("config", CONFIG); //$NON-NLS-1$
		commandSet.put("db", DB); //$NON-NLS-1$
		commandSet.put("gsc", GSC); //$NON-NLS-1$
		commandSet.put("hash", HASH); //$NON-NLS-1$
		commandSet.put("instance", INSTANCE); //$NON-NLS-1$
		commandSet.put("priority", PRIORITY); //$NON-NLS-1$
		commandSet.put("table", TABLE);		 //$NON-NLS-1$
		commandSet.put("table2", TABLE2);		 //$NON-NLS-1$
		commandSet.put("user", USER);		 //$NON-NLS-1$
		commandSet.put("dbinstance", DBINSTANCE);		 //$NON-NLS-1$

		commandSet.put("up", UP);		 //$NON-NLS-1$
		commandSet.put("down", DOWN);		 //$NON-NLS-1$
		commandSet.put("command", COMMAND); //$NON-NLS-1$
		
		commandSet.put("with", WITH); //$NON-NLS-1$
		commandSet.put("pass", PASS); //$NON-NLS-1$
		commandSet.put("dbauth", DBAUTH); //$NON-NLS-1$
		commandSet.put("usrauth", USRAUTH); //$NON-NLS-1$
		commandSet.put("cfgname", CONFIGNAME); //$NON-NLS-1$
		commandSet.put("descript", DESCRIPT); //$NON-NLS-1$
		commandSet.put("refresh", CACHEREFRESH); //$NON-NLS-1$
		commandSet.put("retry", RETRYCOUNT); //$NON-NLS-1$
		commandSet.put("timeout", DETECTTIMEOUT); //$NON-NLS-1$
		commandSet.put("dist", DISTRIBUTE); //$NON-NLS-1$
		commandSet.put("pmode", PARTMODE); //$NON-NLS-1$
		commandSet.put("smode", SYNCMODE); //$NON-NLS-1$
		commandSet.put("hashname", HASHNAME); //$NON-NLS-1$
		commandSet.put("rest", REST); //$NON-NLS-1$
		commandSet.put("servid", SERVID); //$NON-NLS-1$
		commandSet.put("partno", PARTNO); //$NON-NLS-1$
		
		commandSet.put("--", COMMENT_SQL); //$NON-NLS-1$
		commandSet.put("#", COMMENT_SHELL); //$NON-NLS-1$
		
	}

	/**
	 * コンストラクタ
	 * コマンドラインツールのコマンドをパースする。
	 * @param command - コマンド文
	 * @throws SQLException
	 */
	public CommandParser(String command) throws Exception {

		//StreamTokenizerの初期化
		StreamTokenizer tokenizer = initTokenizer(command);

//		m_type = new ArrayList();
		m_table = new ArrayList();
		m_db = new ArrayList();
		m_dbOption = new ArrayList();
		m_dumpFile = new ArrayList();
		m_host = new ArrayList();
		m_port = new ArrayList();
		m_server = new ArrayList();
		m_serverStatus = new ArrayList();
		m_gscName = new ArrayList();
		m_user = new ArrayList();
		m_pass = new ArrayList();
		m_configName = new ArrayList();
		m_paramName = new ArrayList();
		m_paramValue = new ArrayList();
		m_hashName = new ArrayList();
		m_hashDescript = new ArrayList();
		m_hashFile = new ArrayList();
		m_keyCol = new ArrayList();
		m_partCnt = new ArrayList();
		m_restore = new ArrayList();
		m_partNo = new ArrayList();
		m_part2NoList = new ArrayList();
//		m_replaceWord = null;
		
		int typeCommand = NONE;

		//コマンドタイプ取得
		int token = StreamTokenizer.TT_EOF;
		try {
		while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
			if (token == StreamTokenizer.TT_WORD) {

				int type = commandSet.getInt(tokenizer.sval);

				switch (type) {

					// コマンドタイプのパース
				 	case ADD :
				 	case DELETE :
				 	case CHECK :
				 	case CLEAR :
				 	case REPLICATE :
					case CREATE :
					case DROP :
					case DUMP :
					case OPEN :
					case CLOSE :
					case PART :
					case REPART :
					case RESTORE :
					case SET :
					case SHOW :
					case UNPART :
						
						typeCommand = type;
						break;
						
					case COMMENT_SQL :						
					case COMMENT_SHELL :
						
						m_type =  type;
						return;
				 		
				 	case HELP :
				 		typeCommand = type;
						isHelpCommand = true;
						break;
				 		
					case COMMAND :
						//コマンドタイプ判別
						if (typeCommand == HELP){
							m_type = SHOW_HELP;
						}
						break;
						
					case BROKENLOG :

						//コマンドタイプ判別
						switch (typeCommand) {
						case SHOW :
							m_type = SHOW_BROKENLOG;
							if (isHelpCommand) {
								break;
							}
							//To do
							return;

						case CLEAR :
							m_type = CLEAR_BROKENLOG;
							if (isHelpCommand) {
								break;
							}
							//To do
							return;
						}
						break;

					case CONFIG :

						//コマンドタイプ判別
						switch (typeCommand) {
						case REPLICATE :
							m_type = REPLICATE_CONFIG;
							if (isHelpCommand) {
								break;
							}
							//コピー元Config名取得
							tokenizer.nextToken();
							m_configName.add(new String(tokenizer.sval));
							//コピー先Config名取得
							tokenizer.nextToken();
							m_configName.add(new String(tokenizer.sval));
							return;

						case CREATE :
							m_type = CREATE_CONFIG;
							if (isHelpCommand) {
								break;
							}
							//Config名取得
							tokenizer.nextToken();
							m_configName.add(new String(tokenizer.sval));
							return;

						case DROP :
							m_type = DROP_CONFIG;
							if (isHelpCommand) {
								break;
							}
							//Config名取得
							tokenizer.nextToken();
							m_configName.add(new String(tokenizer.sval));
							return;

						case SET :
							m_type = SET_CONFIG;
							if (isHelpCommand) {
								break;
							}
							//Config名取得
							tokenizer.nextToken();
							m_configName.add(new String(tokenizer.sval));
							parseEqualParams(tokenizer, m_type);
							return;
							
						case SHOW :
							m_type = SHOW_CONFIG;
							return;
						}
						break;

					case DB :
						//@@@ To do 複数のサーバを指定してrestore,addする場合
						//コマンドタイプ判別
						switch (typeCommand) {
						case CREATE :
							m_type = CREATE_DB;
							if (isHelpCommand) {
								break;
							}
							//DB名取得
							tokenizer.nextToken();
							m_db.add(new String(tokenizer.sval));
							//サーバID取得
							m_server = parseParenthesis(tokenizer);
							//オプション取得
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);	
							if (type == WITH){
								while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
									m_dbOption.add(new String(tokenizer.sval));	
								}
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}
							return;

						case RESTORE :
							m_type = RESTORE_DB;
							if (isHelpCommand) {
								break;
							}
							//DB名取得
							tokenizer.nextToken();
							m_db.add(new String(tokenizer.sval));
							//サーバID・ダンプファイル名取得
							parseDumpFileList(tokenizer, m_type);
							//オプション取得
							type = commandSet.getInt(tokenizer.sval);	
							if (type == WITH){
								while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
									m_dbOption.add(new String(tokenizer.sval));
								}
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}
							return;

						case DROP :
							m_type = DROP_DB;
							if (isHelpCommand) {
								break;
							}
							//DB名取得
							tokenizer.nextToken();
							m_db.add(new String(tokenizer.sval));
							return;

						case SHOW :
							m_type = SHOW_DB;
							if (isHelpCommand) {
								break;
							}
							return;

						case ADD :
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);
							if (type == INSTANCE) {
								m_type = CREATE_DBINSTANCE;								
								if (isHelpCommand) {
									break;
								}
							} 
							//DB名取得
							tokenizer.nextToken();
							m_db.add(new String(tokenizer.sval));
							//サーバID取得
							tokenizer.nextToken();
							m_server.add(new String(tokenizer.sval));
							//ダンプファイル名取得
							tokenizer.nextToken();
							m_dumpFile.add(new String(tokenizer.sval));
							//オプション取得
							while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
								m_dbOption.add(new String(tokenizer.sval));
							}
							return;

						case DELETE :
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);
							if (type == INSTANCE) {
								m_type = DROP_DBINSTANCE;								
								if (isHelpCommand) {
									break;
								}
							} 
							//DB名取得
							tokenizer.nextToken();
							m_db.add(new String(tokenizer.sval));
							//サーバID取得
							tokenizer.nextToken();
							m_server.add(new String(tokenizer.sval));
							return;

						case OPEN :
							m_type = OPEN_DB;
							if (isHelpCommand) {
								break;
							}
							//DB名取得
							if ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
								m_db.add(new String(tokenizer.sval));
								return;
							}
							return;
							
					 	case CLOSE :
							m_type = CLOSE_DB;
							if (isHelpCommand) {
								break;
							}return;
					 		
						}
						break;

					case DBINSTANCE :
						//コマンドタイプ判別
						switch (typeCommand) {
						case CREATE :
							m_type = CREATE_DBINSTANCE;								
							if (isHelpCommand) {
								break;
							}
							//DB名取得
							tokenizer.nextToken();
							m_db.add(new String(tokenizer.sval));
							//サーバID・ダンプファイル名取得
							parseDumpFileList(tokenizer, m_type);
							//オプション取得
							type = commandSet.getInt(tokenizer.sval);	
							if (type == WITH){
								while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
									m_dbOption.add(new String(tokenizer.sval));
								}
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}
							return;
							
						case DROP :
							m_type = DROP_DBINSTANCE;									
							if (isHelpCommand) {
								break;
							}
							//DB名取得
							tokenizer.nextToken();
							m_db.add(new String(tokenizer.sval));
							//サーバID取得
							tokenizer.nextToken();
							m_server.add(new String(tokenizer.sval));
							return;
						}
						break;

						
					case GSC :
						//コマンドタイプ判別
						switch (typeCommand) {
						case CREATE :
							m_type = CREATE_GSC;
							if (isHelpCommand) {
								break;
							}
							//サーバID取得
							tokenizer.nextToken();
							m_server.add(new String(tokenizer.sval));
							//GSC名取得
							tokenizer.nextToken();
							m_gscName.add(new String(tokenizer.sval));
							return;
							
						case DROP :
							m_type = DROP_GSC;
							if (isHelpCommand) {
								break;
							}
							//サーバID取得
							tokenizer.nextToken();
							m_server.add(new String(tokenizer.sval));
							//GSC名取得
							tokenizer.nextToken();
							m_gscName.add(new String(tokenizer.sval));
							return;

						case SHOW :
							m_type = SHOW_GSC;
							if (isHelpCommand) {
								break;
							}return;

						case DUMP :
							m_type = DUMP_GSC;
							if (isHelpCommand) {
								break;
							}
							//GSC名取得
							tokenizer.nextToken();
							m_gscName.add(new String(tokenizer.sval));
							return;

						case RESTORE :
							m_type = RESTORE_GSC;
							if (isHelpCommand) {
								break;
							}
							//GSC名取得
							tokenizer.nextToken();
							m_gscName.add(new String(tokenizer.sval));
							return;

						case CHECK :
							m_type = CHECK_GSC;
							if (isHelpCommand) {
								break;
							}
							//GSC名取得
							tokenizer.nextToken();
							m_gscName.add(new String(tokenizer.sval));
							return;
							
						}
						break;

					case HASH :

						//コマンドタイプ判別
						switch (typeCommand) {
						case CREATE :
							m_type = CREATE_HASH;
							if (isHelpCommand) {
								break;
							}
							//HashClass名取得
							tokenizer.nextToken();
							m_hashName.add(new String(tokenizer.sval));
							//HashFile名取得
							tokenizer.nextToken();
							m_hashFile.add(new String(tokenizer.sval));
							//Hashの説明取得
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);	
							if (type == WITH){
								while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
									m_hashDescript.add(new String(tokenizer.sval));
								}
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}
							return;

						case DROP :
							m_type = DROP_HASH;
							if (isHelpCommand) {
								break;
							}
							//HashClass名取得
							tokenizer.nextToken();
							m_hashName.add(new String(tokenizer.sval));
							return;

						case SHOW :
							m_type = SHOW_HASH;
							if (isHelpCommand) {
								break;
							}return;
							
						}
						break;

					case INSTANCE :

						//コマンドタイプ判別
						switch (typeCommand) {
						case CREATE :
							m_type = CREATE_INSTANCE;
							if (isHelpCommand) {
								break;
							}
							//ホスト名取得
							tokenizer.nextToken();
							m_host.add(new String(tokenizer.sval));
							//Port番号取得
							tokenizer.nextToken();
							m_port.add(new String(tokenizer.sval));
							return;

						case DROP :
							m_type = DROP_INSTANCE;
							if (isHelpCommand) {
								break;
							}
							//サーバID取得
							tokenizer.nextToken();
							m_server.add(new String(tokenizer.sval));
							return;

						case SHOW :
							m_type = SHOW_INSTANCE;
							if (isHelpCommand) {
								break;
							}
							return;
							
						case SET :
							//インスタンス設定状態取得
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);
							if (type == UP) {
								m_type = SET_INSTANCE_UP;								
							} else if (type == DOWN) {
								m_type = SET_INSTANCE_DOWN;								
							}
							if (isHelpCommand) {
								break;
							}
							//サーバID番号取得
							tokenizer.nextToken();
							m_server.add(new String(tokenizer.sval));							
							return;

						}
						break;						

					case PRIORITY :

						//コマンドタイプ判別
						switch (typeCommand) {
						case SHOW :
							m_type = SHOW_PRIORITY;
							if (isHelpCommand) {
								break;
							}
							//テーブル名取得
							tokenizer.nextToken();
							m_table.add(new String(tokenizer.sval));
							return;

						case SET :
							m_type = SET_PRIORITY;
							if (isHelpCommand) {
								break;
							}
							//テーブル名取得
							tokenizer.nextToken();
							m_table.add(new String(tokenizer.sval));
							//パーティション番号取得
							tokenizer.nextToken();
							m_partNo.add(new String(tokenizer.sval));
							//サーバID取得							
							m_server = parseParenthesis(tokenizer);							
							//To do
							return;
						}
						break;						


					case TABLE :

						//コマンドタイプ判別
						switch (typeCommand) {
						case SHOW :
							if ((token = tokenizer.nextToken()) == StreamTokenizer.TT_EOF) {
								m_type = SHOW_TABLE;
								if (isHelpCommand) {
									break;
								}
							} else {
								m_type = SHOW_TABLE_COLUMN;
								if (isHelpCommand) {
									break;
								}
								m_table.add(new String(tokenizer.sval));		
//								token = tokenizer.nextToken();
//								if (token == ',') {
//									System.out.println("カンマ");
//								} else if (token == '(') {
//									System.out.println("左括弧");
//								} else if (token == ')') {
//									System.out.println("右括弧");
//								}
//								String str = tokenizer.sval;
//								System.out.println(str);
							}
							return;

						case PART :
							m_type = PART_TABLE;
							if (isHelpCommand) {
								break;
							}
							//テーブル名取得
							tokenizer.nextToken();
							m_table.add(new String(tokenizer.sval));
							//パーティション化属性取得							
							m_keyCol=parseParenthesis(tokenizer);
							//パーティション数取得
							tokenizer.nextToken();
							m_partCnt.add(new String(tokenizer.sval));
							//パーティション関数取得
							//データ移行フラグ取得
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);							
							if (type == WITH){
								parseEqualParams(tokenizer, m_type);
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}							
							return;

						case UNPART :
							m_type = UNPART_TABLE;
							if (isHelpCommand) {
								break;
							}
							//テーブル名取得
							tokenizer.nextToken();
							m_table.add(new String(tokenizer.sval));
							return;

						case REPART :
							m_type = REPART_TABLE;
							if (isHelpCommand) {
								break;
							}
							//テーブル名取得
							tokenizer.nextToken();
							m_table.add(new String(tokenizer.sval));
							//パーティション数取得
							tokenizer.nextToken();
							m_partCnt.add(new String(tokenizer.sval));
							//パーティション関数取得
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);
							if (type == WITH){
								parseEqualParams(tokenizer, m_type);
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}							
							return;
							
						}
						break;

					case TABLE2 :

						//コマンドタイプ判別
						switch (typeCommand) {
						case PART :
							m_type = PART_TABLE2;
							if (isHelpCommand) {
								break;
							}
							//テーブル名取得
							tokenizer.nextToken();
							m_table.add(new String(tokenizer.sval));
							//パーティション化属性取得							
							m_keyCol=parseParenthesis(tokenizer);
							//パーティション数取得
							tokenizer.nextToken();
							m_partCnt.add(new String(tokenizer.sval));
							//パーティション2テーブルの配置設定取得
							parsePartTable2Layout(tokenizer, m_type);
							//パーティション関数取得
							//データ移行フラグ取得
							type = commandSet.getInt(tokenizer.sval);
							if (type == WITH){
								parseEqualParams(tokenizer, m_type);
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}							
							return;
							
						}
						break;
						
					case USER :

						//コマンドタイプ判別
						switch (typeCommand) {
						case CREATE :
							m_type = CREATE_USER;
							if (isHelpCommand) {
								break;
							}
							//ユーザ名取得
							tokenizer.nextToken();
							m_user.add(new String(tokenizer.sval));		
							//パスワード取得
							tokenizer.nextToken();
							m_pass.add(new String(tokenizer.sval));		
							//パラメータ取得
							tokenizer.nextToken();
							type = commandSet.getInt(tokenizer.sval);	
							if (type == WITH){
								parseEqualParams(tokenizer, m_type);
							} else if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
								throw new Exception();
							}
							return;

						case DROP :
							m_type = DROP_USER;
							if (isHelpCommand) {
								break;
							}
							//ユーザ名取得
							tokenizer.nextToken();
							m_user.add(new String(tokenizer.sval));	
							return;

						case SHOW :
							m_type = SHOW_USER;
							if (isHelpCommand) {
								break;
							}
							return;
							
						}
						break;
				}

			}

		}
		} catch (Exception e) {
			String errorString = tokenizer.sval;
			if (errorString == null) {
				errorString = ";";
			}
			System.out.println(MessagesCommandLine.getString("cui.error.parser")); 
			System.out.println(MessagesCommandLine.getString("cui.error.parser.at", new Object[] { errorString })); 
			throw new Exception();
		}
	}



	/**
	 * コマンド判別用のマップ
	 *
	 */
	static class CommandMap extends Hashtable {

		public int getInt(Object key) {
			if(key == null){
				return -1;
			}

			Integer value = (Integer) get(key);

			return value == null ? -1 : value.intValue();

		}

		public int put(Object key, int value) {

			Integer oldvalue = (Integer) put(key, new Integer(value));

			return oldvalue == null ? -1 : oldvalue.intValue();

		}

	}



	/**
	 * @param string
	 */
	public void setReplaceWord(String string) {
		m_replaceWord = string;
	}
	
	/**
	 * Tokenizerの初期化
	 * 全てのトークンを文字列(sval)として抽出するよう設定
 	 * @return StreamTokenizer 初期化されたTokenizer
	 * @param string コマンドラインツールのコマンド
	 */
	public static StreamTokenizer initTokenizer(String command) {
		//StreamTokenizerの初期化
		StringReader fr = new StringReader(command);
		StreamTokenizer tokenizer = new StreamTokenizer(fr);

		
		tokenizer.wordChars('a', 'z');
		tokenizer.wordChars('A', 'Z');
		tokenizer.wordChars('_', '_');
		tokenizer.ordinaryChars('0', '9');
		tokenizer.wordChars('0','9');
		tokenizer.ordinaryChars('.', '.');
		tokenizer.wordChars('.','.');
		tokenizer.ordinaryChar(',');
		tokenizer.ordinaryChar('(');
		tokenizer.ordinaryChar(')');
		tokenizer.ordinaryChar('=');
//		tokenizer.wordChars(',',',');
		tokenizer.ordinaryChar('/');		
		tokenizer.wordChars('/','/');		
		tokenizer.whitespaceChars('\t', '\t');
		tokenizer.whitespaceChars('\n', '\n');
		tokenizer.whitespaceChars('\r', '\r');
		tokenizer.quoteChar('\'');
		tokenizer.quoteChar('\"');
		tokenizer.eolIsSignificant(false);

		return tokenizer;
	}

	/**
	 * パーティション2化テーブルを配置するサーバとパーティション番号を取得する。
	 * @param tokenizer コマンドが格納されたトークナイザ
	 * @param commandType コマンドの種類
	 * @throws Exception パースに失敗した場合
	 */
	private void parseDumpFileList(StreamTokenizer tokenizer, int commandType) throws Exception{
		int type = NONE;
		int token = StreamTokenizer.TT_EOF;
		token = tokenizer.nextToken();		
		while ((token != StreamTokenizer.TT_EOF) && (type != WITH)) {

			// 左括弧の抽出
			if (token != LEFT_PARENTHESIS) {
//				System.out.println(MessagesCommandLine.getString("cui.error.commandparser.parenthesis.invalid")); //$NON-NLS-1$
				throw new Exception();
			}
			// サーバIDの抽出
			token = tokenizer.nextToken();
			m_server.add(new String(tokenizer.sval));
			// カンマの抽出
			token = tokenizer.nextToken();
			if(token != COMMA) {
//				System.out.println(MessagesCommandLine.getString("cui.error.commandparser.parenthesis.invalid")); //$NON-NLS-1$
				throw new Exception();
			}
			// ダンプファイル名の抽出
			token = tokenizer.nextToken();
			m_dumpFile.add(new String(tokenizer.sval));

			// 右括弧の抽出			
			token = tokenizer.nextToken();
			if (token != RIGHT_PARENTHESIS) {
//				System.out.println(MessagesCommandLine.getString("cui.error.commandparser.parenthesis.invalid")); //$NON-NLS-1$
				throw new Exception();
			}
			token = tokenizer.nextToken();		
			if( token == COMMA) {
				token = tokenizer.nextToken();
			}
			
			type = commandSet.getInt(tokenizer.sval);
		}		
	}

	/**
	 * パーティション2化テーブルを配置するサーバとパーティション番号を取得する。
	 * @param tokenizer コマンドが格納されたトークナイザ
	 * @param commandType コマンドの種類
	 * @throws Exception パースに失敗した場合
	 */
	private void parsePartTable2Layout(StreamTokenizer tokenizer, int commandType) throws Exception{
		int type = NONE;
		int token = StreamTokenizer.TT_EOF;
		token = tokenizer.nextToken();	
		if (token == StreamTokenizer.TT_EOF) {
			throw new Exception();
		}
		while ((token != StreamTokenizer.TT_EOF) && (type != WITH)) {
			//サーバIDの取得
			type = commandSet.getInt(tokenizer.sval);
			if (type != SERVID){
				throw new Exception();
			}
			String server = parseEqualParam(tokenizer, commandType);
			if (server == null) {
				throw new Exception();				
			}
			m_server.add(server);
			//パーティションテーブル番号の取得
			tokenizer.nextToken();
			type = commandSet.getInt(tokenizer.sval);	
			if (type != PARTNO){
				throw new Exception();
			}
			// イコール
			token = tokenizer.nextToken();
			if (token != EQUAL) {
				throw new Exception();
			}
			m_part2No = parseParenthesis(tokenizer);
			m_part2NoList.add(m_part2No);
			token = tokenizer.nextToken();
			if( token == COMMA) {
				token = tokenizer.nextToken();
			}
			
			type = commandSet.getInt(tokenizer.sval);
		}		
	}
	
	/**
	 * イコール型のパラメータのパース
	 * @param tokenizer コマンドが格納されたトークナイザ
	 * @param commandType コマンドの種類
	 * @throws Exception イコールのパースに失敗した場合
	 */
	private void parseEqualParams(StreamTokenizer tokenizer, int commandType) throws Exception{
		int token = StreamTokenizer.TT_EOF;
		int type =NONE;
		int tokentype = commandSet.getInt(tokenizer.sval);
		token = tokenizer.nextToken();
		while ((token != StreamTokenizer.TT_EOF) ) {
			type = commandSet.getInt(tokenizer.sval);	

			// パラメータ名の取得
			if (!validateEqualParams(commandType, type)) {
				throw new Exception();
			}
			m_paramName.add(new String(tokenizer.sval));		
			// イコール
			token = tokenizer.nextToken();
			if (token != EQUAL) {
				throw new Exception();
			}
			// パラメータ値の取得
			tokenizer.nextToken();
			m_paramValue.add(new String(tokenizer.sval));	

			token = tokenizer.nextToken();
			if( token == COMMA) {
				token = tokenizer.nextToken();
			}
			tokentype = commandSet.getInt(tokenizer.sval);
		}			
	}
	
	/**
	 * イコール型のパラメータのパース
	 * @param tokenizer コマンドが格納されたトークナイザ
	 * @param commandType コマンドの種類
	 * @throws Exception イコールのパースに失敗した場合
	 */
	private String parseEqualParam(StreamTokenizer tokenizer, int commandType) throws Exception{
		String param = null;
		int token = StreamTokenizer.TT_EOF;
		int type =NONE;
		type = commandSet.getInt(tokenizer.sval);	
		// パラメータ名の取得
		if (!validateEqualParams(commandType, type)) {
			throw new Exception();
		}
		// イコール
		token = tokenizer.nextToken();
		if (token != EQUAL) {
			throw new Exception();
		}
		// パラメータ値の取得
		tokenizer.nextToken();
		param =tokenizer.sval;	
		
		return param;
	}
	
	
	/**
	 * イコール型のパラメータの妥当性チェック
	 * コマンドのパラメータではないパラメータが指定されていた場合のためのチェック
	 * @param typeCommand コマンドタイプ
	 * @param type 文字タイプ
	 * @return
	 */
	private boolean validateEqualParams(int typeCommand, int type) {
		boolean ret = false;
		if (typeCommand == CREATE_USER) {
			if (type == PASS || type == DBAUTH || type == USRAUTH) {
				ret = true;
			}
		} else if (typeCommand == SET_CONFIG) {
			if (type == CONFIGNAME || type == DESCRIPT || type == CACHEREFRESH
				|| type == RETRYCOUNT || type == DETECTTIMEOUT || type == DISTRIBUTE
				|| type == PARTMODE || type == SYNCMODE) {
				ret = true;
			}
		} else if (typeCommand == PART_TABLE) {
			if (type == HASHNAME || type == REST) {
				ret = true;
			}
		} else if (typeCommand == PART_TABLE2) {
			if (type == HASHNAME || type == REST 
				|| type == SERVID || type == PARTNO) {
				ret = true;
			}
		} else if (typeCommand == REPART_TABLE) {
			if (type == HASHNAME || type == REST) {
					ret = true;
				}
			}		
		return ret;
	}
	
	/**
	 * 括弧内のカンマで区切られた項目値の抽出
	 * @param tokenizer コマンドが格納されたトークナイザ
	 * @return 項目値が格納されたArrayList
	 * @throws Exception 括弧のパースに失敗した場合
	 */
	private ArrayList parseParenthesis(StreamTokenizer tokenizer) throws Exception{
		ArrayList paramValues = new ArrayList();
		int token = tokenizer.nextToken();
		
		// 左括弧の抽出
		if (token != LEFT_PARENTHESIS) {
			throw new Exception();
		}
		// 括弧内のパラメータの抽出
		token = tokenizer.nextToken();
		while (token != RIGHT_PARENTHESIS) {
			if(token != COMMA) {
				paramValues.add(new String(tokenizer.sval));
			}
			token = tokenizer.nextToken();
		}
		
		return paramValues;
	}
	
	



	public ArrayList getConfigName() {
		return m_configName;
	}

	public ArrayList getGsc() {
		return m_gscName;
	}

	public ArrayList getDB() {
		return m_db;
	}

	public ArrayList getHashDescript() {
		return m_hashDescript;
	}

	public ArrayList getHashFile() {
		return m_hashFile;
	}

	public ArrayList getHashName() {
		return m_hashName;
	}

	public ArrayList getHost() {
		return m_host;
	}

	public ArrayList getKeyCol() {
		return m_keyCol;
	}

	public ArrayList getRestore() {
		return m_restore;
	}

	public ArrayList getParamName() {
		return m_paramName;
	}

	public ArrayList getParamValue() {
		return m_paramValue;
	}

	public ArrayList getPartCnt() {
		return m_partCnt;
	}

	public ArrayList getPass() {
		return m_pass;
	}

	public ArrayList getPort() {
		return m_port;
	}

	public String getReplaceWord() {
		return m_replaceWord;
	}

	public ArrayList getServer() {
		return m_server;
	}

	public ArrayList getTables() {
		return m_table;
	}

	public int getType() {
		return m_type;
	}

	public ArrayList getUser() {
		return m_user;
	}
	public ArrayList getOption() {
		return m_dbOption;
	}
	public ArrayList getDumpFile() {
		return m_dumpFile;
	}

	public boolean isHelpCommand() {
		return isHelpCommand;
	}

	public ArrayList getPartNo() {
		return m_partNo;
	}

	public ArrayList getPart2No() {
		return m_part2No;
	}

	public ArrayList getPart2NoList() {
		return m_part2NoList;
	}

}
