package kr.gmtc.tss.data;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Queue;
import java.util.stream.Collectors;

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

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

import kr.gmtc.tss.data.vo.AsdeTrackVO;
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<AsdeTrackVO> asdeTrackQueue;
	Queue<String> dataFileQueue;
	Queue<AsdeTrackVO> asdeTrackLastQueue;
	Queue<AsdeTrackVO> messageBodyQueue;
	
	private int rcvPos = 0;
	private int rcvStatic = 0;
	
	private boolean isRunning = false;	
	private int listChunkSize = 100; 
	private long sleepMillis;

	private String classification;
	private String swclassification;
	private String logclassification;
	
	public ParseTargetRunnable(Queue<String> rcvQueue, Queue<AsdeTrackVO> asdeTrackQueue, Queue<String> dataFileQueue, Queue<AsdeTrackVO> asdeTrackLastQueue, Queue<AsdeTrackVO> messageBodyQueue
			, int listChunkSize, long sleepMillis, boolean flagFile, boolean flagDataBase, boolean flagDataFile
			, String classification, String swclassification, String logclassification) {
		this.rcvQueue = rcvQueue;
		this.asdeTrackQueue = asdeTrackQueue;
		this.dataFileQueue = dataFileQueue;
		this.asdeTrackLastQueue = asdeTrackLastQueue;
		this.messageBodyQueue = 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;
	}
	
	@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++) {
					parseAndEnqueue(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 parseAndEnqueue(String result) {
		try {
			ArrayList<AsdeTrackVO> histroyQueue = new ArrayList<AsdeTrackVO>();
			ObjectMapper mapper = new ObjectMapper();
			
			Map<String, Object> convert = mapper.readValue(result, new TypeReference<Map<String, Object>>() {});
			//Map<String, Object> data = (Map<String, Object>) convert.get("data");
			ArrayList<LinkedHashMap<String, Object>> list = (ArrayList<LinkedHashMap<String, Object>>) convert.get("data");
			
			logger.info("수신 데이터 변환 건수 {}", 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) {
				
				AsdeTrackVO a = mapper.convertValue(map, AsdeTrackVO.class);
				
				if (i > 0) sb.append("^");
				
				sb.append(a.getTrgtId()); 			sb.append(",");	
				sb.append(a.getModeScd()); 			sb.append(",");	
				sb.append(a.getSsrCd()); 			sb.append(",");	
				sb.append(a.getClsgn()); 			sb.append(",");	
				sb.append(a.getTailNo()); 			sb.append(",");	
				sb.append(a.getTrackNo()); 			sb.append(",");	
				sb.append(a.getRecptnDt()); 		sb.append(",");	
				sb.append(a.getCatTy()); 			sb.append(",");	
				sb.append(a.getLat()); 				sb.append(",");	
				sb.append(a.getLon()); 				sb.append(",");	
				sb.append(a.getSpd()); 				sb.append(",");	
				sb.append(a.getCos()); 				sb.append(",");	
				sb.append(a.getTrgtTy()); 			sb.append(",");	
				sb.append(a.getAlt()); 					
				
				histroyQueue.add(a);
				
				i++;
			}
			
			
			if(flagFile)messageBodyQueue.addAll(histroyQueue);
			if(flagDataFile)dataFileQueue.add(sb.toString());
			if(flagDataBase) {
				
				
				if (histroyQueue.size() > 0) {
					if (flagDataBase) asdeTrackQueue.addAll(histroyQueue);
				} 
				
				if (flagDataBase) {
					histroyQueue
					.stream()
					.collect(Collectors.groupingBy(AsdeTrackVO::getTrgtId,           
							Collectors.maxBy(Comparator.comparing(AsdeTrackVO::getRecptnDt))
							)).forEach((key, value) -> {
								//logger.info(""+value.get().getRecptnDt());
								asdeTrackLastQueue.add(value.get());
							});;
				}
			}
			
		} 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;
	}
}
