package com.eactive.eai.rms.onl.common.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.eactive.eai.rms.onl.common.util.FileSystemUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;

import com.eactive.eai.common.server.Keys;
import com.eactive.eai.data.entity.onl.server.EAIServer;
import com.eactive.eai.rms.common.acl.user.BizService;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.data.entity.onl.server.EAIServerService;
import com.eactive.eai.rms.onl.common.util.DateUtil;
import com.eactive.eai.rms.onl.transaction.online.TransactionOnlineManService;
import com.eactive.eai.rms.onl.vo.TransactionTrackingVo;

public class TransactionReportHourJob implements Job {
    /**
    * Logger for this class
    */
    private static final Logger logger = Logger.getLogger(TransactionReportHourJob.class);

    /** The monitoring context. */
    private transient MonitoringContext monitoringContext;

    /** The transaction service. */
    public TransactionOnlineManService transactionService;

    private BizService bizService;
    
    private EAIServerService eaiServerService;
    
    
    //@ScheduleMethod(type = ScheduleType.CRON, cronExpression = "0 0 * * * ?")
    @Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
        //JobKey jobKey = context.getJobDetail().getKey();

		ApplicationContext appContext = null;
		try {
			appContext = (ApplicationContext)context.getScheduler().getContext().get("applicationContext");
		} catch (SchedulerException e) {
			logger.error("applicationContext get module error",e);
			return ;
		}  
		monitoringContext    = (MonitoringContext)appContext.getBean("monitoringContext");	
		eaiServerService = appContext.getBean(EAIServerService.class);
		transactionService   = (TransactionOnlineManService)appContext.getBean("transactionOnlineService");	
		bizService           = (BizService)appContext.getBean("bizService");	
		
        // 프라퍼티 에서 지정한 시간에 다음 작업을 수행한다.
        String hour = DateUtil.getDateTime("HH");
        if ("00".equals(hour)) {
            return;
        }

        String trTime = monitoringContext.getStringProperty(MonitoringContext.RMS_TRANSACTION_LOG_TIME, "");
        if (trTime.contains("EVERY_HOUR")) {
        	// go on
        } else if (!StringUtils.contains(trTime, hour)) {
            return;
        }        

        backupTransactionData();		
	
		
	}    

    private void backupTransactionData() {

        if (logger.isInfoEnabled()) {
            logger.info("*** START TRANSACTION LOGGING run("
                    + CommonUtil.getToday("yyyy-MM-dd HH:mm") + ")");
        }

        String pathDir = FileSystemUtil.pathNormalize(
                monitoringContext.getStringProperty( MonitoringContext.RMS_TRANSACTION_LOG_PATH,"/fslog/eai/")
                , monitoringContext.getStringProperty( Keys.SERVER_KEY)
                , "trlog"
            );

        ///////////////////////////////////////////////
        // 로컬테스트용
        // pathDir = "D:/RMS_src/RTSApp.ear/cleanupTest" ;
        //
        ///////////////////////////////////////////////

        String header = "tr_";

        File backupDirectory = new File(pathDir);

        if (!backupDirectory.exists()) {
            backupDirectory.mkdirs();
        }

        File backupFile = new File(backupDirectory, header
                + DateUtil.getDateTime("yyyyMMdd_HHmm") + ".xls");

        backupTransactionData(backupFile);

        // 지정된 날짜 이전의 백업파일들은 삭제한다.
        String remainDay = monitoringContext.getStringProperty(
            MonitoringContext.RMS_TRANSACTION_LOG_REMAIN, "7");
        cleanupOldFiles(Integer.parseInt(remainDay), pathDir, header);

        if (logger.isInfoEnabled()) {
            logger.info("*** END TRANSACTION LOGGING run("
                    + DateUtil.getDateTime("yyyy-MM-dd HH:mm") + ")");
        }
    }

    private void backupTransactionData(File backupFile) {
        FileOutputStream os = null;
        try {
            HSSFWorkbook wb = new HSSFWorkbook();
            // 2014-07-18 : Datasource 동적으로 가져오게 변경
            short sheetNo = 0;
            for(DataSourceType source : DataSourceTypeManager.getOnlineDataSourceTypes()) {
                writeExcelSheet(wb, source.getName(),source.getText(), sheetNo);
                sheetNo += 1;
            }

//          // 대외
//          writeExcelSheet(wb, DataSourceTypeManager.FEP, (short) 0);
//            // 내부
//            writeExcelSheet(wb, DataSourceTypeManager.EAI, (short) 1);

            os = new FileOutputStream(backupFile);
            wb.write(os);
        } catch (Exception e) {
            logger.error("*** ERROR TRANSACTION LOGGING ("
                    + DateUtil.getDateTime("yyyy-MM-dd HH:mm") + ")");
            logger.error(this, e);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
        }
    }

    private void cleanupOldFiles(int remainDay, String pathDir, String header) {
        String headFile = header
                + DateUtil.getDateTime(remainDay * -1).substring(0, 8);

        File dir = new File(pathDir);
        if (dir.isDirectory()) {
            String files[] = dir.list();
            if (files != null) {
            	for (String s : files) {
            		File f = new File(pathDir + "/" + s);
            		if (!f.isDirectory()) {
            			if (headFile.compareTo(s) > 0) {
            				if (logger.isDebugEnabled()) {
            					logger.debug("RMS_CLEANUP:Remove old log file =>"
            							+ s);
            				}
            				
            				try {
            					f.delete();
            				} catch (Exception e) {
            					logger.error(this, e);
            				}
            			} else {
            				if (logger.isDebugEnabled()) {
            					logger.debug("RMS_CLEANUP:Recent log file =>" + s);
            				}
            			}
            		}
            	}
            }
        }
    }

    private HSSFCell createUTF_16Cell(HSSFRow row, int i) {
        HSSFCell cell = row.createCell((short) i);
        //cell.setEncoding(HSSFCell.ENCODING_UTF_16);
        return cell;
    }

    private void writeExcelSheet(HSSFWorkbook wb, String service, String sheetName ,short num)
            throws Exception {
        try {
            // HSSFSheet sheet = wb.createSheet(service.getName());
            HSSFSheet sheet = wb.createSheet();
            wb.setSheetName(num, sheetName);

            // make Header
            short col = 0;
            int rownum = 0;

            HSSFRow head = sheet.createRow(rownum++);
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("정상");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("에러");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("타임아웃");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("처리시간");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("합계");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");
            createUTF_16Cell(head, col++).setCellValue("");

            col = 0;
            head = sheet.createRow(rownum++);
            createUTF_16Cell(head, col++).setCellValue("업무구분코드");
            createUTF_16Cell(head, col++).setCellValue("서비스명");
            createUTF_16Cell(head, col++).setCellValue("서버인스턴스");
            createUTF_16Cell(head, col++).setCellValue("100");
            createUTF_16Cell(head, col++).setCellValue("200");
            createUTF_16Cell(head, col++).setCellValue("300");
            createUTF_16Cell(head, col++).setCellValue("400");
            createUTF_16Cell(head, col++).setCellValue("100");
            createUTF_16Cell(head, col++).setCellValue("200");
            createUTF_16Cell(head, col++).setCellValue("300");
            createUTF_16Cell(head, col++).setCellValue("400");
            createUTF_16Cell(head, col++).setCellValue("900");
            createUTF_16Cell(head, col++).setCellValue("300");
            createUTF_16Cell(head, col++).setCellValue("400");
            createUTF_16Cell(head, col++).setCellValue("900");

            createUTF_16Cell(head, col++).setCellValue("IF");
            createUTF_16Cell(head, col++).setCellValue("수동");
            createUTF_16Cell(head, col++).setCellValue("총");

            createUTF_16Cell(head, col++).setCellValue("IfType");
            createUTF_16Cell(head, col++).setCellValue("전체건수");
            createUTF_16Cell(head, col++).setCellValue("에러건수");
            createUTF_16Cell(head, col++).setCellValue("타임아웃");
            createUTF_16Cell(head, col++).setCellValue("정상건수");
            
            //모니터링 추가 >> INST3 이 아닌 해당 서비스 인스턴스로 수정
            DataSourceContextHolder.setDataSourceType(DataSourceTypeManager.getDataSourceType(service));
            List<HashMap<String, Object>> codeList = bizService.selectBizList();
            
          //취약점코드 수정 2019.08.22 SW
            DataSourceType dType = DataSourceTypeManager.getDataSourceType(service);
            if(dType == null) {
            	throw new Exception("DataSourceType not found service="+ service);
            }
            
            List<EAIServer> instList = eaiServerService.selectEaiServerIpList();
            if(instList == null) {
            	throw new Exception("EaiServerIpList not found DataSourceType="+ dType.getName());
            }
            
            List<TransactionTrackingVo> voList = transactionService.findTransactionList(instList);

            String bizCodes[] = new String[codeList.size()];
            HashMap<String, String> codeMap = new HashMap<String, String>();
            int step = 0;
            for (HashMap<String, Object> m : codeList) {
                String code = (String) m.get("BIZCODE");
                String name = (String) m.get("BIZNAME");
                bizCodes[step++] = code ;
                codeMap.put( code, name );
            }
            Arrays.sort(bizCodes);

            double sum[] = new double[16];

            for (int i = 0; i < bizCodes.length; i++) {
                for (TransactionTrackingVo instVo : voList) { // instance 별 리스트
                    HashMap<String, HashMap<String, TransactionTrackingVo>> map;
                    HashMap<String, TransactionTrackingVo> mapSub;

                    map = instVo.getMapToday();

                    // EAI 서버에서 map 값이 null 인 상태로 값이 오는경우 Exception 발생을 방지하기 위함. 
                    if (map == null) {
                        continue;
                    }

                    // DB 에 있는 업무코드는 CHAR[4] 타입이다.
                    //mapSub = map.get(StringUtils.rightPad(bizCodes[i], 4, ' '));
                    mapSub = map.get(bizCodes[i]);

                    if (mapSub == null) {
                        continue;
                    }

                    Iterator<String> it = mapSub.keySet().iterator();
                    String[] svcKeys = new String[mapSub.size()]; // eai service code
                    for (int j = 0; it.hasNext(); j++) {
                        svcKeys[j] = (String) it.next();
                    }
                    Arrays.sort(svcKeys);

                    for (int k = 0; k < svcKeys.length; k++) {

                        TransactionTrackingVo vo = mapSub.get(svcKeys[k]);
                        // codeMap 에는 업무코드가 trim 된형태로 들어 있음.
                        
                        vo.calcTotalCount();                        
                        

                        HSSFRow row = sheet.createRow(rownum++);

                        short colm = 0;

                        createUTF_16Cell(row, colm++).setCellValue(
                            "[" + bizCodes[i] + "]"
                                    + codeMap.get(bizCodes[i]));
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getEaiServiceCode());
                        createUTF_16Cell(row, colm++).setCellValue(
                            instVo.getInstanceName());

                        // 정상건수
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getProc100());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getProc200());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getProc300());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getProc400());

                        // 에러건수
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError100());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError200());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError300());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError400());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError900());

                        // 타임아웃
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError9300());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError9400());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getError9900());

                        // 처리시간
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getTimeEai());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getTimePsv());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getTimeTotal());

                        // 합계
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getIfType());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getTotalProcAll());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getTotalError());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getTotalTimeout());
                        createUTF_16Cell(row, colm++).setCellValue(
                            vo.getTotalProc());

                        sum[0] += vo.getProc100();
                        sum[1] += vo.getProc200();
                        sum[2] += vo.getProc300();
                        sum[3] += vo.getProc400();

                        sum[4] += vo.getError100();
                        sum[5] += vo.getError200();
                        sum[6] += vo.getError300();
                        sum[7] += vo.getError400();
                        sum[8] += vo.getError900();

                        sum[9] += vo.getError9300();
                        sum[10] += vo.getError9400();
                        sum[11] += vo.getError9900();

                        sum[12] += vo.getTotalProcAll();
                        sum[13] += vo.getTotalError();
                        sum[14] += vo.getTotalTimeout();
                        sum[15] += vo.getTotalProc();
                    }
                }
            }

            // 합계
            HSSFRow tail = sheet.createRow(rownum++);
            col = 0;
            createUTF_16Cell(tail, col++).setCellValue("총계");
            createUTF_16Cell(tail, col++).setCellValue("");
            createUTF_16Cell(tail, col++).setCellValue("");

            createUTF_16Cell(tail, col++).setCellValue(sum[0]);
            createUTF_16Cell(tail, col++).setCellValue(sum[1]);
            createUTF_16Cell(tail, col++).setCellValue(sum[2]);
            createUTF_16Cell(tail, col++).setCellValue(sum[3]);

            createUTF_16Cell(tail, col++).setCellValue(sum[4]);
            createUTF_16Cell(tail, col++).setCellValue(sum[5]);
            createUTF_16Cell(tail, col++).setCellValue(sum[6]);
            createUTF_16Cell(tail, col++).setCellValue(sum[7]);
            createUTF_16Cell(tail, col++).setCellValue(sum[8]);

            createUTF_16Cell(tail, col++).setCellValue(sum[9]);
            createUTF_16Cell(tail, col++).setCellValue(sum[10]);
            createUTF_16Cell(tail, col++).setCellValue(sum[11]);

            createUTF_16Cell(tail, col++).setCellValue("");
            createUTF_16Cell(tail, col++).setCellValue("");
            createUTF_16Cell(tail, col++).setCellValue("");
            createUTF_16Cell(tail, col++).setCellValue("");

            createUTF_16Cell(tail, col++).setCellValue(sum[12]);
            createUTF_16Cell(tail, col++).setCellValue(sum[13]);
            createUTF_16Cell(tail, col++).setCellValue(sum[14]);
            createUTF_16Cell(tail, col++).setCellValue(sum[15]);

        } catch (Exception e) {
            throw e;
        }
    }


}
