package com.nms.server.thread.monitor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CountDownLatch;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.snmp4j.mp.SnmpConstants;

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

public class SNMP4JThread implements Runnable{
	private Logger logger = Logger.getLogger(SNMP4JThread.class);
	private Long startTime = Calendar.getInstance().getTimeInMillis();
//	private SimpleDateFormat format = new SimpleDateFormat(Constants.COMMON_DATE_FORMAT);
	private String name;
	private int port = Constants.SNMP_CLIENT_PORT;
	private SetInfo info ;
	private String hostIp;
	private CountDownLatch downLatch;
	/**
	 * 构造方法 
	 * @param name		线程名称
	 * @param host		目标Ip
	 * @param info		监测设置信息
	 */
	public SNMP4JThread(String name, String hostIp, SetInfo info,Long startTime,CountDownLatch downLatch) {
		this.name = name;
		this.hostIp = hostIp;
		this.info = info;
		this.startTime = startTime;
		this.downLatch = downLatch;
	}
	public SNMP4JThread(String name, String hostIp, SetInfo info,Long startTime) {
		this.name = name;
		this.hostIp = hostIp;
		this.info = info;
		this.startTime = startTime;
		this.downLatch = downLatch;
	}
	/* 
	 * 通过SNMP4J GET获取
	 */
	public void run() {
		Thread.currentThread().setName(name + " " + hostIp);

		try {

			//- 通过 CloumnsMap 获取 oids
			logger.debug("json setinfo:"+JSONObject.fromObject(info).toString());
			Map<Integer,TableColumnsModel> CloumnsMap = Common.getTableMap().get(info.getCheckTypeName());
			logger.debug("table CloumnsMap:"+CloumnsMap.size());
			List<String> oidList = new LinkedList<String>();
			if(CloumnsMap!=null && CloumnsMap.size()>0){
				Iterator<Entry<Integer, TableColumnsModel>> entryIte = CloumnsMap.entrySet().iterator();
				while (entryIte.hasNext()) {
					Entry<Integer, TableColumnsModel> cloumnEntry = (Entry<Integer, TableColumnsModel>) entryIte.next();
					String oid = cloumnEntry.getValue().getOid();
					if (StringUtils.isNotEmpty(oid)){
						oidList.add(oid);
					}
				}
			}
			logger.debug("table CloumnsMap:"+Arrays.toString(oidList.toArray()));
			
		
			int version = Common.getSnmpVerByUUID(Common.getIpSeqIdMap().get(hostIp));
		
			//-- 执行和解析 即获取详细数据
			int retries = info.getCheckMaxTimes()==null?3:info.getCheckMaxTimes().intValue();
			int timeout = info.getCheckOutTime() == null?10000:info.getCheckOutTime().intValue()*1000;
			int state = -1;

			List<Map<String, String>> snmpDatas = new LinkedList<Map<String, String>>() ;
			StringBuffer stateInfo = new StringBuffer();
			List<List<String>> snmpDatasList = null;
			try {
				String rootOid = Common.getInsertTable().get(info.getCheckTypeName()).getOid();
				logger.debug("rootOid "+rootOid);
				snmpDatasList = resoveVersion(snmpDatas,oidList,rootOid,version,retries,timeout,stateInfo);
				state = 1;
			} catch (Exception e) {
				state = -1;
				stateInfo.append(e.getMessage());
				logger.error((version == SnmpConstants.version3?"version3":"version2c")+" GET failure", e);
			}
		
			//- 监测数据集合
			List<String> pubDatas = new ArrayList<String>(); // 拼写数据格式
		
			//- DetecDatas 拼写 Header
			pubDatas.add(Common.getIpSeqIdMap().get(hostIp)+"");// uuid，
			pubDatas.add(info.getId() + "");// 监测设置ID，
			pubDatas.add(info.getCheckTypeName());// 监测类别，
			pubDatas.add(info.getProcessIden());// 进程名称（检查类别设置名称），
			pubDatas.add(startTime + "");// 监测服务启动时间，
			pubDatas.add(timeout+"");// 检测时延（秒）
			//- 当前检测时间
			Calendar checkTime = Calendar.getInstance();
			pubDatas.add(checkTime.getTimeInMillis() + "");// 本次检测时间，
			pubDatas.add(retries + "");// 尝试次数，
			//- 下次检测时间
			Calendar nextTime = Calendar.getInstance();
			nextTime.add(Calendar.MINUTE, info.getCheckGap().intValue());
			pubDatas.add(nextTime.getTimeInMillis() + "");// 下次计划监测时间，



			//- DetecDatas 拼写 Body
			List<List<String>> pubDatasList = new ArrayList<List<String>>();
			if(state != -1){
				pubDatasList = datasBody(retries,stateInfo.toString(),state,snmpDatasList);
			}
			
			pubDatas.add(state+""); // 执行状态
			pubDatas.add(stateInfo.toString()); // 状态信息（描述信息），
			pubDatas.add(""); // 性能数据，
			
			if(pubDatasList.size()>0){
				pubDatasList.add(0,Arrays.asList(new String[]{"details",pubDatasList.size()+""}));
			}
			pubDatasList.add(0,pubDatas);
			
			//- 存入缓存
			if(pubDatasList!=null && pubDatasList.size()>0){
				try {
					Common.addDeteData(CSVUtils.csvFilePrinter(pubDatasList, Constants.COMMON_TEXT_CODING));
					logger.debug("监测数据以 CSV格式 保存完成");
				} catch (Exception e) {
					logger.error("Monitoring data to save exceptions in CSV format", e);
				}
			}

		} catch (Exception e) {
			String[] alarm = Common.alarmExceptionInfo(info.getId(), hostIp, info.getCheckTypeName(), info.getProcessIden(), startTime, 1,Constants.DETECTION_INFO_ALARM_WRONG, e.getMessage());
			Common.addAlarmData(alarm);
			logger.error("Program unknown error ", e);
		}finally{
			if(downLatch != null){
				downLatch.countDown();
			}
		}
	}
	
	private List<List<String>> resoveVersion(List<Map<String, String>> datasMapList,List<String> oids,String oid,int version ,int retries,int timeout,StringBuffer stateInfo) throws Exception{

		List<List<String>> snmpDatasList = new LinkedList<List<String>>();
		logger.debug("SNMP4J 》》》》"+oid+" "+hostIp+" "+port+" "+Constants.SNMP_COMMUNITY+" "+retries+" "+timeout+" "+ version);
		
		
		SNMP4JUtils.snmpTree(datasMapList, oids,oid, hostIp, port+"", Constants.SNMP_COMMUNITY,retries,timeout,version,info.getCheckTypeName());
		logger.debug("datasMapList size "+datasMapList.size());
		//- 获取表字段结构
		Map<Integer,TableColumnsModel> cloumnsList = Common.getTableMap().get(info.getCheckTypeName());
		logger.debug(info.getCheckTypeName()+" cloumnsList size "+cloumnsList.size());
		
		//- 存值
		if(cloumnsList!=null && cloumnsList.size() > 0 && datasMapList!=null && datasMapList.size()>0){
			for(Map<String, String> datasMap : datasMapList){
				List<String> snmpDatas = new LinkedList<String>();
				for (int i = 1; i <= cloumnsList.size(); i++) {
					TableColumnsModel cloumn = cloumnsList.get(i);
					String oid0 = cloumn.getOid();
					snmpDatas.add(datasMap.get(oid0));
//					if(oid0.equals(oid+".1")){
//						stateInfo.append(oid0+":"+datasMap.get(oid0)+"\n");
//					}
				}
				snmpDatasList.add(snmpDatas);
			}
		}
		return snmpDatasList;
	}
	
	private List<List<String>> datasBody(int times,String stateInfo,int state,List<List<String>> snmpDatas2)throws Exception{

//		List<List<String>> pubDatasList = new LinkedList<List<String>>();

		logger.debug("监测数据主体拼写 state "+state+" size"+(snmpDatas2==null ? -1 :snmpDatas2.size()));

		if(snmpDatas2!=null && snmpDatas2.size()!=0){
		for (List<String> snmpDatas : snmpDatas2) {
//			List<String> pubDatas0 = new LinkedList<String>();
//		执行状态是否成功是否正常,	第三方脚本监测任务执行结果（用于报警 -1执行失败 0不正常，1正常）-1时可保留后续数据为空，但是数据个数需要对应
				// -- 执行状态是否成功，记录的状态是否正常（用于报警），
				String [] datas0 =  new String[0];
				datas0 = snmpDatas.toArray(datas0);
//			logger.debug("snmpDatas>>>> "+Arrays.toString(snmpDatas.toArray(datas0)));
//			logger.debug("Common.getAlarmInfoMap()>>>> "+Common.getAlarmInfoMap().size());
				String[] pArray = Common.getAlarmState(Common.getAlarmInfoMap().get(info.getId()+""), datas0);
//			logger.debug("pArray>>>> "+Arrays.toString(pArray));
				if (pArray == null || pArray.length==0) {
					snmpDatas.add(0, "");
					snmpDatas.add(1, "");
					snmpDatas.add(2, "");
				} else {
					state = 0;
					List<AlarmInfo> aiList = Common.getAlarmInfoMap().get(info.getId()+"");
					snmpDatas.add(0, pArray == null ? "" : pArray[0]);
					snmpDatas.add(1, pArray == null ? "" : pArray[1]);
					snmpDatas.add(2, pArray == null ? "" : pArray[2]);
					stateInfo+=Common.getStateInfo(info.getCheckTypeName(),Common.getAlarmInfoMap().get(info.getId()+""), datas0);
				}
//			logger.debug("pArray>>>> "+Arrays.toString(pubDatas0.toArray()));
		}
		}
		return snmpDatas2;
		
	}
	
	public static void main(String [] args) {
		
	}
}
