package com.nms.server.thread;

import java.io.File;
import java.sql.SQLException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import com.nms.server.bean.ServerTable;
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.service.ThreadService;
import com.nms.server.service.UpgradeService;
import com.nms.server.snmp.trap.TrapServer;
import com.nms.server.thread.alarmData.AlarmDataResoveManagerThread;
import com.nms.server.thread.change.ChangeManagerThread;
import com.nms.server.thread.dataCollect.DataCollectManagerThread;
import com.nms.server.thread.dataCollect.NoDetectDataCollectManagerThread;
import com.nms.server.thread.dataCollect.NonRltTaskResultCollectManagerThread;
import com.nms.server.thread.deleteFiles.DeleteFilesManagerThread;
import com.nms.server.thread.detecData.DetecDataResoveManagerThread;
import com.nms.server.thread.detectDataHandler.DataInsertManagerThread;
import com.nms.server.thread.detectDataHandler.DataResolveThread;
import com.nms.server.thread.detectDataHandler.DetectInfoInsertThread;
import com.nms.server.thread.email.RefreshEmailFlagThread;
import com.nms.server.thread.errorinfo.ErrorInfoResoveManagerThread;
import com.nms.server.thread.file.UnZipManagerThread;
import com.nms.server.thread.file.upload.FileUploadManagerThread;
import com.nms.server.thread.mission.InitRunningMissionThread;
import com.nms.server.thread.mission.LoadNewMissionThread;
import com.nms.server.thread.mission.MissionResultManagerThread;
import com.nms.server.thread.overrunData.DataFileReaderManagerThread;

/**
 *  DC初始化启动线程
 *  初始化流程
 *  1、初始化数据库连接，加载DC自身信息
 *  2、初始化本地目录信息，公共缓存信息
 *  3、启动各解析线程
 *  4、启动任务和主动监测现成
 *  5、启动SNMP TRAP端口
 *  6、变更启动标示
 *  @date Mar 27, 2013 2:47:31 PM
 *	@author ZhangGang
 *
 */
public class InitServerThread implements Runnable{
	private  Logger logger = Logger.getLogger(InitServerThread.class);

	@Override
	public void run() {

//		Thread.currentThread().setName("初始化线程");
		Thread.currentThread().setName("Initialization thread");
		
		CommonDao dao = null;
		try {
			
			// 连接数据库
			dao = new CommonDao();
			CommonService service = new CommonService(dao);
			
			// 初始化自身信息(失败情况下会由Web唤醒)
			if(!service.initServerParams()){
				return;
			}
			
			// 根据初始化成功标示，初始化DC实际操作信息
			if(!Constants.flag_init){
			
				//- 目录及缓存信息（监测类型和表、数据字段、告警、ip主机映射等）
				initCommonInfo(dao);
				
				try
				{
					//- 启动SNMP监测服务端口
					Common.getSnmp().addCommandResponder(TrapServer.getInstance());					
				} catch (Exception e)
				{
					logger.error("Start the SNMP monitoring service port exception", e);
				}
				
				//- 监测数据解析
				if(Constants.FLAG_DETEC_RESOVE==1){
					if(Constants.DETECT_INSERT_THREAD_MODE == 1){//单线程
						//注销线程
						Common.cancelRunnableAtOnce(Constants.DETEC_DATA_RESOVE_MANAGER);
						int delay = 0;//管理线程延时多久启动
						Date dbNow = service.getDbTime();
						long dbLong = dbNow.getTime();
						int period = Constants.DETEC_DATA_RESOLVE_PERIOD*1000;//周期：ms
						ServerTable st = Common.getServerTable();
						int count = st.getConut();
						int index = st.getIndex();
						int cst = (index-1) *period/count;//当前dc 的时间窗口 开始时间
						int pass = (int) (dbLong%period);
						
						if(cst >= pass){
							delay = cst - pass;
						}else{
							delay = period -pass + cst;
						}
						logger.debug("共 "+count+" 个 有效DC,当前DC index :  "+ index+", 数据库当前时间 ：" + dbNow.toLocaleString() +" ,DETEC_DATA_RESOLVE_PERIOD ：" + Constants.DETEC_DATA_RESOLVE_PERIOD +" s , 监测数据解析入库管理线程延迟：" + delay +" ms 启动");
						/**
						 * 解析线程scheduleWithFixedDelay不能修改为scheduleAtFixedRate是因为:解析管理线程很快就会执行完毕，不会像收集线程，需要等待节点收集完毕，
						 * 而且解析线程会尝试5次，如果都在解析，则会将数据存入硬盘，如果改了，那么解析的周期就更短了，因为管理线程几乎用不了1秒就执行完了，
						 * 这样解析线程就只有5秒左右的执行时间，会有大问题的（解析线程需要延长时间，收集线程需要缩短时间）
						 */
						/**
						 * 2018年6月14日14:34:49 修改 根据dc 个数固定 管理线层启动 时间窗口，分散一下dc 入库时间，固定周期时间启动
						 */
						ScheduledFuture<?> fcFuture = Common.scheduled.scheduleAtFixedRate(new DetecDataResoveManagerThread(), delay, period, TimeUnit.MILLISECONDS);
						//注册 管理线程
						Common.registRunnable(Constants.DETEC_DATA_RESOVE_MANAGER, fcFuture);
					}else if(Constants.DETECT_INSERT_THREAD_MODE ==  2){//多线程，info表一个线程，其它每个监测详细信息表一个线程共用一个线程池
						int im = Constants.DETECT_INFO_THREAD_MODE;
						int it = Constants.DETECT_INFO_THREAD_TIME;
						int id = Constants.DETECT_INFO_THREAD_DELAY;
						int dm = Constants.DETECT_DETAIL_THREAD_MODE;
						int dt = Constants.DETECT_DETAIL_THREAD_TIME;
						int dd = Constants.DETECT_DETAIL_THREAD_DELAY;
						
						Common.cancelRunnableAtOnce(Constants.DETECT_INFO_THREAD_KEY);
						Common.cancelRunnableAtOnce(Constants.DETECT_DETAIL_THREAD_KEY);
						Common.cancelRunnableAtOnce(Constants.DETECT_RESOVE_THREAD_KEY);
						
						//info入库线程运行模式，1：每隔 n秒 运行一次，2：间隔 n 秒运行一次
						if(im == 1){
							ScheduledFuture<?> fcFuture = Common.scheduled.scheduleAtFixedRate(new DetectInfoInsertThread(), id, it, TimeUnit.SECONDS);
							//注册 管理线程
							Common.registRunnable(Constants.DETECT_INFO_THREAD_KEY, fcFuture);
						}else{
							ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new DetectInfoInsertThread(), id, it, TimeUnit.SECONDS);
							//注册 管理线程
							Common.registRunnable(Constants.DETECT_INFO_THREAD_KEY, fcFuture);
						}
						
						if(dm == 1){
							ScheduledFuture<?> fcFuture = Common.scheduled.scheduleAtFixedRate(new DataInsertManagerThread(), dd, dt, TimeUnit.SECONDS);
							//注册 管理线程
							Common.registRunnable(Constants.DETECT_DETAIL_THREAD_KEY, fcFuture);
						}else{
							ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new DataInsertManagerThread(), dd, dt, TimeUnit.SECONDS);
							//注册 管理线程
							Common.registRunnable(Constants.DETECT_DETAIL_THREAD_KEY, fcFuture);
						}
						
						Future<?> future = Common.service.submit(new DataResolveThread());
						Common.registRunnable(Constants.DETECT_RESOVE_THREAD_KEY, future);
					}else{
						logger.error("detect.insert.thread.mode = " + Constants.DETECT_INSERT_THREAD_MODE +" is error");
					}
				}
				
				//- 错误信息（DC程序运行异常捕获报警）解析管理线程
				if(Constants.FLAG_ERROR_INFO==1){
					//注销线程
					Common.cancelRunnableAtOnce(Constants.ERROR_INFO_RESOVE_MANAGER);
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new ErrorInfoResoveManagerThread(), 0, Constants.ERROR_INFO_RESOVE_PERIOD, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.ERROR_INFO_RESOVE_MANAGER, fcFuture);
				}
				
				//- 告警数据解析管理线程
				if(Constants.FLAG_ALARM_RESOVE==1){
					//注销线程
					Common.cancelRunnableAtOnce(Constants.ALARM_DATA_RESOVE_MANAGER);
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new AlarmDataResoveManagerThread(), 0, Constants.DETEC_DATA_RESOLVE_PERIOD, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.ALARM_DATA_RESOVE_MANAGER, fcFuture);
				}
				
				//-硬盘数据（监测数据、告警数据、任务结果：由于数据量过大，暂时无法入库，而存放在硬盘上的数据）解析入库管理线程
				if(Constants.FLAG_FILES_READER_RESOVE==1){
					//注销线程
					Common.cancelRunnableAtOnce(Constants.OVERRUN_DATA_RESOVE_MANAGER);
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new DataFileReaderManagerThread(), 0, Constants.DISK_DATA_RESOLVE_PERIOD, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.OVERRUN_DATA_RESOVE_MANAGER, fcFuture);
				}
				
				
				//- DC端主动收集数据（监测数据、任务结果、回传文件）管理线程
				if(Constants.FLAG_DATA_COLLECT==1) {
					//注销线程
					Common.cancelRunnableAtOnce(Constants.DATA_COLLECT_MANAGER);
					/**
					 * 收集线程scheduleWithFixedDelay修改为scheduleAtFixedRate是因为:
					 *     scheduleWithFixedDelay:等待线程执行完毕，还会再等待指定的周期时间
					 *     scheduleAtFixedRate：为了节省时间，且线程执行完毕
					 *          1.线程执行时间大于周期间隔，则直接执行下一周期
					 *          2.线程执行时间小于周期间隔，则两次线程开始执行时间点的间隔就是设定的周期
					 *    
					 *   （解析线程需要延长时间，收集线程需要缩短时间）
					 */					
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleAtFixedRate(new DataCollectManagerThread(),0, Constants.DATA_COLLECT_PERIOD, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.DATA_COLLECT_MANAGER, fcFuture);
					
					Common.cancelRunnableAtOnce(Constants.NO_DETECT_DATA_NODE_DATA_COLLECT_MANAGER);
					ScheduledFuture<?> enFuture = Common.scheduled.scheduleAtFixedRate(new NoDetectDataCollectManagerThread(),0, Constants.ERROR_NODE_DATA_COLLECT_PERIOD, TimeUnit.SECONDS);
					Common.registRunnable(Constants.NO_DETECT_DATA_NODE_DATA_COLLECT_MANAGER, enFuture);

					
				}
				
				//- 定时的刷新是否启用邮件发送功能：从数据库读取配置
				if(Constants.FLAG_EMAIL_START==1) {
					//注销线程
					Common.cancelRunnableAtOnce(Constants.EMAIL_START_THREAD);
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new RefreshEmailFlagThread(),0, Constants.REFRESH_EMAIL_FLAG_PEROID, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.EMAIL_START_THREAD, fcFuture);
				}
				
				//定时删除log线程
				if(Constants.FLAG_DELETE_TMP_FILES==1) {
					//注销线程
					Common.cancelRunnableAtOnce(Constants.DELETE_TMP_FILES_MANAGER);
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new DeleteFilesManagerThread(),0, Constants.DELETE_TMP_FILES_PERIOD, TimeUnit.HOURS);
					//注册 管理线程
					Common.registRunnable(Constants.DELETE_TMP_FILES_MANAGER, fcFuture);					
				}

				
				//DC端定时的去收集执行完成但无任务结果返回的任务的结果信息
				if(Constants.FLAG_NONRLTTASK_RESULT_COLLECT==1) {
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new NonRltTaskResultCollectManagerThread(),0, Constants.NONRLTTASK_RESULT_COLLECT_PERIOD, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.NONRLTTASK_RESULT_COLLECT_MANAGER, fcFuture);
				}
				
				
				//- 文件上传管理线程
				if(Constants.FLAG_FILE_UPLOAD==1){
					//注销线程
					Common.cancelRunnableAtOnce(Constants.MISSION_FILE_UPLOAD);
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new FileUploadManagerThread(), 0, Constants.MISSION_FILE_UPLOAD_PERIOD, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.MISSION_FILE_UPLOAD, fcFuture);
				}
				
				//- 变更操作管理线程
				if(Constants.FLAG_CHANGE_OPERATIONS==1){
					//注销线程
					Common.cancelRunnableAtOnce(Constants.CHANGE_OPERATIONS_MANAGER);
					ScheduledFuture<?> fcFuture = Common.scheduled.scheduleWithFixedDelay(new ChangeManagerThread(), 0, Constants.CHANGE_OPERATIONS_PERIOD, TimeUnit.SECONDS);
					//注册 管理线程
					Common.registRunnable(Constants.CHANGE_OPERATIONS_MANAGER, fcFuture);
				}
				
				//- 任务初始化分配和任务线程启动
				if(Constants.FLAG_MISSION==1){
					//-- 启动已执行任务加载线程
					Common.scheduled.schedule(new InitRunningMissionThread(null),Constants.MISSION_FIRST_START, TimeUnit.SECONDS);
					
					//-- 启动已创建任务加载线程
					Common.scheduled.scheduleWithFixedDelay(new LoadNewMissionThread(null), Constants.MISSION_CHECK_NEW_START, Constants.MISSION_CHECK_NEW_PERIOD, TimeUnit.SECONDS);
					
					//启动任务结果管理线程
					if(Constants.FLAG_MISSION_RESULT==1){
						//注销线程
						Common.cancelRunnableAtOnce(Constants.MISSION_RESULT_RESOVE_MANAGER);
						//logger.debug(Constants.MISSION_RESULTS_SAVE_START+" -- "+Constants.MISSION_RESULTS_SAVE_PERIOD);
						ScheduledFuture<?> mrFuture = Common.scheduled.scheduleWithFixedDelay(new MissionResultManagerThread(),Constants.MISSION_RESULTS_SAVE_START, Constants.MISSION_RESULTS_SAVE_PERIOD, TimeUnit.SECONDS);
						//注册 管理线程
						Common.registRunnable(Constants.MISSION_RESULT_RESOVE_MANAGER, mrFuture);
					}
				}
				
				//服务端NMSC监测任务添加--一种监测--此处的握手监测仅为非服务器的握手监测
				if(Constants.FLAG_NMSC==1){
					initDrivingDetectionThread(dao,Constants.DETEC_NMSC_STR);
				}
				
				//服务端SNMP监测任务添加-system，snmp4j，objectsnmp:特设的电源、风扇、网元系统信息等？---snmp类型的监测，多个
				if(Constants.FLAG_SNMP==1){
					initDrivingDetectionThread(dao,Constants.DETEC_SNMP_STR);
				}
				//服务端PING监测任务添加--一种监测
				if(Constants.FLAG_PING==1){
					initDrivingDetectionThread(dao,Constants.DETEC_PING_STR);
				}
				//服务端SWITCH监测任务添加-交换机、特种设备：端口流量监测等--一种监测
				if(Constants.FLAG_SWITCH==1){
					initDrivingDetectionThread(dao,Constants.DETEC_SWITCH_STR);
				}
				//服务端SYSTEMDATE监测任务添加--一种监测
				if(Constants.FLAG_SYSTEMDATE==1){
					initDrivingDetectionThread(dao,Constants.DETEC_SYSTEMDATE_STR);
				}
				
				//压缩文件解压操作
				if(Constants.FLAG_ZIP==1){
					//启动时，执行一次压缩文件解压操作
					Common.service.submit(new UnZipManagerThread());
				}
				if(Constants.DETECSELFTHREAD_FLAG){
					//缓存数据量监测线程
					Common.cancelRunnableAtOnce(Constants.DETECTI_SELF_THREAD_NAME);
					ScheduledFuture<?> dsFuture = Common.dcPrivScheduled.scheduleAtFixedRate(new DetecSelfThread(),Constants.DETECSELFTHREAD_INITIALDELAY,Constants.DETECSELFTHREAD_PERIOD,TimeUnit.SECONDS);
					Common.registRunnable(Constants.DETECTI_SELF_THREAD_NAME, dsFuture);
				}
				
				
				//单独起一个线程，监督数据收集线程是否运行:放在收集数据线程之后即可
				if(Constants.FLAG_DATA_COLLECT==1) {
					Common.cancelRunnableAtOnce(Constants.DETECTI_DATA_COLLECT_THREAD_NAME);
					Future<?> detecDataCollectFuture = Common.service.submit(new DetecDataCollectThread());
					Common.registRunnable(Constants.DETECTI_DATA_COLLECT_THREAD_NAME, detecDataCollectFuture);
				}

				
				//DC缓存信息定时刷新功能
				Common.cancelRunnableAtOnce(Constants.RESET_SERVER_THREAD_NAME);
				ScheduledFuture<?> rsFuture = Common.dcPrivScheduled.scheduleAtFixedRate(new ResetServerThread(-1),8,8,TimeUnit.HOURS);
				Common.registRunnable(Constants.RESET_SERVER_THREAD_NAME, rsFuture);
				
				//数据库连接监听线程
				Common.cancelRunnableAtOnce(Constants.DB_CONNECTION_THREAD_NAME);
				ScheduledFuture<?> dbcFuture = Common.dcPrivScheduled.scheduleAtFixedRate(new DBTestThread(),3,3,TimeUnit.MINUTES);
				Common.registRunnable(Constants.DB_CONNECTION_THREAD_NAME, dbcFuture);
				
				logger.info("------- DataController Start Success------------");
				Constants.flag_init = true;
			}
			
		} catch (SQLException e) {
			logger.error("Failed to get database connection, execute again in 5 minutes"+ e.getMessage());
			Common.scheduled.schedule(this, 5, TimeUnit.MINUTES);
			Common.addErrorInfoForMySelf(Constants.ERROR_CODE_DB_CONNECT,Constants.ERROR_INFO_SATAE_ERROR,"");
		} catch (Exception e) {
			logger.error("DataController initialization failure",e);
			Common.scheduled.schedule(this, 5, TimeUnit.MINUTES);
		}finally{
			if(dao!=null){
				dao.close();
				dao=null;
			}
			logger.debug("启动程序dao已关闭");
		}
	}
	
	/**
	 * 初始化主动监测线程
	 * @time Sep 20, 2011-7:07:36 PM
	 * @param dao
	 * @return
	 */
	public  boolean initDrivingDetectionThread(CommonDao dao,String checkType){

		boolean isSuccess = true;
		CommonService commonService = new CommonService(dao);
		ThreadService service = new ThreadService();
		//--获取checkType 监测配置并启动监测任务
		List<SetInfo> setList =  commonService.getDrivingSetInfo(checkType);//获得checkType类型的所有监测设置
		logger.info("检查主动监测类别："+checkType+" 关联监测设置："+(setList==null?0:setList.size())+"个");
		//-- checkType 监测任务启动 和 客户端启动监测任务启动
		if(setList!=null && setList.size()>0){
			for (Iterator setIte = setList.iterator(); setIte.hasNext();) {
				SetInfo si = (SetInfo) setIte.next();
				if(Constants.DETEC_SNMP_STR.equalsIgnoreCase(checkType)){
					if(Constants.DETEC_SWITCH_STR.equalsIgnoreCase(si.getCheckTypeName())){
						continue;
					}
				}
				service.updateThread(si);
				
			}
		}
		return isSuccess;
	}
	
	/**
	 * 初始化公共信息方法
	 * <p>Common类中的公共数据集合，在此方法中进行数据初始化</p>
	 * Init server 
	 * @time Aug 24, 2011-9:55:44 AM
	 * @return
	 */
	public  boolean initCommonInfo(CommonDao dao) {
		initCheck();
		boolean flag =  true;
		
		CommonService service = new CommonService(dao);
		UpgradeService upService = new UpgradeService(dao);
		try{
			//-- 从数据库中查询邮件创建信息
			Constants.flag_email = service.getFlagEmail();
			//-- checkTypeName TableModel Map Init（监测类别名称 与 检测类别信息）
			service.updateCheckTableInfo(Common.getInsertTable(), null);
			service.updateSetInfoName(Common.getSetInfoNameMape(), null);
			//-- Table Columns Map Init（数据库表结构信息）
			service.updateTableColumnsMap(Common.getTableMap(), null);
			
			//alarm Ping Init（告警数据结构信息）
			service.updateAlarmInfo(Common.getAlarmInfoMap(),null);
			
			//-- LoginIp nodeip Init（seq_id-物理节点信息）
			service.updateSimpleNodeByUUID(null);
			
			//--（ClientIP-seq_id信息）
			service.updateSeqIdByNodeIp(Common.getIpSeqIdMap(),null);
			
			service.updateUserPwdByNodeIp(Common.getIpUserPwdMap(),null);
			
			// init loop Mission info
			upService.updateLoopMissionInfo(Common.getLoopMissionInfoMap(), null);
			upService.updateLoopMissionRoundInfo(Common.getLoopMissionRoundInfoList(), null);
			
			// init detection info
			List<SetInfo> siList = service.getDrivingSetInfo(Constants.ALARM_SNMP_TRAP_STR);
			if(siList !=null && siList.size()>0){
				Common.setSnmpTrapSetInfo(siList.get(0));
			}

		}catch (Exception e) {
			logger.debug("NMSServer参数初始化失败", e);
			System.exit(0);
		}

		return flag;
	}
	
	/**
	 * 程序启动时校验操作
	 * <p>必要文件目录的存在校验操作、及相关必要存在校验操作</p>
	 * @time Aug 24, 2011-10:14:35 AM
	 * @return
	 */
	public  void initCheck() {

		File file = new File(Constants.MISSION_FILE_UPLOAD_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
		file = new File(Constants.MISSION_FILE_DOWNLOAD_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
		file = new File(Constants.ZIP_FILE_DETECT_DATA_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
		file = new File(Constants.ZIP_FILE_TASK_RESULT_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
		file = new File(Constants.ZIP_FILE_TASK_RETURN_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
		file = new File(Constants.ZIP_RESOVE_DETECT_DATA_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
		file = new File(Constants.ZIP_RESOVE_TASK_RESULT_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		file = new File(Constants.ZIP_RESOVE_TASK_RESULT_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
		file = new File(Constants.ZIP_RESOVE_TASK_RETURN_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		file = new File(Constants.ERROR_DETEC_FILE_DIR);
		if (!file.exists()) {
			file.mkdirs();
		}
		
//		return flag;
	}
}
