package com.eactive.eai.rms.onl.manage.rule.upload;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.SystemUtil;
import com.eactive.eai.rms.common.base.OnlBaseAnnotationController;
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.interceptor.InterceptorSkipController;
import com.eactive.eai.rms.common.logging.UserAccessLogger;
import com.eactive.eai.rms.onl.common.service.EaiCmReflectionService;
import com.eactive.eai.rms.onl.common.util.FileWriteUtil;
import com.eactive.eai.rms.onl.loader.service.TransactionLoaderService;

@Controller
public class CMFileUploadController extends OnlBaseAnnotationController implements InterceptorSkipController {

    private static final Logger logger = Logger.getLogger("IOMAP_LOGGER");
	@Autowired
	@Qualifier("monitoringContext")
	private MonitoringContext monitoringContext;
    
    @Autowired
    @Qualifier("loaderService") 
    private TransactionLoaderService loaderService; 
    
    @Autowired
    @Qualifier("eaiCmReflectionService")
    private EaiCmReflectionService eaiCmReflectionService;   
 
    /**
     * CM File Upload 관련 컨트롤러
     * *
     * @param request
     * @param response
     * @param schema
     * @return
     * @throws Exception
     */
    @RequestMapping(value= "/cmFileUpload.file", method=RequestMethod.POST)
    public ModelAndView cmFileUpload(StandardMultipartHttpServletRequest request, HttpServletResponse response) throws Exception {
    	
        UserAccessLogger.log(request, "Message", "L", "");
    	if (SystemUtil.isDevServer()){
            HashMap resultMap = new HashMap();
            resultMap.put("status", "fail");
            resultMap.put("errorMsg","not support dev server");
            return new ModelAndView("jsonView", resultMap);
    	}
        
		HashMap<String,String> map = new HashMap<String,String>();
		
		logger.debug("cmFileUpload content-Type="+request.getContentType());
		Properties prop = monitoringContext.getProperties();
		makecmfolder(prop);
		
		String downloadPath   = prop.getProperty(MonitoringContext.CM_DOWNLOAD_PATH , "/dat/eaiData/engineData/download/");
		String tempPath       = prop.getProperty(MonitoringContext.CM_TEMP_PATH     , "/dat/eaiData/engineData/temp/");
		String backupPath     = prop.getProperty(MonitoringContext.CM_BACKUP_PATH   , "/dat/eaiData/engineData/backup/");
		String cmFolder     = "";
		//sample /dat/eaiData/engineData/download                                        = downloadPath
		//sample 20191029235959_S010795_DSG_TXT                                = downloadPath + File.separator + cmFolder
		//sample 20191029235959_S010795_DSG_TXT/interface                      = downloadPath + File.separator + cmFolder + Fileseparator + keys[0]
		//sample 20191029235959_S010795_DSG_TXT/interface/TST0200100EAIS02.txt = downloadPath + File.separator + cmFolder + Fileseparator + keys[0] + Fileseparator + keys[1]

    	cmFolder = request.getParameter("cmFolder");
    	String eaiSevrName = null; 
		if(cmFolder != null){ //취약점소스 수정 2020.08.27
			eaiSevrName = cmFolder.split("_")[2];
		}
		for (String key : request.getParameterMap().keySet()){
			String [] datas= request.getParameterValues(key);
			StringBuffer resultS = new StringBuffer();
			for(String data : datas){
				resultS.append(data);
			}
			map.put(key, resultS.toString());
		}
    	for(Part part : request.getParts()){
    		String key = part.getName();
    		String[] keys = key.split("_",2);
    		if (keys.length != 2){
    			throw new Exception("name("+key+") path error ");
    		}
    		//temp folder download
    		String tempDownloadPath = tempPath + File.separator + cmFolder + File.separator + keys[0] +File.separator;
    		FileWriteUtil.FileWrite(tempDownloadPath, keys[1], (String)map.get(key));
    	}
    	//추가로 interface에 어댑터 validation 로직추가
		try{
			DataSourceType dt = null;
			if(eaiSevrName != null){ //취약점소스 수정 2020.08.27
				dt = DataSourceTypeManager.getDataSourceType(eaiSevrName);
			}
			if (dt == null){
				logger.info("not support eaiSevrName : "+ eaiSevrName);
				throw new Exception("not support eaiSevrName : "+ eaiSevrName);
			}
			DataSourceContextHolder.setDataSourceType(dt);
			interfaceAdapterValidate(dt,tempPath + File.separator + cmFolder + File.separator);
		}catch(Exception e){
			HashMap resultMap = new HashMap();
			resultMap.put("status", "fail");
			resultMap.put("errorMsg", e.getMessage());
			return new ModelAndView("jsonView", resultMap);
		}
    	
    	//download folder check & move
    	File downloadFolder = new File(downloadPath + File.separator + cmFolder);
    	if (downloadFolder.exists()){
    		downloadFolder.renameTo(new File(backupPath+ File.separator + cmFolder + "_" + DatetimeUtil.getCurrentTimeMsNoMark(downloadFolder.lastModified())));
    	}
    	//temp folder to download folder 
    	File tempFolder = new File(tempPath + File.separator + cmFolder);
    	if (tempFolder.exists()){
    		tempFolder.renameTo(new File(downloadPath+ File.separator + cmFolder ));
    	}

        HashMap resultMap = new HashMap();
        resultMap.put("status", "success");
        
        return new ModelAndView("jsonView", resultMap);
    }
    
    /**
     * CM File Upload 관련 컨트롤러
     * file upload 및 실시간 적용
     * *
     * @param request
     * @param response
     * @param schema
     * @return
     * @throws Exception
     */
    @RequestMapping(value= "/cmFileUpload.file",params = "cmd=realtimeApply", method=RequestMethod.POST)
    public ModelAndView cmFileUploadAndRealtimeApply(StandardMultipartHttpServletRequest request, HttpServletResponse response) throws Exception {
    	
        UserAccessLogger.log(request, "Message", "L", "");
    	if (SystemUtil.isDevServer()){
            HashMap resultMap = new HashMap();
            resultMap.put("status", "fail");
            resultMap.put("errorMsg","not support dev server");
            return new ModelAndView("jsonView", resultMap);
    	}
    	
		HashMap<String,String> map = new HashMap<String,String>();
		
		logger.debug("cmFileUpload content-Type="+request.getContentType());
		Properties prop = monitoringContext.getProperties();
		makecmfolder(prop);
		
		String tempPath       = prop.getProperty(MonitoringContext.CM_TEMP_PATH     , "/fslog/eai/eaisvc/temp/");
		String subPath        = DatetimeUtil.getCurrentTimeMillis();

    	String cmFolder = request.getParameter("cmFolder");
    	
    	String eaiSevrName = null; //취약점소스 수정 2020.08.25
    	   if(cmFolder != null) {
    		   eaiSevrName = cmFolder.split("_")[2];
    	   }
		for (String key : request.getParameterMap().keySet()){
			// Multipart Data From Request Object
			String [] datas= request.getParameterValues(key);
			
			StringBuffer resultS = new StringBuffer();
			for(String data : datas){
				resultS.append(data);
			}
			map.put(key, resultS.toString());
		}
		
    	for(Part part : request.getParts()){
    		String key = part.getName();
    		logger.debug("part key : " + key);
    		String[] keys = key.split("_",2);
    		if (keys.length != 2){
    			throw new Exception("name("+key+") path error ");
    		}
    		//temp folder download
    		String tempDownloadPath = tempPath + subPath + File.separator + keys[0] +File.separator;
    		FileWriteUtil.FileWrite(tempDownloadPath, keys[1], (String)map.get(key));
    	}
    	//적용
		DataSourceType dt = null;
		if(eaiSevrName != null){  //취약점소스 수정 2020.08.26
			dt = DataSourceTypeManager.getDataSourceType(eaiSevrName);
		}
		if (dt == null){
			logger.info("not support eaiSevrName : "+ eaiSevrName);
			throw new Exception("not support eaiSevrName : "+ eaiSevrName);
		}
		DataSourceContextHolder.setDataSourceType(dt);
		logger.debug("cmFileUpload folder path =" + tempPath + subPath);
		File f = new File(tempPath + subPath);
		File[] typeDirs = f.listFiles();
		logger.debug("folder list : " + typeDirs);
		HashMap<String,ArrayList<String>> syncData = null;
		try{
			 if(typeDirs != null) {//취약점소스 수정 2020.08.25
				 syncData = eaiCmReflectionService.insertFileData(dt,typeDirs);
			 }
		}catch(Exception e){
			HashMap resultMap = new HashMap();
			resultMap.put("status", "fail");
			resultMap.put("errorMsg", e.getMessage());
			return new ModelAndView("jsonView", resultMap);
		}
		for(String key : syncData.keySet()){
			if (FileWriteUtil.INTERFACE.equals(key)){
				if(syncData != null){  //취약점소스 수정 2020.08.26
					eaiCmReflectionService.interfaceMemorySync(syncData.get(key),syncData.get(key+"EXT"));
				}
			}else if (FileWriteUtil.B2B.equals(key)){
				if(syncData != null){ //취약점소스 수정 2020.08.26
					eaiCmReflectionService.b2bMemorySync(syncData.get(key));
				}
			}else if (FileWriteUtil.ADAPTER.equals(key) || FileWriteUtil.MESSAGEKEY.equals(key)) {
				//메모리동기화 화면 안됨==> 어댑터 메시지키 만 동기화
				eaiCmReflectionService.adapterMemorySync(syncData.get(key));
				;
			}
		}
		if (f.isDirectory()){
			FileUtils.deleteDirectory(f);
		}
    	
        HashMap resultMap = new HashMap();
        resultMap.put("status", "success");
        
        return new ModelAndView("jsonView", resultMap);
        

    }

    /**
     * CM File Upload List 관련 컨트롤러
     * *
     * @param request
     * @param response
     * @param schema
     * @return
     * @throws Exception
     */
    @RequestMapping(value= "/cmFileUpload.file",params = "cmd=select", method=RequestMethod.POST)
    public ModelAndView selectFileList(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	
        UserAccessLogger.log(request, "Message", "L", "");
    	if (SystemUtil.isDevServer()) {
            HashMap resultMap = new HashMap();
            resultMap.put("status", "fail");
            resultMap.put("errorMsg","not support dev server");
            return new ModelAndView("jsonView", resultMap);
    	}        
		List<String> list = new ArrayList<String>();
		
		logger.debug("cmFileUpload content-Type="+request.getContentType());
		Properties prop = monitoringContext.getProperties();
		makecmfolder(prop);

		String downloadPath   = prop.getProperty(MonitoringContext.CM_DOWNLOAD_PATH, "/dat/eaiData/engineData/download/");

    	//download folder select
    	File downloadFolder = new File(downloadPath);
    	if (downloadFolder != null){
    		for(File f : downloadFolder.listFiles()){
    			if (f.exists()){
    				list.add(f.getName());
    			}
    		}
    	}
		Map resultMap = new HashMap();
		resultMap.put("rows"   , list);
		return new ModelAndView("jsonView",resultMap);		
    }    
    /**
     * CM File Upload List 관련 컨트롤러
     * *
     * @param request
     * @param response
     * @param schema
     * @return
     * @throws Exception
     */
    @RequestMapping(value= "/cmFileUpload.file",params = "cmd=detail", method=RequestMethod.POST)
    public ModelAndView selectFileDetail(HttpServletRequest request, HttpServletResponse response) throws Exception {
		Map<String, List<Map<String, String>>> ret = new HashMap<String, List<Map<String, String>>>();
    	
    	UserAccessLogger.log(request, "Message", "L", "");
    	if (SystemUtil.isDevServer()){
            HashMap resultMap = new HashMap();
            resultMap.put("status", "fail");
            resultMap.put("errorMsg","not support dev server");
            return new ModelAndView("jsonView", resultMap);
    	}    	
    	//List<String> list = new ArrayList<String>();
    	
    	logger.debug("cmFileUpload content-Type="+request.getContentType());
    	Properties prop = 	monitoringContext.getProperties();
    	makecmfolder(prop);
    	
    	String downloadPath   = prop.getProperty(MonitoringContext.CM_DOWNLOAD_PATH, "/dat/eaiData/engineData/download/");
    	String fileName       = request.getParameter("fileName");

    	//download folder select
    	File f = new File(downloadPath + fileName);
		File[] folders = f.listFiles();
		if(folders != null){ //취약점소스 수정 2020.08.26
			for (File folder : folders){
				if (FileWriteUtil.INTERFACE.equals(folder.getName())){
					File[] files = folder.listFiles();
					if(files != null) {//취약점소스 수정 2020.08.25
						for(File file : files){
							HashMap map = loaderService.parse(file.getAbsolutePath());
							dataPut(ret, map,"TSEAIHE01","EAISVCNAME","EAISvcCode");
							dataPut(ret, map,"TSEAIFR03","EAISVCNAME","FieldInfo");
							dataPut(ret, map,"TSEAIHS04","BZWKSVCKEYNAME","KBStdCode");
							dataPut(ret, map,"TSEAIFR06","EAISVCNAME","B2BExt");
						}
					}
				}else if  (FileWriteUtil.B2B.equals(folder.getName())){
					File[] files = folder.listFiles();
					if(files != null){  //취약점소스 수정 2020.08.26
						for(File file : files){
							HashMap map = loaderService.parse(file.getAbsolutePath());
							dataPut(ret, map,"TSEAIHE03","EXTNLINSTIIDNFINAME","B2BSvc");
						}
					}
					
				}
			}
		}
		
		
		for(String key : ret.keySet()){
			List<Map<String, String>> retData = (List<Map<String, String>>) ret.get(key);
			if(retData != null && retData.size() > 0){//취약점소스 수정 2020.08.27
				List<Map<String,String>> list2 = (ArrayList<Map<String, String>>) retData.parallelStream().distinct().collect(Collectors.toList());
				ret.replace(key, list2);
					
			}
		}
    	return new ModelAndView("jsonView",ret);		
    }    
    /**
     * CM File Upload List 관련 컨트롤러
     * *
     * @param request
     * @param response
     * @param schema
     * @return
     * @throws Exception
     */
    @RequestMapping(value= "/cmFileUpload.file",params = "cmd=delete", method=RequestMethod.POST)
    public ModelAndView deleteFileList(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	
        UserAccessLogger.log(request, "Message", "L", "");
    	if (SystemUtil.isDevServer()){
            HashMap resultMap = new HashMap();
            resultMap.put("status", "fail");
            resultMap.put("errorMsg","not support dev server");
            return new ModelAndView("jsonView", resultMap);
    	}        
		logger.debug("cmFileUpload content-Type="+request.getContentType());
		Properties prop = monitoringContext.getProperties();
		makecmfolder(prop);
		
		String downloadPath   = prop.getProperty(MonitoringContext.CM_DOWNLOAD_PATH, "/dat/eaiData/engineData/download/");
        String fileList       = request.getParameter("fileList");
        
        String [] fileLists   = null;  //취약점소스 수정 2020.08.25
        if(fileList != null) {
        	fileLists   = fileList.split("\\&");
        }

        if(fileLists != null){ //취약점소스 수정 2020.08.26
        	for(String fileName : fileLists){
        		if (StringUtils.isBlank(fileName)) {
        			continue;
        		}
        		File f = new File(downloadPath + File.separator + fileName);
        		if (!f.exists()){
        			throw new Exception("folder("+f.getAbsolutePath()+") 가 존재 하지 않습니다.");
        		}
        		if (f.isDirectory()){
        			FileUtils.deleteDirectory(f);
        		}
        	}
        }
    	
		Map resultMap = new HashMap();
		resultMap.put("status"   , "success");
		return new ModelAndView("jsonView",resultMap);	
    }    

	private void dataPut(Map<String, List<Map<String, String>>> result, HashMap parsingMap, String tableName, String keyColumn, String hashKey){
		List<Map<String,String>> data = null;
		List<HashMap> list = (List<HashMap>)parsingMap.get(tableName);
		if (list != null && list.size() > 0){
			if (result.containsKey(hashKey)){
				data = result.get(hashKey);
			}else {
				data = new ArrayList<Map<String,String>>();
			}
			for(HashMap m : list){
				if (m.containsKey(keyColumn)){
					 if(data != null) {  //취약점소스 수정 2020.08.25
						 data.add(new HashMap(){{put("CODE",(String)m.get(keyColumn));}});
					 }
				}
			}
			result.put(hashKey, data);
		}
	}
	private void makecmfolder(Properties prop) throws Exception{
		ArrayList<String> list = new ArrayList<String>();
		list.add(prop.getProperty(MonitoringContext.CM_DOWNLOAD_PATH , "/dat/eaiData/engineData/download/"));
		list.add(prop.getProperty(MonitoringContext.CM_TEMP_PATH     , "/dat/eaiData/engineData/temp/"));
		list.add(prop.getProperty(MonitoringContext.CM_BACKUP_PATH   , "/dat/eaiData/engineData/backup/"));
		list.add(prop.getProperty(MonitoringContext.CM_AFTER_PATH    , "/dat/eaiData/engineData/after/"));
		for(String path : list){
			File directory = new File(path);
			if (!directory.exists()){
				if (!directory.mkdirs()){
					throw new Exception("디렉토리 생성 오류입니다."+path);
				}
			}
		}
	}
    //1.File에 존재 하는 어댑터 추출
	//2.File에 존재 하는 interface 어댑터를 validation하는 로직
    private void interfaceAdapterValidate(DataSourceType dt,String path) throws Exception{
    	//1.어댑터 목록 확인
    	//2.인터페이스 어댑터 확인
    	//3.인터페이스의 어댑터 인스턴스 확인
    	//4.메시지키 단독일 때 
    	HashSet adapters = new HashSet<String>();
    	File adapterFolder = new File(path + FileWriteUtil.ADAPTER );
    	if (adapterFolder != null && adapterFolder.isDirectory()){
    		for(File f : adapterFolder.listFiles()){
    			if ( f.exists()){
    				String fileName = f.getName();
    				if (!StringUtils.isBlank(fileName) && fileName.endsWith(FileWriteUtil.EXT_TXT)){
    					fileName = fileName.substring(0,fileName.length()-4);
    				}
    				adapters.add(fileName);
    			}
    		}
    	}
    	//인터페이스 
    	File interfaceFolder = new File(path + FileWriteUtil.INTERFACE );
    	if (interfaceFolder != null && interfaceFolder.isDirectory()){
    		for(File f : interfaceFolder.listFiles()){
    			if ( f.exists()){
    				HashMap map =loaderService.parse(f.getAbsolutePath());
    				HashSet<String> interfaceAdapters = loaderService.getFileInterfaceAdapterList(map);
    				interfaceAdapters.removeAll(adapters);
    				if (interfaceAdapters.size()==0) continue;
    				HashSet<String> selectAdapters = new HashSet<String>();
    				//DB 쿼리
    				List<LinkedHashMap> dbList = loaderService.selectTableDataForListValue(dt, "TSEAIAD01", "ADPTRBZWKGROUPNAME", new ArrayList(interfaceAdapters));
    				for(LinkedHashMap lmap : dbList){
    					selectAdapters.add((String)lmap.get("ADPTRBZWKGROUPNAME"));
    				}
    				interfaceAdapters.removeAll(selectAdapters);
    				if(interfaceAdapters.size() !=0 ){
    					throw new Exception("어댑터가 해당서버에 존재하지 않습니다. "+interfaceAdapters.toString());
    				}
    				//어댑터 인스턴스비교
    				loaderService.adptInstValid(dt,map);
    			}
    		}
    	}    	
    	File b2bFolder = new File(path + FileWriteUtil.B2B );
    	if (b2bFolder != null && b2bFolder.isDirectory()){
    		for(File f : b2bFolder.listFiles()){
    			if ( f.exists()){
    				HashMap map =loaderService.parse(f.getAbsolutePath());
					loaderService.adapterGroupValid(dt, map, "TSEAIHE03");
    			}
    		}
    	}
    	
    	File messageKeyFolder = new File(path + FileWriteUtil.MESSAGEKEY );
    	if (messageKeyFolder != null && messageKeyFolder.isDirectory()){
    		for(File f : messageKeyFolder.listFiles()){
    			if ( f.exists()){
    				HashMap map =loaderService.parse(f.getAbsolutePath());
					loaderService.adapterGroupValid(dt, map, "TSEAIFR04");
    			}
    		}
    	}
    }
}
