package com.nms.server.thread.dataCollect;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
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.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.nms.server.bean.DetectInfo;
import com.nms.server.bean.NodeModel;
import com.nms.server.bean.SetInfo;
import com.nms.server.common.Common;
import com.nms.server.common.Constants;
import com.nms.server.dao.CommonDao;
import com.nms.server.service.CommonService;
import com.nms.server.thread.monitor.util.MonitorUtil;
import com.nms.server.util.BoneCPPool;
import com.nms.server.util.ExceptionPrintUtils;

//监测数据主动收集管理线程
public class DataCollectManagerThread implements Runnable{
	private Logger logger = Logger.getLogger(DataCollectManagerThread.class);
	private long startTime = Calendar.getInstance().getTimeInMillis();
	
	public void run() {
//		Thread.currentThread().setName("数据（监测数据、任务结果、回传文件）收集管理线程");
		Thread.currentThread().setName("Data (Monitoring data, Task results, Return files) To Collect Management Threads");
		CommonDao dao = null;
		try {
			dao = new CommonDao();
			CommonService service = new CommonService(dao);
			
			//- 非升级操作判断
			if(Common.SERVER_UN_UPGRADE_FLAG){//---起什么作用？
				//循环向自己管辖的Client端，收集数据
				List<String> ipList = new LinkedList<String>();
				ipList = service.getAllComputerIp();//当前DC管理范围内+有效节点+有效节点组+服务器节点
				int j=0;
				String key="";
				/*
				 * 2013-7-29 hyx
				 * 获得所有握手监测的节点信息，若数据收集的节点在握手监测节点范围内，则收集数据的同时进行握手监测（传递true），确认一个，从握手监测中删除一个节点，最后未握手的节点则不在数据收集范围内（这种情况不应该存在）
				 */
				Map<String,SetInfo> nodeMap = getNmsclientNodeList(service);//ip:setinfo	
				//20160901 hyx 增加此代码的原因是：数据收集管理线程运行一段时间后，会出现获取数据库连接一直阻塞的情况，而此时其它线程是可以正常获取数据库连接的，一个原因可能是之前没有dao=null；另一个原因可能是，之后的数据收集及超时操作，可能由于各种原因，如异常节点较多，导致连接最后没能正常关闭，所以在连接不使用的时候，尽早关闭
				try {
					if(dao!=null){
						dao.close();
						dao=null;
					}
				} catch (Exception e)
				{
					logger.error("Data collection management thread early closing database connection exception", e);
				}

				boolean nmsclientFlag = false;//节点是否进行握手监测的标识
				Map<String,Future<?>> ipFutureMap = new HashMap<String,Future<?>>();
				int ipNum = ipList.size();
				for(int i=0;i<ipNum;i++) {//最多启动几个线程,之后呢？？其它未收集的怎么办？？应该超过池里的线程之后，会排队吧，等有空闲的了，再开启线程？？
					String ip = ipList.get(i);
					if(ip!= null  && !Common.noDetectDataNodeList.contains(ip)){
						//- 检查线程运行状态  运行中无操作
						key = Constants.DATA_COLLECT+":"+ip;
						Future<?> future = Common.getFutureMap().get(key);
						if(future != null && !future.isCancelled() && !future.isDone()){	//运行中
							logger.info("对"+ip+"的数据（监测数据、任务结果、回传文件）收集执行线程 运行中 不再启动新收集线程");
							continue;
						}
						SetInfo setInfo = nodeMap.get(ip);
						if(nodeMap.containsKey(ip)) {//当前节点需要进行握手监测
							nmsclientFlag = true;
//							future = Common.service.submit(new DataCollectThread("数据收集执行线程:>"+ip,ip,Constants.SSL_CLIENT_PORT,nmsclientFlag,setInfo,startTime));
							future = Common.service.submit(new DataCollectThread("Data Collection Execution Thread:>"+ip,ip,Constants.SSL_CLIENT_PORT,nmsclientFlag,setInfo,startTime));
							ipFutureMap.put(ip, future);
						}else {//当前节点不需要进行握手监测
							nmsclientFlag = false;
							future = Common.service.submit(new DataCollectThread("Data Collection Execution Thread（No need shakehand）:>"+ip,ip,Constants.SSL_CLIENT_PORT,nmsclientFlag,setInfo,startTime));
						}
						
						//注册
						Common.getFutureMap().put(key, future);
						j++;
					}
				}
				logger.info("*******************************************共"+ipNum+"个节点(实际收集"+(ipNum-Common.noDetectDataNodeList.size())+"个)，数据（监测数据、任务结果、回传文件）收集执行线程启动个数："+j);
				
				//握手监测信息
				Iterator ite = ipFutureMap.entrySet().iterator();
				
				Thread.sleep(Constants.DATA_COLLECT_DAILY*1000);//默认2分钟（socket超时20多秒，ping失败13秒，ssh失败20多秒，共计1分钟左右，再加上数据收集的时间，2分钟满足）
				for(;ite.hasNext();) {
					Entry en = (Entry)ite.next();
					String ip = (String)en.getKey();
					if(Common.noDetectDataNodeList.contains(ip)){
						continue;
					}
					SetInfo setInfo = nodeMap.get(ip);
					Object rlt = null;
					Future<?> futureTmp = (Future<?>)en.getValue();
					try {
						logger.info("对节点"+ip+"的数据收集及握手监测 等待中。。。");
						rlt = futureTmp.get(2, TimeUnit.MILLISECONDS);//如果在执行时间内没有获取结果，则直接返回null
						
					} catch (TimeoutException e) {
						logger.debug("对 "+ip+" 的数据收集超时（"+Constants.DATA_COLLECT_DAILY+"秒）");
						String keyTmp = Constants.DATA_COLLECT+":"+ip;
						Common.cancelRunnableAtOnce(keyTmp);//此处很重要，需要取消线程的执行，如果取消失败，或者不及时，会生成两条握手监测数据（收集线程一条，管理线程一条）
 					}finally{
 						DetectInfo  detectInfo = rlt!=null?((DetectInfo)rlt):(new DetectInfo());
						detectInfo.setTestTimes(1);//尝试次数
						detectInfo.setCheckTime(System.currentTimeMillis());//监测时间
						try{
							/**
							 * -- 监测数据描述信息非空（web界面的状态信息），才生成监测数据:
							 *    1、监测数据为空可能是收集线程超时导致ping或者ssh未执行完毕，未生成描述信息
							 *    2、此时web端进行超周期设置时，过滤掉异常的节点，异常节点的异常信息还是采用之前周期的-此功能 20160906 web端还未实现						     
							 */
							if(StringUtils.isBlank(detectInfo.getDescInfo())){
								detectInfo.setDescInfo(Constants.NO_DETECTDATA_STATUS_INFO);
								logger.info("对节点"+ip+"的数据集超时，未获取监测数据");
								MonitorUtil.createMonitorData(ip, setInfo, startTime, Common.getAlarmInfoMap().get(setInfo.getId()+ ""), detectInfo);
								if(!Common.noDetectDataNodeList.contains(ip)){
									Common.addNoDeteDataNode(ip);
									logger.info("对节点"+ip+"的数据集超时，将节点加入无监测数据列表，由无监测数据收集线程进行收集");
								}
							}
						} catch (Exception ex) {
							logger.error(ExceptionPrintUtils.printExceptionStack(ex));
							String processIden = setInfo.getProcessIden()==null ? "" : setInfo.getProcessIden();
							String[] alarm = Common.alarmExceptionInfo(setInfo.getId(), ip, Constants.DETEC_NMSC_STR,processIden , startTime, 1,Constants.DETECTION_INFO_ALARM_WRONG, ex.getMessage());
							Common.addAlarmData(alarm);
						}
 					}
 					
					logger.info("对节点"+ip+"的数据收集及握手监测 完毕"+Constants.DATA_COLLECT_DAILY);
					
				}
			}
		} catch (Exception e) {
			logger.error("Monitoring data collection management threads run abnormity",e);
		} finally {
			if(dao!=null){
				dao.close();
				dao=null;
			}
			logger.debug("执行结束");
		}
	}

	//获得进行握手监测的所有节点：握手的条件：到首次监测时间+节点有效（节点组有效）+监测设置内的节点+监测设置有效
	private Map<String,SetInfo> getNmsclientNodeList(CommonService service){
		List<NodeModel> nodeList = new ArrayList<NodeModel>();
		Map<String,SetInfo> nodeMap = new HashMap<String,SetInfo>();
		try
		{
			if(Constants.FLAG_NMSC==1){
				List<SetInfo> setList =  service.getDrivingSetInfo(Constants.DETEC_NMSC_STR);//获得checkType类型的所有监测设置
				if(setList!=null && setList.size()>0){
					List<NodeModel> nodeTmpList = new ArrayList<NodeModel>();
					for (Iterator setIte = setList.iterator(); setIte.hasNext();) {
						SetInfo setInfo = (SetInfo) setIte.next();
						//如果首次监测时间没到，则不用查询节点
						//- 计算启动后第一次检测时间 默认即时启动
						long initialDelay = 0l;
						if(setInfo.getPlanCheckTime()!=null){
							initialDelay = setInfo.getPlanCheckTime().longValue() - (new Date().getTime());
							initialDelay = initialDelay > 0l ? initialDelay : 0l;
						}
						
						if(initialDelay<=0) {//到首次监测时间了，查询进行握手监测的节点		
							//节点可能存在重复的情况
							nodeTmpList = service.getNodeModelListBySetInfo(setInfo);
							nodeList.addAll(nodeTmpList);
						}else {
							logger.info("握手监测，未到首次监测时间，距离首次监测时间还有："+initialDelay/1000/60+"分钟");
						}
						
						for(NodeModel node:nodeTmpList) {
							nodeMap.put(node.getNodeIp(), setInfo);
						}
					}					
					
					logger.debug("本次服务器握手监测的节点数为："+nodeMap.size());
				}
			}else {
				logger.info("未开启握手监测标识");
			}
		} catch (Exception e)
		{
			logger.error("Obtaining a node exception for handshake monitoring", e);
		}
		
		
		return nodeMap;
	}
	
	public static void main(String[] args) throws Exception {
		
		CommonDao dao = null;
		ScheduledFuture<?> future = null;
		Object rlt = null;
		try
		{
			Thread.sleep(3000);
			BoneCPPool.initPool();
			Thread.sleep(3000);
//			DataCollectManagerThread runThread = new DataCollectManagerThread();
//			Thread thread = new Thread(runThread);
//			thread.start();
			dao = new CommonDao();
			CommonService service = new CommonService(dao);
			
			// 初始化自身信息(失败情况下会由Web唤醒)
			if(!service.initServerParams()){
				return;
			}
			
			
			future = Common.scheduled.scheduleWithFixedDelay(new DataCollectManagerThread(), 0, 300, TimeUnit.SECONDS);
			Common.registRunnable(Constants.DATA_COLLECT_MANAGER, future);
			Thread.sleep(7000);
			System.out.println(future==null?"null3":future.isDone());
			System.out.println(future==null?"null4":future.isCancelled());
			System.out.println("***************=====结束了？");
			rlt = future.get();
			Thread.sleep(5000);
//          future.cancel(true);
			//发生异常未捕捉后：
			System.out.println("future="+future);
			System.out.println(future==null?"null55":future.isDone());
			System.out.println(future==null?"null55":future.isCancelled());
			System.out.println("==============结束了？55");
			System.out.println("rlt="+rlt);
			
			
			
		} catch (Exception e)
		{
			System.out.println("catch*******************");
			System.out.println("eeeeeeeefuture="+future);
			System.out.println(future==null?"eeeeeeeeenull55":future.isDone());
			System.out.println(future==null?"eeeeeeeeeenull55":future.isCancelled());
			System.out.println("eeeeeeeeee==============结束了？55");
			System.out.println("eeeeeeeerlt="+rlt);
			
			System.out.println("数据收集线程是否注册-catch-done"+Common.getFutureMap().get(Constants.DATA_COLLECT_MANAGER).isDone());
			System.out.println("数据收集线程是否注册-catch-cancel"+Common.getFutureMap().get(Constants.DATA_COLLECT_MANAGER).isCancelled());
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			if(dao!=null){
				dao.close();
				dao=null;
			}
			System.out.println("finally**********************************");
//			Common.scheduled.shutdown();//关闭线程池
//			System.out.println(Common.scheduled.isTerminated());//?????????
//			System.out.println(Common.scheduled.isShutdown());
			System.out.println("数据收集线程是否注册-catch-done"+Common.getFutureMap().get(Constants.DATA_COLLECT_MANAGER).isDone());
			System.out.println("数据收集线程是否注册-catch-cancel"+Common.getFutureMap().get(Constants.DATA_COLLECT_MANAGER).isCancelled());
//			System.out.println("关闭线程池");
			
		}
	}
}
