/*

Copyright (C) 2009 NTT DATA INTELLILINK CORPORATION

This program is free software; you can redistribute it and/or
Modify it under the terms of the GNU General Public License 
as published by the Free Software Foundation, version 2.

This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied 
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
PURPOSE.  See the GNU General Public License for more details.

 */

package jp.co.intellilink.hinemos.test.monitor.syslogng;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import jp.co.intellilink.hinemos.test.util.EjbConnectionManager;
import jp.co.intellilink.hinemos.test.util.Messages;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.clustercontrol.logtransfer.bean.LogTransferFileInfo;
import com.clustercontrol.logtransfer.bean.LogTransferInfo;
import com.clustercontrol.logtransfer.ejb.session.LogTransferController;
import com.clustercontrol.repository.bean.FacilityAttributeConstant;
import com.clustercontrol.repository.ejb.session.RepositoryController;
import com.clustercontrol.syslogng.bean.LogFilterInfo;
import com.clustercontrol.syslogng.ejb.session.SyslogNGController;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;

/**
 * Syslog-ng監視のテストクラス<br>
 * 
 * @version 1.0.2
 * @since 1.0.2
 */
public class TestMonitorSyslogng {

	// ログ出力
	private static Log log = LogFactory.getLog(TestMonitorSyslogng.class);
	protected BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

	protected HashMap<String, ArrayList<String>> messageMap = new HashMap<String, ArrayList<String>>();
	protected HashMap<String, ArrayList<String>> fileMap = new HashMap<String, ArrayList<String>>();

	protected static final ArrayList<String> attributeListTarget = new ArrayList<String>();
	protected static final ArrayList<String> attributeListPlatform = new ArrayList<String>();
	static{
		attributeListTarget.add(FacilityAttributeConstant.IPPROTOCOLNUMBER);
		attributeListTarget.add(FacilityAttributeConstant.NODENAME);
		attributeListTarget.add(FacilityAttributeConstant.IPNETWORKNUMBER);
		attributeListTarget.add(FacilityAttributeConstant.IPNETWORKNUMBERV6);
		attributeListPlatform.add(FacilityAttributeConstant.PLATFORM);
	}

	public static void main(String[] arg){
		TestMonitorSyslogng test = new TestMonitorSyslogng();
		test.test();
	}

	/**
	 * Syslog-ng監視をテストする。<br>
	 */
	public void test() {
		log.info("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.Syslogng.Start"));

		messageMap = getMessageMap();
		fileMap = getFileMap();

		for(String facilityId : messageMap.keySet()){
			Object[] args = {facilityId};
			log.info("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.FacilityID", args));

			logger(facilityId);
		}

		log.info("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.Syslogng.End"));
	}

	/**
	 * Syslog-ng監視テスト実行
	 * 
	 * @param facilityId ファシリティID
	 */
	protected void logger(String facilityId){
		String platform = getPlatform(facilityId);
		if(platform.matches(".*(Linux|LINUX|linux).*")){
			loggerLinux(facilityId);
		}
		else if(platform.matches(".*(Windows|WINDOWS|windows).*")){
			loggerWindows(facilityId);
		}
	}

	/**
	 * Syslog-ng監視テスト実行(Linux)
	 * 
	 * @param facilityId ファシリティID
	 */
	protected void loggerLinux(String facilityId){
		try{
			String node = getTargetIP(facilityId);

			JSch jsch=new JSch();

			System.out.println("Enter uid (" + node + ")");
			System.out.print("uid > ");
			String user = reader.readLine();

			Session session=jsch.getSession(user, node, 22);

			// username and password will be given via UserInfo interface.
			MyUserInfo ui = new MyUserInfo();
			session.setUserInfo(ui);
			session.connect();

			if((messageMap.get(facilityId) instanceof ArrayList)){
				for(String message : messageMap.get(facilityId)){
					String filePath = "";
					if(fileMap.get(facilityId) instanceof ArrayList){
						for(String file : fileMap.get(facilityId)){
							if(message.matches(".*" + file + ".*")){
								filePath = file;
								break;
							}
						}
					}

					String command = "";
					if(filePath == "")
						command = "logger " + "'" + message + "'";
					else
						command = "echo " + "'" + message + "' >> " + filePath;

					log.info("[" + Messages.getMsg("TestSyslog")+ "] " + "Command Execute : " + command);
					System.out.println("Command Execute : " + command);

					Channel channel=session.openChannel("exec");
					((ChannelExec)channel).setCommand(command);

					channel.setInputStream(null);
					((ChannelExec)channel).setErrStream(System.err);

					InputStream in = channel.getInputStream();

					channel.connect();

					byte[] tmp=new byte[1024];
					while(true){
						String output = "";
						while(in.available()>0){
							int i=in.read(tmp, 0, 1024);
							if(i<0)break;
							output = new String(tmp, 0, i);
							System.out.print(output);
						}
						if(channel.isClosed()){
							log.info("[" + Messages.getMsg("TestSyslog")+ "] " + "ExitCode : " + channel.getExitStatus());
							System.out.println("ExitCode : " + channel.getExitStatus());
							break;
						}
						try{Thread.sleep(500);}catch(Exception ee){}
					}
					channel.disconnect();
				}
			}
			session.disconnect();
		}
		catch(Exception e){
			log.error("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.ConnectManagerFailed"), e);
			System.exit(14);
		}
	}

	/**
	 * Syslog-ng監視テスト実行(Windows)
	 * 
	 * @param facilityId ファシリティID
	 */
	protected void loggerWindows(String facilityId){
	}

	/**
	 * テスト対象のプラットフォームを取得する<br>
	 * 
	 * @param facilityId ファシリティID
	 * @return テスト対象のプラットフォーム
	 */
	protected String getPlatform(String facilityId) {
		RepositoryController repository = EjbConnectionManager.getConnectionManager().getRepositoryController();

		String platform = "";
		if(facilityId != null && !"".equals(facilityId)){	
			try{
				// ノードの属性取得
				@SuppressWarnings("unchecked")
				HashMap facilityAttrMap = repository.getNodeDetail(facilityId, attributeListPlatform);

				//プラットフォームを取得する。
				platform = (String)facilityAttrMap.get(FacilityAttributeConstant.PLATFORM);
			} catch (Exception e){
				log.error("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.ConnectManagerFailed"), e);
				System.exit(14);
			}
		}

		return platform;
	}

	/**
	 * テスト対象のIPアドレスを取得する<br>
	 * 
	 * @param facilityId ファシリティID
	 * @return テスト対象のIPアドレス
	 */
	protected String getTargetIP(String facilityId) {
		RepositoryController repository = EjbConnectionManager.getConnectionManager().getRepositoryController();

		int version = 4;
		String node = "";
		if(facilityId != null && !"".equals(facilityId)){	
			try{
				// ノードの属性取得
				@SuppressWarnings("unchecked")
				HashMap facilityAttrMap = repository.getNodeDetail(facilityId, attributeListTarget);

				//プロトコルのバージョンが指定されていればversionを指定する。
				if((Integer)facilityAttrMap.get(FacilityAttributeConstant.IPPROTOCOLNUMBER) != null){
					version = ((Integer)facilityAttrMap.get(FacilityAttributeConstant.IPPROTOCOLNUMBER)).intValue();
				}else{
					version = 4;
				}

				if(version == 6){
					InetAddress[] ip = InetAddress.getAllByName((String)facilityAttrMap.get(FacilityAttributeConstant.IPNETWORKNUMBERV6));

					if(ip.length != 1){
						//IPアドレスをInetAddressクラスでデコードしているのに1つじゃないときは
						//UnnownHostExcption
						throw new UnknownHostException();
					}

					node = ip[0].getHostAddress();
				}else{
					node = (String)facilityAttrMap.get(FacilityAttributeConstant.IPNETWORKNUMBER);
				}
			} catch (Exception e){
				log.error("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.ConnectManagerFailed"), e);
				System.exit(14);
			}
		}

		return node;
	}

	/**
	 * ノードのファシリティIDを取得する。<br>
	 * 
	 * @param facilityId ファシリティID
	 * @return ファシリティIDリスト
	 */
	@SuppressWarnings("unchecked")
	protected ArrayList<String> getFacilityIdList(String facilityId) {

		RepositoryController repository = EjbConnectionManager.getConnectionManager().getRepositoryController();

		ArrayList<String> records = new ArrayList<String>();
		try {
			if(repository.isNode(facilityId)){
				records.add(facilityId);
			}
			else{
				records.addAll(repository.getExecTargetFacilityIdList(facilityId));
			}
		} catch (Exception e) {
			log.error("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.ConnectManagerFailed"), e);
			System.exit(14);
		}
		return records;
	}

	/**
	 * 監視項目リストを取得する。<br>
	 * 
	 * @return 監視項目一覧
	 */
	protected HashMap<String, ArrayList<String>> getMessageMap() {
		HashMap<String, ArrayList<String>> messageMap = new HashMap<String, ArrayList<String>>();

		ArrayList<LogFilterInfo> infoList = getSyslogngList();

		if(infoList instanceof ArrayList){
			for(LogFilterInfo info : infoList){
				Object[] args = {info.getMonitorId()};
				log.info("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.MonitorID", args));
				
				ArrayList<String> facilityIdList = getFacilityIdList(info.getFacilityId());
				for(String facilityId : facilityIdList){
					ArrayList<String> messageList = messageMap.get(facilityId);
					if(!(messageList instanceof ArrayList))
						messageList = new ArrayList<String>();

					messageList.add(info.getPattern());

					messageMap.put(facilityId, messageList);
				}
			}
		}
		return messageMap;
	}


	/**
	 * 監視項目リストを取得する。<br>
	 * 
	 * @return 監視項目一覧
	 */
	@SuppressWarnings("unchecked")
	protected ArrayList<LogFilterInfo> getSyslogngList() {

		SyslogNGController syslog = EjbConnectionManager.getConnectionManager().getMonitorSyslogNGController();

		ArrayList<LogFilterInfo> records = null;
		try {
			records = syslog.getFilterInfoList();
		} catch (Exception e) {
			log.error("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.ConnectManagerFailed"), e);
			System.exit(14);
		}
		return records;
	}

	/**
	 * ログ転送情報を取得する。<br>
	 * 
	 * @return ログ転送情報
	 */
	@SuppressWarnings("unchecked")
	protected HashMap<String, ArrayList<String>> getFileMap() {
		HashMap<String, ArrayList<String>> fileMap = new HashMap<String, ArrayList<String>>();

		ArrayList idList = getLogTransferIdList();

		if(idList instanceof ArrayList){
			Iterator itr = idList.iterator();
			while(itr.hasNext()){
				ArrayList line = (ArrayList)itr.next();

				Object[] args = {(String)line.get(0)};
				log.info("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.TransferID", args));

				LogTransferInfo info = getLogTransfer((String)line.get(0));
				ArrayList<String> facilityIdList = getFacilityIdList(info.getFacilityId());
				for(String facilityId : facilityIdList){
					ArrayList<String> fileList = fileMap.get(facilityId);
					if(!(fileList instanceof ArrayList))
						fileList = new ArrayList<String>();

					for(LogTransferFileInfo fileInfo : info.getFileInfo()){
						fileList.add(fileInfo.getFilePath());
					}
					fileMap.put(facilityId, fileList);
				}
			}
		}
		return fileMap;
	}

	/**
	 * ログ転送情報を取得する。<br>
	 * 
	 * @param transferId 取得対象の転送ID
	 * @return ログ転送情報
	 */
	protected LogTransferInfo getLogTransfer(String transferId) {

		LogTransferController transfer = EjbConnectionManager.getConnectionManager().getLogTransferController();

		LogTransferInfo info = null;
		try {
			info = transfer.getLogTransfer(transferId);
		} catch (Exception e) {
			log.error("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.ConnectManagerFailed"), e);
			System.exit(14);
		}
		return info;
	}

	/**
	 * 転送IDリストを取得する。<br>
	 * 
	 * @return 転送ID一覧
	 */
	@SuppressWarnings("unchecked")
	protected ArrayList getLogTransferIdList() {

		LogTransferController transfer = EjbConnectionManager.getConnectionManager().getLogTransferController();

		ArrayList records = null;
		try {
			records = transfer.getLogTransferList();
		} catch (Exception e) {
			log.error("[" + Messages.getMsg("TestSyslog")+ "] " + Messages.getMsg("TestTool.ConnectManagerFailed"), e);
			System.exit(14);
		}
		return records;
	}

	public static class MyUserInfo implements UserInfo{
		protected BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		protected String passwd;

		public String getPassword(){ 
			return passwd; 
		}
		public boolean promptYesNo(String str){
			try {
				System.out.println("\n" + str);
				System.out.print("y/n > ");
				String res = reader.readLine();
				String check = res.trim().toLowerCase();
				if(check.equals("y"))
					return true;
				else if(check.equals("yes"))
					return true;
				else
					return false;
			} catch (IOException e) {
				e.printStackTrace();
				return false; 
			}
		}
		public String getPassphrase(){ 
			return null;
		}
		public boolean promptPassphrase(String message){
			return true; 
		}
		public boolean promptPassword(String message){
			try {
				System.out.println("\nEnter password");
				System.out.print("password > ");
				passwd = reader.readLine();
				return true;
			} catch (IOException e) {
				e.printStackTrace();
				return false; 
			}
		}
		public void showMessage(String message){
			System.out.print("message");
		}
	}
}