package com.nms.server.thread.monitor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.log4j.Logger;

import com.nms.server.bean.AlarmInfo;
import com.nms.server.bean.SetInfo;
import com.nms.server.common.Common;
import com.nms.server.common.Constants;
import com.nms.server.util.CSVUtils;
import com.nms.server.util.ExceptionPrintUtils;

/**
 * 监测数据 Ping数据获取执行线程
 * 
 * @date Jul 18, 2011 5:32:44 PM
 * @author ZhangGang
 * 
 */
public class PingThread  implements Runnable {
	private Logger logger = Logger.getLogger(PingThread.class);
	private String name;
	private String pingIp = "";
	private long startTime = Calendar.getInstance().getTimeInMillis();
	private String checkTypeName = null;
	private Long sitInfoId = null;
	private long outTime = 2;
	private long maxTimes = 3;
	private long gap = 0;
	private CountDownLatch downLatch;
	/**
	 * 构造方法
	 * @param name 线程名称
	 * @param ip 被监测端IP	
	 * @param port socket通信端口
	 * @param info
	 */
	public PingThread(String name,String ip,SetInfo info,Long startTime,CountDownLatch downLatch) {
		this.name = name;
		this.pingIp = ip;
		this.sitInfoId = info.getId();
		this.checkTypeName = info.getCheckTypeName();
		this.startTime = startTime;
		this.outTime = info.getCheckOutTime();
		this.maxTimes = info.getCheckMaxTimes();
		this.gap = info.getCheckGap();
		this.downLatch = downLatch;
	}
	
	public PingThread(String name,String ip,SetInfo info,Long startTime) {
		this.name = name;
		this.pingIp = ip;
		this.sitInfoId = info.getId();
		this.checkTypeName = info.getCheckTypeName();
		this.startTime = startTime;
		this.outTime = info.getCheckOutTime();
		this.maxTimes = info.getCheckMaxTimes();
		this.gap = info.getCheckGap();
		this.downLatch = downLatch;
	}
	/**
	 * 构造方法
	 * 
	 * @param name
	 *            线程名称
	 * @param pingIp
	 *            被监测端IP
	 * @param sitInfoId
	 *            设置信息ID
	 * @param outTime
	 *            超时时间
	 * @param maxTimes
	 *            最大尝试次数
	 */
	/*public PingThread(String name, Long sitInfoId, String pingIp, long gap,
			long outTime, long maxTimes) {
		this.name = name;
		this.pingIp = pingIp;
		this.sitInfoId = sitInfoId;
		this.outTime = outTime;
		this.maxTimes = maxTimes;
		this.gap = gap;
	}
*/
	@Override
	public void run() {
		Thread.currentThread().setName(name + " " + pingIp);
		BufferedReader in = null; // 读取 Ping命令返回的信息

		try {
			
			StringBuffer buffer = new StringBuffer();
			logger.debug("Ping 监测获取开始");
			Calendar checkTime = Calendar.getInstance();
			Calendar nextTime = Calendar.getInstance();
			nextTime.add(Calendar.MINUTE, Long.valueOf(gap).intValue());
			List<String> datas = new ArrayList<String>(); // 拼写数据格式
			// --初始部分数据整理
			datas.add(Common.getIpSeqIdMap().get(pingIp)+"");// IP，
			datas.add(sitInfoId + "");// 监测设置ID，
			datas.add(checkTypeName);// 监测类别，
			datas.add("");// 进程名称（检查类别设置名称），
			datas.add(startTime + "");// 监测服务启动时间，
			datas.add("0");// 检测时延（秒）
			datas.add(checkTime.getTimeInMillis() + "");// 本次检测时间，
			String command = ""; // 命令语句
			int minTime = Integer.MAX_VALUE, maxTime = 0, totalTime = 0, curTime; // 最短时间，最长时间，总时间，时间变量
			int snum = 0, fnum = 0; // 发包成功和失败数
			// 判断系统类型 win or Linux
			String system = (String) (System.getProperty("os.name"))
					.toLowerCase();
			if (system.toLowerCase().indexOf("win") != -1) {
				command += "ping -n " + maxTimes + " -w " + outTime * 1000
						+ " " + pingIp;
			} else if (system.toLowerCase().indexOf("linux") != -1) {
				command += "ping -c " + maxTimes + " -w " + outTime
						+ " " + pingIp;
			} else {
				command += "ping -w 4 " + pingIp;
			}
			
			String stateInfo = "";
			int state = -1;
			String[] datas2 = new String[7];
			Process process = null;
			try {
				process = Runtime.getRuntime().exec(command);
				in = new BufferedReader(new InputStreamReader(process
						.getInputStream()));
				String line = null;
				long count = maxTimes + 10;
				int index;
				// 最多只读10行
				while ((line = in.readLine()) != null && count != 0) {
					if ("".equals(line)) {
						continue;
					} // 空串跳过
					//System.out.println("-- "+line);
					buffer.append(line + "\n");
					line = line.toLowerCase();
					// System.out.println(pingIp+"> line === "+line);
					if (line.indexOf("ttl") > 0) { // 获得成功响应的数据
						count--; // 计数器自减1
						// 截取time 值
						if ((index = line.lastIndexOf("ms")) != -1) {
							byte[] buf = line.getBytes();
							int start = 0, end = buf.length, i, j;
							// 下标末点
							for (i = index; i >= 0; i--) {
								if (Character.isDigit((char) buf[i])) {
									end = i;
									break;
								}
							}
							if (i == 0)
								continue;
							// 下标起点
							for (j = end; j >= 0; j--) {
								if (!Character.isDigit((char) buf[j])) {
									start = j + 1;
									break;
								}
							}
							// 时间值截取
							curTime = Integer.parseInt(new String(buf, start,
									end + 1 - start));
							snum++; // 成功接收次数加1
							totalTime += curTime; // 计算总时间
							if (curTime < minTime) {
								minTime = curTime;
							} // 最小时间
							if (curTime > maxTime) {
								maxTime = curTime;
							} // 最大时间
						}
					} else if (line.split(" ").length < 4) {
						count--; // 计数器自减1
						fnum++; // 失败接收次数加1
					} else {
						stateInfo += line + "\n";
					}
				}
				if (totalTime == 0) {
					minTime = 0;
				}
				// 已发送包数
				datas2[0] = "" + (snum + fnum);
				datas2[1] = "" + snum;
				datas2[2] = "" + fnum;
				if (snum == 0 && fnum == 0) {
					state = -1;
					fnum = 1;
				} else {
					state = 0;
				}
				BigDecimal fnum0 = new BigDecimal(fnum);
				BigDecimal tnum0 = new BigDecimal(snum + fnum);
				DecimalFormat df = new DecimalFormat("####0.00");
				datas2[3] = ""
						+ ((new BigDecimal(df.format(fnum0.divide(tnum0,2,RoundingMode.HALF_UP))))
								.multiply(new BigDecimal(100)));
				datas2[4] = "" + minTime;
				datas2[5] = "" + maxTime;
				datas2[6] = "" + (snum == 0 ? 0 : (totalTime / snum));
			} catch (Exception e) {
				state = -1;
				logger.error(ExceptionPrintUtils.printExceptionStack(e));
			}finally{
				if(in!=null){try {
					in.close();
				} catch (IOException e) {
					logger.error("",e);
				}}
				if(process!= null)process.destroy();
				process = null;
			}

			if (state != -1) {
				datas.add((snum + fnum) + "");// 尝试次数，
				datas.add(nextTime.getTimeInMillis() + "");// 下次计划监测时间，
				// -- 执行状态是否成功，记录的状态是否正常（用于报警），
				String[] pArray = getAlarmState(Common.getAlarmInfoMap().get(
						sitInfoId.longValue() + ""), datas2);
				
				if (pArray == null && snum > 0) {
					datas.add("1"); // 执行状态 正常
					datas.add(""); // 告警列序号，
					datas.add(""); // 告警级别，
					datas.add(""); // 告警值，
				} else {
					datas.add("0"); // 执行状态 非正常
					datas.add(pArray == null ? "" : pArray[0]); // 告警列序号，
					datas.add(pArray == null ? "" : pArray[1]); // 告警级别，
					datas.add(pArray == null ? "" : pArray[2]); // 告警值，
				}
				if(snum == 0){
//					stateInfo = "目标主机ping失败 \n"+stateInfo;
//					stateInfo = "Failed to ping the target host \n"+stateInfo;
					stateInfo = "i18n_server.PingThread.ping_n81i \n"+stateInfo;
				}
				datas.add(stateInfo); // 状态信息（描述信息），
				datas.add(stateInfo); // 性能数据，
				datas.addAll(Arrays.asList(datas2));// 监测具体数据信息（每个字段一列）
			} else {
				datas.add((snum + fnum) + ""); // 尝试次数，
				datas.add(nextTime.getTimeInMillis() + "");// 下次计划监测时间，
				datas.add("-1"); // 执行状态
				datas.add(""); // 告警列序号，
				datas.add(""); // 告警级别，
				datas.add(""); // 告警值，
				datas.add(stateInfo); // 状态信息（描述信息），
				datas.add(stateInfo); // 性能数据，
			}
			//- 存入缓存
			try {
				Common.addDeteData(CSVUtils.csvBytesPrinter(datas, Constants.COMMON_TEXT_CODING));
				logger.debug("监测数据以 CSV格式 保存完成");
			} catch (Exception e) {
				logger.error("Monitoring data to save exceptions in CSV format", e);
			}

		} catch (Exception ex) {
			logger.error("",ex);
			String[] alarm = Common.alarmExceptionInfo(sitInfoId, pingIp, Constants.DETEC_PING_STR, "", startTime, 1,Constants.DETECTION_INFO_ALARM_WRONG, ex.getMessage());
			Common.addAlarmData(alarm);
		} finally {
			if(downLatch != null){
				downLatch.countDown();
			}
			try {
				if (in != null)
					in.close();
			} catch (IOException e) {
				logger.error(ExceptionPrintUtils.printExceptionStack(e));
			}
		}
	}

	// 获得当前的报警设置信息，与相应字段值比较
	private String[] getAlarmState(List<AlarmInfo> alarmInfos, String[] sysData) {
		String[] strs = null;
		if (alarmInfos != null) {
			strs = new String[] { "", "", "" };
			for (AlarmInfo alarm : alarmInfos) {
				if (sysData.length >= alarm.getShowNum()) {
					Double data = Math.abs(Double.parseDouble(sysData[alarm
							.getShowNum() - 1]));
					if("equal".equals(alarm.getPoliceSysmbols())){
						if((data+"").equals(alarm.getPoliceValue())){
							strs[0] += alarm.getShowNum() + "|";// 告警序列号
							strs[1] += alarm.getPoliceLevel() + "|"; //告警级别
							strs[2] += alarm.getPoliceValue() + "|"; //告警值
						}
					}
					else if("include".equals(alarm.getPoliceSysmbols())){
						if((data+"").indexOf(alarm.getPoliceValue())!=-1){
							strs[0] += alarm.getShowNum() + "|";// 告警序列号
							strs[1] += alarm.getPoliceLevel() + "|"; //告警级别
							strs[2] += alarm.getPoliceValue() + "|"; //告警值
						}
					}
					else if("exclude".equals(alarm.getPoliceSysmbols())){
						if((data+"").indexOf(alarm.getPoliceValue())==-1){
							strs[0] += alarm.getShowNum() + "|";// 告警序列号
							strs[1] += alarm.getPoliceLevel() + "|"; //告警级别
							strs[2] += alarm.getPoliceValue() + "|"; //告警值
						}
					}
					else{
						double result = data - Double.parseDouble(alarm.getPoliceValue());
						if ((">".equals(alarm.getPoliceSysmbols()) && result > 0)
								|| ("<".equals(alarm.getPoliceSysmbols()) && result < 0)
								|| ("=".equals(alarm.getPoliceSysmbols()) && result == 0)
								|| (">=".equals(alarm.getPoliceSysmbols()) && result >= 0)
								|| ("<=".equals(alarm.getPoliceSysmbols()) && result <= 0)) {
							strs[0] += alarm.getShowNum() + "|";// 告警序列号
							strs[1] += alarm.getPoliceLevel() + "|"; // 告警级别
							strs[2] += alarm.getPoliceValue() + "|"; // 告警值
						}
					}
				}
			}
			for (int i = 0; i < strs.length; i++) {
				if (strs[i].length() > 0) {
					strs[i] = strs[i].substring(0, strs[i].length() - 1);
				}
			}
		}

		if (strs != null && "".equals(strs[0])) {
			strs = null;
		}

		return strs;
	}
	
/*	public static void main(String [] args) {
		Thread thread = new Thread(new PingThread("Ping Thread",10l,"10.0.6.11",2,100,3));
//		String name,Long sitInfoId,String socketIp,int socketPort,long gap,long outTime,long maxTimes
		thread.start();
		
	}*/
}
