package com.nms.server.thread.monitor.util;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

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


/**
 * 监测数据结果整理类
 * 根据监测设置信息整理监测信息，并做告警处理
 */
public class MonitorUtil{
	private static Logger logger = Logger.getLogger(MonitorUtil.class);

	public static final String SEPARATOR = "@#@";
	
	
	/**
	 * 
	 * TODO 
	 * @author Administrator Jun 20, 2013
	 * @version 1.0 
	 * @param ip
	 * @param setInfo:监测设置
	 * @param startTime:该监测启动的时间
	 * @param alarmInfos：当前监测设置的告警设置信息,data_police_relation表
	 * @param detectInfo:监测数据相关详细信息
	 */
	public static void createMonitorData(String ip, SetInfo setInfo, Long startTime, List<AlarmInfo> alarmInfos,DetectInfo detectInfo) {
		
		Date writeDate = new Date();
		int testTimes = detectInfo.getTestTimes();	//尝试次数
		
		try {
			/* 
			 * 2013-4-11 数据顺序调整如下:
			 * 总数据：本机IP,监测设置ID,监测类别,进程名称（监测类别设置名称）,监测服务启动时间,检测时延（秒）,本次检测时间,尝试次数,下次计划监测时间,
			 *       执行状态是否成功是否正常（用于报警:-1执行失败，0不正常，1正常）,状态信息（描述信息）,性能数据
			 * 详细信息：details,详细信息条数（要入到对应的监测类别信息表的数据条数）
			 *         告警列序号,告警级别,告警值,监测具体数据信息（多列）,,,,
			 */
			
			String checkDelayTime = getCheckDelayTime(detectInfo.getCheckTime());// 检测时延
			
			// ------- 数据状态（告警）和详细监测数据组织
			int totalStatus = Constants.DETECTION_INFO_DETEC_RIGHT;
			int totalAlarmLevel = 99;//似乎没用？
			StringBuffer functionSb = new StringBuffer();
			List<String[]> detailDataList = new LinkedList<String[]>();
			if (detectInfo == null || detectInfo.getDetailDatas() == null || detectInfo.getDetailDatas().size() == 0) {// 执行失败
				totalStatus = Constants.DETECTION_INFO_DETEC_ERROR;//监测信息异常
				// detectInfo不为空，即无具体的详细数据，有描述信息（目前是针对进程与系统时间）
				if (detectInfo != null){
					// 如果是进程监测, 找不到进程或找到多个进程时，告警；如果时间差监测，获取DC系统时间失败，告警
					
					//因为肯定会有一条监测数据入库，如果再入告警数据，就重复了？
//					String[] alarm = Common.alarmExceptionInfo(setInfo.getId(), ip, setInfo.getCheckTypeName(), "", startTime, 1,Constants.DETECTION_INFO_ALARM_WRONG, detectInfo.getDescInfo());
//					Common.addAlarmData(alarm);//所有异常监测，都发主动告警
				}
				
				logger.info("预设监测 setId: " + setInfo.getId() + " > " + setInfo.getCheckTypeName() + "_"	+ setInfo.getProcessIden() + "，获取数据失败");
			}else {// 即正常生成详细监测数据
				
				List<String> detailDatas = detectInfo.getDetailDatas();
				for(int i=0; i<detailDatas.size(); i++){
					String[] detailData = detailDatas.get(i).split(SEPARATOR);
					int index = 0;
					String[] dataArr = new String[3 + detailData.length];//3：告警数据占用3列
					// 与报警字段值比较是否状态正常
					String[] alarmArr = getAlarmState(detailData,alarmInfos);
					if (alarmArr != null && "".equals(alarmArr[0])) {// 记录的状态正常
						dataArr[index++] = "";// 告警列序号
						dataArr[index++] = "";// 告警级别
						dataArr[index++] = "";// 告警值
					} else {// 记录的状态不正常
						totalStatus = Constants.DETECTION_INFO_DETEC_WRONG;//监测信息异常
						dataArr[index++] = alarmArr[0];// 告警列序号
						dataArr[index++] = alarmArr[1];// 告警级别
						dataArr[index++] = alarmArr[2];// 告警值
						
						if(!"".equals(alarmArr[4]) && totalAlarmLevel > Integer.parseInt(alarmArr[4])){// 将更高的告警级别赋给总告警级别
							totalAlarmLevel = Integer.parseInt(alarmArr[4]);
						}
					}
					if(detailDatas.size()>1 && alarmArr[3].length()>0){
						functionSb.append("【" + detailData[0] + "】 " + alarmArr[3] + "</br>");// 组织性能数据
					}else{
						functionSb.append(alarmArr[3]);// 组织性能数据
					}
					for (int j = 0; j < detailData.length; j++) {// 监测具体数据信息
						dataArr[index + j] = detailData[j];
					}
					
					detailDataList.add(dataArr);
				}
			}
			
			// ------- 主动告警
//				String totalAlarmInfo = null;
//				if(totalStatus == Constants.DETECTION_INFO_DETEC_RIGHT){
				// 本次数据正常，看原本的状态：若是告警状态，则发送恢复通知；若是正常状态，则不变
//					if(alarmState){
//						totalAlarmInfo = "【数据状态恢复正常】</br>" + functionSb.toString();
//					}
//					alarmState = false;
//					alarmTimes = 0;
//				}else if(totalStatus == Constants.DETECTION_INFO_DETEC_WRONG){
//					alarmTimes ++;
//					if(!alarmState){// 本次数据不正常，看原本的状态：若是正常状态，则发送告警
//						totalAlarmInfo = "【数据状态异常，超过告警值】</br>" + functionSb.toString();
//					}
//					alarmState = true;
//				}
			
//				if(totalAlarmInfo!=null){
//					String[] alarm = Common.alarmExceptionInfo(setInfo.getId(), pingIp, setInfo.getCheckTypeName(), "", startTime, 1,Constants.DETECTION_INFO_ALARM_WRONG, totalAlarmInfo);
//					Common.addAlarmData(alarm);
//				}
			
			// ------- 总监测数据组织
			int index = 0;
			String[] totalData = new String[12];
			totalData[index++] = Common.getUUIDByIp(ip)+"";// UUID
			totalData[index++] = setInfo.getId() + "";// 监测设置ID
			totalData[index++] = setInfo.getCheckTypeName();// 监测类别
			totalData[index++] = setInfo.getProcessIden();// 进程名称
			totalData[index++] = startTime+"";// 监测服务启动时间
			totalData[index++] = checkDelayTime;// 检测时延（秒）
			totalData[index++] = writeDate.getTime() + "";// 本次检测时间
			totalData[index++] = testTimes + "";// 尝试次数
			totalData[index++] = getNextCheckTime(writeDate,setInfo.getCheckGap().intValue());// 下次计划监测时间
			totalData[index++] = totalStatus + "";// 执行状态是否成功是否正常：state
			totalData[index++] = (detectInfo == null ? "" : detectInfo.getDescInfo());// 状态信息（描述信息）：失败的原因等？
			if(Constants.DETEC_NMSC_STR.toLowerCase().equals(setInfo.getCheckTypeName().toLowerCase())){//如果是握手监测，则性能数据和状态信息一样，而不是取告警值的信息
				totalData[index++] = (detectInfo == null ? "" : detectInfo.getDescInfo());// 性能数据
			}else {
				totalData[index++] = StringUtils.isBlank(functionSb.toString())?(detectInfo == null ? "" : detectInfo.getDescInfo()):functionSb.toString();// 性能数据，就是performace_data字段
			}
			
			List<String[]> dataList = new LinkedList<String[]>();
			// 总数据
			dataList.add(totalData);
			// 详细信息
			dataList.add(new String[]{"details", detailDataList.size() + ""});// details(解析标识),详细信息条数
			dataList.addAll(detailDataList);// 具体的详细数据
			
			// 特殊数据定制(目前是针对系统信息监测systeminfo) add by zg 0604(DC未使用，须详细测试)
			if (detectInfo!=null && detectInfo.getRelatedDatas() != null) {//网卡和硬盘详细信息
				Set<Map.Entry<String, List<String[]>>> set = detectInfo.getRelatedDatas().entrySet();
				for(Map.Entry<String, List<String[]>> entry : set){
					dataList.add(new String[]{entry.getKey(), entry.getValue().size() + ""});// 解析标识, 行数（当前解析标识指定的类型有多少条数据）
					dataList.addAll(entry.getValue());// 多条数据
				}
			}
			
			for(String[] val : dataList){
				logger.debug(Arrays.toString(val));
			}
			
			//- 存入缓存
			try {
				Common.addDeteData(CSVUtils.csvBytesPrinter1(dataList, Constants.COMMON_TEXT_CODING));
				logger.debug("监测数据以 CSV格式 保存完成");
			} catch (Exception e) {
				logger.error("Monitoring data to save exceptions in CSV format", e);
			}

		} catch (Exception e) {
			logger.error("Error generating monitoring data" ,e);
		}
		
	}
	
	// 获得当前的报警设置信息，与相应字段值比较:sysData是按showNum排列的
	private static String[] getAlarmState(String[] sysData,List<AlarmInfo> alarmInfos){
		// strs数组数据依次为：告警序列号、告警级别、告警值、性能数据、本次最高告警级别
		String[] strs = new String[]{"", "", "", "", ""};
		if(alarmInfos==null){
			return strs;
		}
		int maxAlarmLevel = 99;
		for (AlarmInfo alarm : alarmInfos) {
			if (sysData.length < alarm.getShowNum()) {// 得到的数据个数和告警列数比较，如果设置的告警字段的showNum比总的告警信息字段数还大，则此告警设置不对
				continue;
			}
			String data = sysData[alarm.getShowNum() - 1];
			boolean alarmFlag = false;
			if ("equals".equalsIgnoreCase(alarm.getPoliceSysmbols())) {//相同
				if(data.equals(alarm.getPoliceValue())){
					alarmFlag = true;
				}
			} else if ("include".equalsIgnoreCase(alarm.getPoliceSysmbols())) {//包含告警值内容
				if(data.contains(alarm.getPoliceValue())){
					alarmFlag = true;
				}
			} else if ("exclude".equalsIgnoreCase(alarm.getPoliceSysmbols())) {//不包含告警值内容
				if(!data.contains(alarm.getPoliceValue())){
					alarmFlag = true;
				}
			} else {
				double result = Double.parseDouble(data) - Double.parseDouble(alarm.getPoliceValue());//一定就是数字吗？web界面貌似没做数字限定
				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) ) {
					alarmFlag = true;
				}
			}
			String sysmbol = getAlarmSymbol(alarm.getPoliceSysmbols(), alarmFlag);
			if(alarmFlag){
				strs[0] += alarm.getShowNum() + "|";// 告警序列号
				strs[1] += alarm.getPoliceLevel() + "|"; //告警级别
				strs[2] += alarm.getPoliceValue() + "|"; //告警值
				//性能信息
//				strs[3] += alarm.getFiledCommonts()
//						+ sysData[alarm.getShowNum() - 1]
//						+ alarm.getPoliceUnit() + sysmbol + "告警值"
//						+ alarm.getPoliceValue()
//						+ alarm.getPoliceUnit() + "  不正常；";
				strs[3] += alarm.getFiledCommonts()
						+ sysData[alarm.getShowNum() - 1]
						+ alarm.getPoliceUnit() + sysmbol + "i18n_server.MonitorUtil.warnValue_n81i"
						+ alarm.getPoliceValue()
						+ alarm.getPoliceUnit() + "  i18n_server.MonitorUtil.abnormal_n81i；";
				
				//2011-09-29 添加了连续几次达到告警值后主动告警，恢复正常后发送恢复信息
				//2013-03-26 添加了告警状态控制是否立刻主动告警，如果已经告警则后期不发送告警信息。
				//alarmHandler(alarm, strs[3]);
				
				if (maxAlarmLevel  > alarm.getPoliceLevel()) {// 保留本次最高告警级别，值越小级别越高
					maxAlarmLevel = alarm.getPoliceLevel();
				}
				
			}else{
				// 性能信息
//				strs[3] += alarm.getFiledCommonts()
//						+ sysData[alarm.getShowNum() - 1]
//								+ alarm.getPoliceUnit() + sysmbol + "告警值"
//								+ alarm.getPoliceValue()
//								+ alarm.getPoliceUnit() + "  正常；";
				strs[3] += alarm.getFiledCommonts()
						+ sysData[alarm.getShowNum() - 1]
						+ alarm.getPoliceUnit() + sysmbol + "i18n_server.MonitorUtil.warnValue_n81i"
						+ alarm.getPoliceValue()
						+ alarm.getPoliceUnit() + "  i18n_server.MonitorUtil.normal_n81i；";
				//对发送告警信息后，恢复正常的信息(为保证告警成对)
				//2013-03-26 当告警恢复后发送恢复告警信息。
				//alarmRecovery(alarm, strs[3]);
				
			}

		}//for end
		for (int i = 0; i < strs.length-1; i++) {
			if (strs[i].length() > 0) {
				strs[i] = strs[i].substring(0, strs[i].length() - 1);
			}
		}
		strs[strs.length-1] = maxAlarmLevel + "";// 本次告警最高级别
		return strs;
	}
	
	private static String getAlarmSymbol(String oldSymbol, boolean alarmFlag){
		String symbol = "";
		if(alarmFlag){
//			if(">".equals(oldSymbol)){
//				symbol = "大于";
//			}else if(">=".equals(oldSymbol)){
//				symbol = "超过";
//			}else if("<".equals(oldSymbol)){
//				symbol = "小于";
//			}else if("<=".equals(oldSymbol)){
//				symbol = "未超过";
//			}else if("=".equals(oldSymbol)){
//				symbol = "等于";
//			}else{
//				symbol = oldSymbol;
//			}
			if(">".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.gt_n81i";
			}else if(">=".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.out_n81i";
			}else if("<".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.lt_n81i";
			}else if("<=".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.in_n81i";
			}else if("=".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.eq_n81i";
			}else{
				symbol = oldSymbol;
			}
		}else{
//			if(">".equals(oldSymbol)){
//				symbol = "未超过";
//			}else if(">=".equals(oldSymbol)){
//				symbol = "小于";
//			}else if("<".equals(oldSymbol)){
//				symbol = "超过";
//			}else if("<=".equals(oldSymbol)){
//				symbol = "大于";
//			}else if("=".equals(oldSymbol)){
//				symbol = "不等于";
			if(">".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.in_n81i";
			}else if(">=".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.lt_n81i";
			}else if("<".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.out_n81i";
			}else if("<=".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.gt_n81i";
			}else if("=".equals(oldSymbol)){
				symbol = "i18n_server.MonitorUtil.notEquels_n81i";
			}else if("equals".equalsIgnoreCase(oldSymbol)){
				symbol = "not equals";
			}else if("include".equalsIgnoreCase(oldSymbol)){
				symbol = "exclude";
			}else if("exclude".equalsIgnoreCase(oldSymbol)){
				symbol = "include";
			}
		}
		return symbol;
	}
	
    // 检测时延（秒）
    private static String getCheckDelayTime(Long checkTime){
    	long val = System.currentTimeMillis() - checkTime;
    	return val/1000 + "";
    }
    
    // 下一次检测时间
    private static String getNextCheckTime(Date now,int gap){
    	Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		cal.add(Calendar.MINUTE, gap);
    	return cal.getTimeInMillis() + "";
    }
}
