package kr.gmtc.tss.data;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Queue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import kr.gmtc.tss.data.vo.AlarmVO;
import kr.gmtc.tss.data.vo.StandStatusVO;
import kr.gmtc.tss.status.CountStatus;

public class ParseTargetRunnable implements Runnable {
	
	private boolean flagFile;
	private boolean flagDataBase;
	private boolean flagDataFile;
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	Queue<String> rcvQueue;
	
	Queue<StandStatusVO> standStatusQueue;
	Queue<String> dataStandStatusFileQueue;
	Queue<StandStatusVO> messageBodyStandStatusQueue;
	
	Queue<AlarmVO> alarmQueue;
	Queue<String> dataAlarmQueueFileQueue;
	Queue<AlarmVO> messageBodyAlarmQueue;
	
	private int rcvPos = 0;
	private int rcvStatic = 0;
	
	private boolean isRunning = false;	
	private int listChunkSize = 100; 
	private long sleepMillis;
	
	private boolean isAlarm = false;

	//new ParseTargetRunnable(rcvAlarmQueue, alarmQueue, dataAlarmQueueFileQueue, messageBodyAlarmQueue, queueChunkSize, parseTargetSleepMs, flagFile, flagDataBase, flagDataFile, true);
	
	private String classification;
	private String swclassification;
	private String logclassification;
	
	public ParseTargetRunnable(Queue<String> rcvQueue, 
			Queue<StandStatusVO> standStatusQueue, Queue<String> dataStandStatusFileQueue, Queue<StandStatusVO> messageBodyQueue, 
			int listChunkSize, long sleepMillis, boolean flagFile, boolean flagDataBase, boolean flagDataFile,
			String classification, String swclassification, String logclassification) {
		this.rcvQueue = rcvQueue;
		this.standStatusQueue = standStatusQueue;
		this.dataStandStatusFileQueue = dataStandStatusFileQueue;
		this.messageBodyStandStatusQueue = messageBodyQueue;
		this.listChunkSize = listChunkSize;
		this.sleepMillis = sleepMillis;
		this.flagFile = flagFile;
		this.flagDataBase = flagDataBase;
		this.flagDataFile = flagDataFile;
		this.classification = classification;
		this.swclassification = swclassification;
		this.logclassification = logclassification;
	}
	
	public ParseTargetRunnable(Queue<String> rcvQueue, 
			Queue<AlarmVO> alarmQueue, Queue<String> dataAlarmQueueFileQueue, Queue<AlarmVO> messageBodyQueue, 
			int listChunkSize, long sleepMillis, boolean flagFile, boolean flagDataBase, boolean flagDataFile, boolean b,
			String classification, String swclassification, String logclassification) {
		this.rcvQueue = rcvQueue;
		this.alarmQueue = alarmQueue;
		this.dataAlarmQueueFileQueue = dataAlarmQueueFileQueue;
		this.messageBodyAlarmQueue = messageBodyQueue;
		this.listChunkSize = listChunkSize;
		this.sleepMillis = sleepMillis;
		this.flagFile = flagFile;
		this.flagDataBase = flagDataBase;
		this.flagDataFile = flagDataFile;
		this.isAlarm = b;
		this.classification = classification;
		this.swclassification = swclassification;
		this.logclassification = logclassification;
	}
	
	@Override
	public void run() {
		isRunning = true;
		
		while (isRunning) {
			
			try {
				int loopCnt = 0;
				if(rcvQueue.size()>listChunkSize) {
					loopCnt = listChunkSize;
				}else {
					loopCnt = rcvQueue.size();
				}
				String [] chunkArr = new String[loopCnt];
				
				for (int i = 0; i < loopCnt; i++) {
					chunkArr[i] = rcvQueue.poll();
				}
				
				for (int i = 0; i < chunkArr.length; i++) {
					if (isAlarm) {
						parseAlarmAndEnqueue(chunkArr[i]);
					} else {
						parseStandStatusAndEnqueue(chunkArr[i]);
					}
				}
				
			} catch (Exception e) {
				if (e.getMessage() != null) {
					logger.debug("[ParseTarget] Parsing Error Message : " ,e);
				} else {
					logger.info("[ParserThread] Parsing Error Call Stack" ,e);
				}
			} 
			
			sleep(sleepMillis);
		}
	}
	
	private void parseAlarmAndEnqueue(String result) {
		try {
			ArrayList<AlarmVO> histroyQueue = new ArrayList<AlarmVO>();
			ObjectMapper mapper = new ObjectMapper();
			
			Map<String, Object> convert = mapper.readValue(result, new TypeReference<Map<String, Object>>() {});
			ArrayList<LinkedHashMap<String, Object>> list = (ArrayList<LinkedHashMap<String, Object>>) convert.get("data");

			logger.info("ic.analyze.situation 수신 데이터 변환 건수 {}", list.size());
			
			DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
	        String dateTime = dateFormat.format(new Date());
			
	        StringBuilder sb = new StringBuilder();
			
	        sb.append(dateTime); sb.append(",");
	        sb.append(logclassification); sb.append(",");	//log구분
	        sb.append(swclassification); sb.append(",");	//sw구분
	        sb.append(classification); sb.append("|");		//서버구분
			
	        int i = 0;
			for (LinkedHashMap<String, Object> map : list) {
				AlarmVO a = mapper.convertValue(map, AlarmVO.class);
				histroyQueue.add(a);
				
				if (i > 0) sb.append("^");
				
				sb.append(a.getAnalsId()); 						sb.append(",");	
				sb.append(a.getAnalsDt()); 						sb.append(",");	
				sb.append(a.getAnalsTy()); 						sb.append(",");	
				sb.append(a.getArea().toDataFormat()); 			sb.append(",");						
				sb.append(a.getTarget1().toDataFormat()); 		sb.append(",");						
				sb.append(a.getTarget2().toDataFormat()); 		sb.append(",");						
				sb.append(a.getAnalsMsg());
				i++;
			}
					
			if(flagFile)messageBodyAlarmQueue.addAll(histroyQueue);
			
			if(flagDataFile)dataAlarmQueueFileQueue.add(sb.toString());
			
			if(flagDataBase) {
				if (histroyQueue.size() > 0) {
					if (flagDataBase) alarmQueue.addAll(histroyQueue);
				} 
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			if (e.getMessage() != null) {
				logger.debug("[ParserThread] Parsing Error Message : " + e.getMessage());
				logger.debug("",e);
			} else {
				logger.debug("[ParserThread] Parsing Error Packet Message :" + result);
			}
		}
	}
	
	private void parseStandStatusAndEnqueue(String result) {
		try {
			
			ArrayList<StandStatusVO> histroyQueue = new ArrayList<StandStatusVO>();
			ObjectMapper mapper = new ObjectMapper();
			
			Map<String, Object> convert = mapper.readValue(result, new TypeReference<Map<String, Object>>() {});
			ArrayList<LinkedHashMap<String, Object>> list = (ArrayList<LinkedHashMap<String, Object>>) convert.get("data");
			
			logger.info("ic.analyze.stand.status 수신 데이터 변환 건수 {}", list.size());
			
			DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
	        String dateTime = dateFormat.format(new Date());
			
	        StringBuilder sb = new StringBuilder();
			
	        sb.append(dateTime); sb.append(",");
	        sb.append(logclassification); sb.append(",");	//log구분
	        sb.append(swclassification); sb.append(",");	//sw구분
	        sb.append(classification); sb.append("|");		//서버구분
			int i = 0;
			
			for (LinkedHashMap<String, Object> map : list) {
				StandStatusVO s = mapper.convertValue(map, StandStatusVO.class); 
				histroyQueue.add(s);
				
				if (i > 0) sb.append("^");
				
				sb.append(s.getStandNo()); 								sb.append(",");	
				sb.append(s.getStandSttusTy().toDataFormat()); 			sb.append(",");	
				sb.append(s.getAircraftSttusTy()); 						sb.append(",");	
				sb.append(s.getClsgn()); 									
				
				i++;
			}
			
			if(flagFile)messageBodyStandStatusQueue.addAll(histroyQueue);
			if(flagDataFile)dataStandStatusFileQueue.add(sb.toString());
			if(flagDataBase) {				
				if (histroyQueue.size() > 0) {
					standStatusQueue.addAll(histroyQueue);
				} 
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			if (e.getMessage() != null) {
				logger.debug("[ParserThread] Parsing Error Message : " + e.getMessage());
				logger.debug("",e);
			} else {
				logger.debug("[ParserThread] Parsing Error Packet Message :" + result);
			}
		}
	}

	
	public synchronized CountStatus getCountAndSetZero() {
		CountStatus countStatus = new CountStatus(rcvPos,rcvStatic);
		rcvPos = 0;
		rcvStatic = 0;
		return countStatus;
	}
	
	private void sleep(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			logger.debug("[ParseTargetRunnable] sleep error : "+e.getLocalizedMessage());
		}
	}

	public void setRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}
}
