package org.postgresforest.tool.commandline.action;

import java.util.ArrayList;
import java.util.Iterator;

import org.postgresforest.tool.action.DbAction;
import org.postgresforest.tool.action.DbInstanceAction;
import org.postgresforest.tool.action.ExecDdl;
import org.postgresforest.tool.bean.AddDbInfo;
import org.postgresforest.tool.bean.DbLinkInfo;
import org.postgresforest.tool.bean.ServerDumpDataInfo;
import org.postgresforest.tool.bean.ServerInfo;
import org.postgresforest.tool.db.DbBase;
import org.postgresforest.tool.db.GSCdata;
import org.postgresforest.tool.util.CommandParser;
import org.postgresforest.tool.util.MessagesCommandLine;

/**
 * データベースへのコマンドラインツール用のアクションを提供するクラス
 */
public class DbActions {

	/**
	 * DBの作成
	 * @param cp コマンド解析結果
	 * @param gsc GSCヘの接続情報
	 */	
	public void create(CommandParser cp, GSCdata gsc) {
		//DB名取得
		String dbName = (String)cp.getDB().get(0);
		//オプション取得
		String option = ""; //$NON-NLS-1$
		Iterator it = cp.getOption().iterator();
		while(it.hasNext()){
			option += (String)it.next();
		}
		
		ArrayList chkServerList = cp.getServer();
		// 表示用のサーバリストの作成
		String serverListStr = "";
		int chksize = chkServerList.size();
		for (int i=0; i<chksize-1;i++) {
			serverListStr += (String)chkServerList.get(i) + ",";
		}
		serverListStr += chkServerList.get(chksize-1);		
		
		DbInstanceAction dbInstance = new DbInstanceAction(gsc);
		AddDbInfo addDbInfo;
		try {
			addDbInfo = dbInstance.getAddDbInfo();
		} catch (Exception e) {
			System.out.println(MessagesCommandLine.getString("cui.error.db.create", new Object[] {dbName, serverListStr})); //$NON-NLS-1$
			System.err.println(e);
			return;
		}

		//DB作成インスタンス取得
		ArrayList serverList = addDbInfo.getServer();
		Iterator it2 = serverList.iterator();
		while(it2.hasNext()){
			ServerInfo srvInfo = (ServerInfo)it2.next();
			srvInfo.setChkFlag(false);
			int id = srvInfo.getId();
			Iterator it3 = chkServerList.iterator();
			while(it3.hasNext()){
				int chkServerId = Integer.parseInt((String)it3.next());
				if (id == chkServerId){
					srvInfo.setChkFlag(true);
				}
			}
		}
		
		//DB作成情報の格納
		addDbInfo.setDb(dbName);
		addDbInfo.setOption(option);
		addDbInfo.setMakeMode(DbBase.DB_MAKE);
		addDbInfo.setServer(serverList);

		// DB作成
		DbAction addDb = new DbAction(gsc);
		if (addDb.add(addDbInfo)) {
			System.out.println(MessagesCommandLine.getString("cui.message.db.create", new Object[] {dbName, serverListStr}));			 //$NON-NLS-1$
			return;
		}
		System.out.println(MessagesCommandLine.getString("cui.error.db.create", new Object[] {dbName, serverListStr})); //$NON-NLS-1$
	}
	
	/**
	 * DBの削除
	 * @param cp コマンド解析結果
	 * @param gsc GSCヘの接続情報
	 */	
	public void drop(CommandParser cp, GSCdata gsc) {
		String dbName = (String)cp.getDB().get(0);
		//データベース削除
		if(dbName != ""){ //$NON-NLS-1$
			//データベースリンク情報を取得
			ArrayList dbLinkList = getDbLinkList(gsc);
			
			//選択されているデータベースのサーバ情報を取得
			ArrayList dbServer = null;
			for (Iterator iter = dbLinkList.iterator(); iter.hasNext();) {
				DbLinkInfo dbInfo = (DbLinkInfo) iter.next();
				if (dbName.compareTo(dbInfo.getName()) == 0) {
					dbServer = dbInfo.getServer();
					break;
				}
			}

			for (Iterator iter= dbServer.iterator(); iter.hasNext();) {
				ServerInfo serverInfo = (ServerInfo) iter.next();
				serverInfo.setChkFlag(true); 
			}			

			//データベース削除
			DbAction dbAction = new DbAction(gsc);
			try {
				if(dbAction.del(dbLinkList)){
					System.out.println(MessagesCommandLine.getString("cui.message.db.drop", new Object[] {dbName}) ); //$NON-NLS-1$
					return;
				}
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
		System.out.println(MessagesCommandLine.getString("cui.error.db.drop", new Object[] {dbName}) ); //$NON-NLS-1$
	}

	/**
	 * DBのリストア
	 * @param cp コマンド解析結果
	 * @param gsc GSCヘの接続情報
	 */	
	public void restore(CommandParser cp, GSCdata gsc) {
		//DB名取得
		String dbName = (String)cp.getDB().get(0);

		ArrayList chkServerList = cp.getServer();
		// 表示用のサーバリストの作成
		String serverListStr = "";
		int chksize = chkServerList.size();
		for (int i=0; i<chksize-1;i++) {
			serverListStr += (String)chkServerList.get(i) + ",";
		}
		serverListStr += chkServerList.get(chksize-1);
		
		DbInstanceAction dbInstance = new DbInstanceAction(gsc);
		AddDbInfo addDbInfo;
		try {
			addDbInfo = dbInstance.getAddDbInfo();
		} catch (Exception e) {
			System.out.println(MessagesCommandLine.getString("cui.error.db.restore", new Object[] {dbName, serverListStr}) ); //$NON-NLS-1$
			System.err.println(e);
			return;
		}
	
		//ダンプファイル名取得
		ArrayList dumpFileList = cp.getDumpFile();
		//オプション取得
		String option = ""; //$NON-NLS-1$
		Iterator it = cp.getOption().iterator();
		while(it.hasNext()){
			option += (String)it.next();
		}
		//DB作成インスタンス取得
		ArrayList serverList = addDbInfo.getServer();
		Iterator it4 = serverList.iterator();
		while(it4.hasNext()){
			ServerDumpDataInfo srvInfo = (ServerDumpDataInfo)it4.next();
			int id = srvInfo.getId();
			srvInfo.setChkFlag(false);					
			Iterator it2 = chkServerList.iterator();
			Iterator it3 = dumpFileList.iterator();
			while(it2.hasNext()){
				int chkServerId = Integer.parseInt((String)it2.next());
				String dumpFile = (String)it3.next();
				if (id == chkServerId){
					srvInfo.setChkFlag(true);
					srvInfo.setDumpData(dumpFile);
				}
			}
		}

		//DB作成情報の格納
		addDbInfo.setDb(dbName);
		addDbInfo.setOption(option);
		addDbInfo.setMakeMode(DbBase.DB_SHIFT);
		addDbInfo.setServer(serverList);

		// DB選択とダンプファイルの整合性チェック
		validateDumpFile(addDbInfo);
		
		//DB作成
		DbAction addDb = new DbAction(gsc);
		if( addDb.add(addDbInfo) ){
			System.out.println(MessagesCommandLine.getString("cui.message.db.restore", new Object[] {dbName, serverListStr}) ); //$NON-NLS-1$
			return;
		}	
		System.out.println(MessagesCommandLine.getString("cui.error.db.restore", new Object[] {dbName, serverListStr}) ); //$NON-NLS-1$
	}
	
	/**
	 * DBの表示
	 * @param gsc GSCヘの接続情報
	 */	
	public void show(GSCdata gsc) {
		//DB情報取得
		ArrayList dbList = getDbLinkList(gsc);

		//DB情報表示
		System.out.println(MessagesCommandLine.getString("cui.message.db.show")) ; //$NON-NLS-1$
		Iterator it = dbList.iterator();
		System.out.println(" DBNAME \t| SERVERID \t| HOST \t| PORT "); //$NON-NLS-1$
		System.out.println("----------------------------------------------"); //$NON-NLS-1$
		while (it.hasNext()) {
			DbLinkInfo dbLinkInfo = (DbLinkInfo)it.next();
			Iterator it2 = dbLinkInfo.getServer().iterator();
			while (it2.hasNext()) {
				ServerInfo srvInfo = (ServerInfo)it2.next();
				System.out.print(dbLinkInfo.getName() + "\t| "); //$NON-NLS-1$
				System.out.print(srvInfo.getId() + "\t| "); //$NON-NLS-1$
				System.out.print(srvInfo.getHost() + "\t| "); //$NON-NLS-1$
				System.out.println(srvInfo.getPort());
			}
		}
	}

	/**
	 * DBインスタンスの追加
	 * @param cp コマンド解析結果
	 * @param gsc GSCヘの接続情報
	 */	
	public void createDbInstance(CommandParser cp, GSCdata gsc) {
		//DB名取得
		String dbName = (String)cp.getDB().get(0);
		//ダンプファイル名取得
		ArrayList dumpFileList = cp.getDumpFile();
		//オプション取得
		String option = ""; //$NON-NLS-1$
		Iterator it = cp.getOption().iterator();
		while(it.hasNext()){
			option += (String)it.next();
		}
		
		//指定されたDBが存在するかどうかのチェック
		ArrayList dbList = getDbLinkList(gsc);
		Iterator itdb = dbList.iterator();
		boolean isDbExist = false;
		while (itdb.hasNext()) {
			DbLinkInfo dbLinkInfo = (DbLinkInfo)itdb.next();
			if (dbName.equals(dbLinkInfo.getName())){
				isDbExist = true;
			}
		}
		if (!isDbExist) {
			System.out.println(MessagesCommandLine.getString("cui.error.db.open.nosuchdb", new Object[] { dbName })) ;
			return;
		}
		
		ArrayList chkServerList = cp.getServer();
		// 表示用のサーバリストの作成
		String serverListStr = "";
		int chksize = chkServerList.size();
		for (int i=0; i<chksize-1;i++) {
			serverListStr += (String)chkServerList.get(i) + ",";
		}
		serverListStr += chkServerList.get(chksize-1);
		
		DbInstanceAction dbInstance = new DbInstanceAction(gsc);
		AddDbInfo addDbInfo;
		try {
			addDbInfo = dbInstance.getAddDbInfo();
		} catch (Exception e) {
			System.out.println(MessagesCommandLine.getString("cui.error.db.instance.add", new Object[] {dbName, serverListStr})) ; //$NON-NLS-1$
			System.err.println(e);
			return;
		}

 		// 指定されたDB名の登録されていないインスタンスのリストを作成する
		ArrayList existServerList = getExistServerList(gsc, dbName);
		ArrayList serverList = addDbInfo.getServer();

		for (Iterator iter2 = existServerList.iterator(); iter2.hasNext();) {
			ServerInfo existServerInfo = (ServerInfo) iter2.next();
			for (Iterator iter = serverList.iterator(); iter.hasNext();) {
				ServerInfo severInfo = (ServerInfo) iter.next();
				if( severInfo.getId() == existServerInfo.getId() ){
					serverList.remove(severInfo);
					break;
				}
			}
			
		}
	
		//DB作成インスタンス取得
		Iterator it4 = serverList.iterator();
		while(it4.hasNext()){
			ServerDumpDataInfo srvInfo = (ServerDumpDataInfo)it4.next();
			int id = srvInfo.getId();
			srvInfo.setChkFlag(false);					
			Iterator it2 = chkServerList.iterator();
			Iterator it3 = dumpFileList.iterator();
			while(it2.hasNext()){
				int chkServerId = Integer.parseInt((String)it2.next());
				String dumpFile = (String)it3.next();
				if (id == chkServerId){
					srvInfo.setChkFlag(true);
					srvInfo.setDumpData(dumpFile);
				}
			}
		}
		
		// チェックしたインスタンスが既にDBに登録されていないかのチェック
		// エラー表示用のサーバリストの作成
		String existServerListStr = "";
		int servsize = serverList.size();
		for (int i=0; i<servsize-1;i++) {
			existServerListStr += Integer.toString(((ServerDumpDataInfo)serverList.get(i)).getId()) + ",";
		}
		if(servsize == 0) {
			System.out.println(MessagesCommandLine.getString("cui.error.db.instance.invalid.noaddinstance", new Object[] {dbName})) ; //$NON-NLS-1$				
			return;
		}
		existServerListStr += Integer.toString(((ServerDumpDataInfo)serverList.get(servsize-1)).getId()) ;
		Iterator it5 = chkServerList.iterator();
		while(it5.hasNext()){
			boolean existFlag = false;
			int chkServerId = Integer.parseInt((String)it5.next());
			Iterator it6 = serverList.iterator();
			while(it6.hasNext()){
				ServerDumpDataInfo srvInfo = (ServerDumpDataInfo)it6.next();
				int id = srvInfo.getId();
				if (id == chkServerId){
					existFlag = true;
				}
			}
			if (!existFlag) {
				System.out.println(MessagesCommandLine.getString("cui.error.db.instance.invalid", new Object[] {existServerListStr})) ; //$NON-NLS-1$				
				return;
			}
		}
		
		// DB選択とダンプファイルの整合性チェック
		validateDumpFile(addDbInfo);
		
		//DB作成情報の格納
		addDbInfo.setDb(dbName);
		addDbInfo.setOption(option);
		addDbInfo.setMakeMode(DbBase.DB_ADD);
		addDbInfo.setServer(serverList);

		//DB作成
		DbAction addDb = new DbAction(gsc);
		if( addDb.add(addDbInfo) ){
			System.out.println(MessagesCommandLine.getString("cui.message.db.instance.add", new Object[] {dbName, serverListStr})) ; //$NON-NLS-1$
			return;
		}
		System.out.println(MessagesCommandLine.getString("cui.error.db.instance.add", new Object[] {dbName, serverListStr})) ; //$NON-NLS-1$
	}
	
	/**
	 * DBインスタンスの削除
	 * @param cp コマンド解析結果
	 * @param gsc GSCヘの接続情報
	 */	
	public void dropDbInstance(CommandParser cp, GSCdata gsc) {
		String dbName = (String)cp.getDB().get(0);
		int selectId = Integer.parseInt((String)cp.getServer().get(0));
		//データベース削除
		if(dbName != "" && selectId >= 0){ //$NON-NLS-1$

			//セッション･プロパティからデータベースリンク情報を取得
			ArrayList dbLinkList = getDbLinkList(gsc);
			
			//選択されているデータベースのサーバ情報を取得
			ArrayList dbServer = null;
			for (Iterator iter = dbLinkList.iterator(); iter.hasNext();) {
				DbLinkInfo dbInfo = (DbLinkInfo) iter.next();
				if (dbName.compareTo(dbInfo.getName()) == 0) {
					dbServer = dbInfo.getServer();
					break;
				}
			}

			//
			for (Iterator iter= dbServer.iterator(); iter.hasNext();) {
				ServerInfo serverInfo = (ServerInfo) iter.next();
				if (serverInfo.getId() == selectId) {
					serverInfo.setChkFlag(true);
					break;
				}
			}

			//データベース削除
			DbAction dbAction = new DbAction(gsc);
			try {
				if (dbAction.del(dbLinkList)) {
					System.out.println(MessagesCommandLine.getString("cui.message.db.instance.delete", new Object[] {dbName, Integer.toString(selectId)})) ;		
					return;
				}
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
		System.out.println(MessagesCommandLine.getString("cui.error.db.instance.delete", new Object[] {dbName, Integer.toString(selectId)})) ; //$NON-NLS-1$
		
	}
	
	/**
	 * DDLコマンドの実行
	 * @param gsc GSCヘの接続情報
	 * @param command DDLコマンド
	 * @param selectDb データベース名
	 */	
	public void executeDdl(GSCdata gsc, String command, String selectDb) {
		String dbName = null;
		if (selectDb != null) {
			dbName = selectDb;
		} else {
			System.err.print(MessagesCommandLine.getString("cui.message.db.notopen", new Object[] {dbName})); //$NON-NLS-1$
			return;
		}
		ExecDdl execDdl = new ExecDdl(gsc, dbName);
		try {
			if (execDdl.executeMain(command)) {
				System.out.println(MessagesCommandLine.getString("cui.message.db.ddl.execute", new Object[] {dbName})) ;				 //$NON-NLS-1$
				return;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}				
		System.out.println(MessagesCommandLine.getString("cui.error.db.ddl.execute", new Object[] {dbName})) ;				 //$NON-NLS-1$
	}

	/**
	 * データベースのオープン
	 * @param cp コマンド解析結果
	 * @param gsc GSCヘの接続情報
	 */	
	public boolean open(CommandParser cp, GSCdata gsc) {
		boolean ret = false;		
		String dbName = (String)cp.getDB().get(0);
		//DB情報取得
		ArrayList dbList = getDbLinkList(gsc);
		//DB情報表示
		Iterator it = dbList.iterator();
		while (it.hasNext()) {
			DbLinkInfo dbLinkInfo = (DbLinkInfo)it.next();
			if (dbName.compareToIgnoreCase(dbLinkInfo.getName()) == 0) {
				ret = true;
				break;
			}
		}
		return ret;
	}
	
	/**
	 * データベース一覧の取得
	 * @param gsc GSCヘの接続情報
	 */
	private ArrayList getDbLinkList(GSCdata gsc) {
		ArrayList dbList = null;
		DbInstanceAction dbInstance = new DbInstanceAction(gsc);
		try {
			dbList = dbInstance.getDbLinkList();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return dbList;
	}
	
	private ArrayList getExistServerList(GSCdata gsc, String dbName) {
		ArrayList serverList = null;
		ArrayList servDbList = getDbLinkList(gsc);
		Iterator it = servDbList.iterator();
		while (it.hasNext()) {
			DbLinkInfo dbLinkInfo = (DbLinkInfo)it.next();
			if (dbName.equals(dbLinkInfo.getName())) {
				serverList = dbLinkInfo.getServer();
			}
		}
		return serverList;
	}

    /* (非 Javadoc)
     * @see org.postgresforest.tool.dialog.CommonDialog#validate()
     */
    private boolean validateDumpFile(AddDbInfo m_addDb) {
    	boolean isValid = false;
    	
		ArrayList serverList = m_addDb.getServer();
		for (Iterator iter = serverList.iterator(); iter.hasNext();) {
		    ServerDumpDataInfo serverInfo = (ServerDumpDataInfo) iter.next();
		    String dumpdata = serverInfo.getDumpData();
		    boolean isChkServer = serverInfo.isChkFlag();
		    if(isChkServer && (dumpdata == null || dumpdata.equals(""))){
				System.out.println(MessagesCommandLine.getString("errors.dump.input" ));
				return isValid;
		    }
            
        }
		isValid = true;
		return isValid;

    }	
}
