package com.nms.server.thread.detecData;

import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import com.nms.server.common.Common;
import com.nms.server.common.Constants;
import com.nms.server.util.ExceptionPrintUtils;
import com.nms.server.util.FileUtils;

public class DetecDataResoveManagerThread implements Runnable {
	private Logger logger = Logger.getLogger(DetecDataResoveManagerThread.class);
	private int testNum = 0;// 尝试运行线程Constants.DETEC_DATA_RESOVE的次数
	public void run() {
		
		// 将线程运行程序，尽可能的catch捕获异常
//		Thread.currentThread().setName("监测数据解析管理线程");
		Thread.currentThread().setName("Monitoring Data Parsing Management Thread");

		try {
			// 如果内存中监测数据列表的数据超过指定值，则将数据存入硬盘（10万）
			int detectDataNum = Common.getAllDeteDataNum();
			if (detectDataNum >= Constants.MAX_DETECT_DATA_RESOVE_LIMIT_NUM) {
				logger.warn("Excesive monitoring data："+detectDataNum+"pieces， data written to the hard disk");
				saveDetectDataToDisk();
				return;
			}
			// dc监测数据入库模式，1：由web 主控控制入库，2：自己主动入库，3：智能模式（1和2结合），4，写入文件，定时上传web端
			if (Constants.DETECT_INSERT_MODE == 1) {
				logger.debug("DETECT_INSERT_MODE = " + Constants.DETECT_INSERT_MODE + ",不启动监测数据入库线程");
				return;
			} else if (Constants.DETECT_INSERT_MODE == 2) {
				// 2：自己主动入库
				logger.debug("DETECT_INSERT_MODE = " + Constants.DETECT_INSERT_MODE + ",主动入库");
				modeTwo();
			} else if (Constants.DETECT_INSERT_MODE == 3) {
				// 3：智能模式（1和2结合）
				long last = Common.getLastWebHandshake();
				long n = System.currentTimeMillis();
				if((n-last)/Constants.WEB_NOTICE_INSERT_DETECT_OVER_TIMES > Constants.DETEC_DATA_RESOLVE_PERIOD*1000){
					//超过两个监测周期都没有 web 握手信息
					logger.debug("超过两个周期都没有web握手信息，dc 主动入库,lastTime : " + new Date(last).toLocaleString());
					modeTwo();
				}else{
					logger.debug("等待web 通知监测数据入库，lastTime : " + new Date(last).toLocaleString());
				}
			} else if (Constants.DETECT_INSERT_MODE == 4) {
				// 4，写入文件，定时上传web端，暂不实现

			}
		} catch (Exception e) {
			logger.error("", e);
		} finally {
			logger.debug("执行结束");
		}
	}

	/**
	 * mode ：2 自己主动入库，查询 数据库 server_table 表共多少有效 dc ，根据自己排序，监测入库周期时间，计算
	 * 在哪一个时间段入库
	 */
	public void modeTwo() {
		// 测试数据库连接
		boolean runFlag = Common.isDbConnected();
		
		// - 检查线程运行状态 运行中无操作
		Future<?> future = Common.getFutureMap().get(Constants.DETEC_DATA_RESOVE);
		if (future != null && !future.isCancelled() && !future.isDone() && runFlag) { // 运行中
			runFlag = false;
			logger.info("监测数据解析执行线程 运行中 不再启动新解析线程");
		}
		/*
		 * 连续超过Constants.CHECK_WARNING_DATA_OVERRUN次数时，将数据存入硬盘中 否则 正常执行数据解析线程
		 */
		if (!runFlag) { // 判断并结束线程
			testNum = (testNum % Constants.CHECK_DETEC_DATA_OVERRUN);
			testNum++;
			if (testNum == Constants.CHECK_DETEC_DATA_OVERRUN) {
				if (Constants.FLAG_DETECT_DATA_SAVE_DISK_RESOVE == 1) {
					/*
					 * 连续多个周期仍未解析完成 说明list里存有大量的数据，则先将当前未解析的数据列表存入硬盘，
					 * 然后停掉解析线程，将正在解析的数据列表中的剩余数据存入硬盘
					 */
					logger.warn("Failed to create database connection,data written to hard disk");
					saveDetectDataToDisk();
				}
			}
			return;
		} else { // 重置计数器 程序继续执行
			testNum = 1;
		}

		// - 非升级操作判断
		if (Common.SERVER_UN_UPGRADE_FLAG) {

			// - 为空或空闲中 变更存储区 启动新解析线程
			// Common.chengeDeteDataFlag(); //变更数据存放集合
			// 2018年6月14日11:04:57 根据集合的大小自动切换取缓存数据最多的
			LinkedList<byte[]> dsbList = Common.getDeteDataList(); // 获取非存放状态的数据集合
			if (dsbList != null && dsbList.size() > 0) {
				logger.info("监测数据解析执行线程  空闲中 启动新解析线程");
				// -- 获取线程执行 需进行主动告警和邮件通知等相关操作，待考虑
				future = Common.dataResoveService.submit(new NewDetecDataResoveThread("Monitoring Data Parse Perform Thread",dsbList));
				// 注册
				Common.getFutureMap().put(Constants.DETEC_DATA_RESOVE, future);
			} else {
				logger.info("获取到的集合中数据数量为0，无需启动解析线程");
			}
		}
	}

	// 2013-2-19 hyx ：当监测数据量过大时，将数据先存放到硬盘，再定时入库（由单独的定时线程实现）
	public void saveDetectDataToDisk() {
		LinkedList<byte[]> notResolvingDetectDataList = Common.getNotResovlingDeteDataList(); // 获取未在解析的监测数据集合
		try {
			// 终止正在解析监测数据的线程，并将正在解析的list里未解析的数据存入硬盘
			Future<?> future = Common.getFutureMap().get(Constants.DETEC_DATA_RESOVE);
			if (future != null && !future.isCancelled() && !future.isDone()) { // 运行中
				future.cancel(true);
			}
			LinkedList<byte[]> detectDataList = Common.getDeteDataList(); // 获取非存放状态的数据集合(正在解析的list)
			saveByteToFile(detectDataList);

			// 将未在解析的list存放到硬盘上
			saveByteToFile(notResolvingDetectDataList);

		} catch (IndexOutOfBoundsException e) {
			logger.error("When there is too much monitoring data ,the data is stored on the hard disk exception",e);
		} catch (Exception e) {
			logger.error(ExceptionPrintUtils.printExceptionStack(e));
		}

	}

	private void saveByteToFile(LinkedList<byte[]> dataList) {
		String filePath = "";
		int dataSize = dataList.size();// 如果不按此时的size来操作，则list里的数据可能会一直在增加，就会一直循环下去？
		logger.info("监测数据过多，共" + dataSize + "条监测数据，等待存入硬盘:" + Constants.OVERRUN_DETEC_FILE_DIR + "/"
				+ Common.getDateDirName() + "/");
		try {
			for (int j = 0; j < dataSize; j++) {
				if (dataList.size() > 0) {
					byte[] data = dataList.get(0);// 因为每次循环都会dataList.remove(0);所以每次操作的都是第0条记录
					filePath = Constants.OVERRUN_DETEC_FILE_DIR + "/" + Common.getDateDirName() + "/"
							+ Calendar.getInstance().getTimeInMillis() + "_" + j + ".csv";
					FileUtils.wirteBytesToFile(data, filePath);
					dataList.remove(0);
				}
			}

		} catch (Exception e) {
			logger.error("When there is too much monitoring data ,the data is stored on the hard disk exception",e);
		}
	}

	public static void main(String[] args) {
		Common.scheduled.scheduleAtFixedRate(new DetecDataResoveManagerThread(), 0, 50, TimeUnit.SECONDS);
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.exit(0);
	}
}
