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

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.onl.common.service.DashboardTargetService;
import com.eactive.eai.rms.onl.common.service.EaiServerInfoService;
import com.eactive.eai.rms.onl.dashboard.repository.Dashboard2Repository;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.EAIEngineStatusVo;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;

@Service("dashboard2RepositoryService")
public class Dashboard2RepositoryService {

	private static final Logger logger = Logger.getLogger(Dashboard2RepositoryService.class);

	/** The monitoring context. */
	@Autowired
	@Qualifier("monitoringContext")
	private transient MonitoringContext monitoringContext;

	/** The eai server info service. */
	@Autowired
	@Qualifier("eaiServerInfoService")
	private EaiServerInfoService eaiServerInfoService;

	/** The dashboard target service. */
	@Autowired
	@Qualifier("DashboardTargetService")
	private DashboardTargetService dashboadTargetService;

	@Autowired
	@Qualifier("dashboard2Repository")
	private Dashboard2Repository dashboardRepository;

	// hostNames, instNames 초기화 여부
	private boolean isInitHostInstName = false;

	// EAISevrDstcd 초기화 여부
	private boolean isInitEAISevrDstcd = false;

	private boolean isInitTargetService = false;
	private String  dashTargetService   = ""   ;

	public void initTargetService() {
		if( isInitTargetService == false ) {
			dashTargetService = getTargetService();
			isInitTargetService = true ;
		}
	}

	public String getDashTargetService() {
		initTargetService();
		return dashTargetService ;
	}


	/**
	 * repository 데이터를 초기화 한다.
	 * ( 날짜가 변경선을 지난 경우 등에 해당한다. )
	 */
	public void initMemTrRepository() {
		dashboardRepository.initMemTrRepository();
		initHostInstNames(true, null);
		initEaiSevrDstcd(true);
	}

	public void checkMemTrRepository() {
		dashboardRepository.checkMemTrRepository();
	}

	public void removeMemTrRepository( String host, String inst ) {
		dashboardRepository.removeMemTrRepository(host, inst);
	}


	/**
	 * 서비스별 호스트명 리스트를 맵에 추가한다.
	 * @param service
	 * @param list
	 */
	public void setHostNames(String service, List<String> list ) {
		dashboardRepository.setHostNames(service, list);
	}

	/**
	 * 호스트별 인스턴스명 리스트를 맵에 추가한다.
	 * @param host
	 * @param list
	 */
	public void setInstNames(String host, List<String> list ) {
		dashboardRepository.setInstNames(host, list);
	}

	/**
	 * Repository 에 주어진 서비스를 키로 하여 메모리 거래현황 맵을 추가한다.
	 * @param service
	 * @param map
	 */
	public void setItsmDashTranInfo(String service, HashMap<String,String> map) {
		dashboardRepository.setItsmDashTranInfo(service, map);
	}

	public void setItsmDashPeakdayInfo(String service, HashMap<String,String> map) {
		dashboardRepository.setItsmDashPeakdayInfo(service, map);
	}

	/**
	 * 주어진 서비스명으로  메모리에서 읽어온 맵을 리턴한다.
	 * @param service
	 * @return
	 */
	public HashMap<String,String> getItsmDashTranInfo(String service) {
		return dashboardRepository.getItsmDashTranInfo(service);
	}

	/**
	 * Repository 에 주어진 서비스를 키로 하여 메모리 거래현황 맵을 추가한다.
	 * @param service
	 * @param map
	 */
	public void setItsmDashHourTranList(String service, List list) {
		dashboardRepository.setItsmDashHourTranList(service, list);
	}


	public void setItsmDashDayTranList(String service, List list) {
		dashboardRepository.setItsmDashDayTranList(service, list);
	}

	public void setItsmDashBizErrorMap(HashMap<String, HashMap<String, String>> map) {
		dashboardRepository.setItsmDashBizErrorMap(map);
	}


	public void setItsmDashTimeoutErrorMap(HashMap<String, HashMap<String, String>> map) {
		dashboardRepository.setItsmDashTimeoutErrorMap(map);
	}

	public void setItsmDashConnectErrorMap(HashMap<String, HashMap<String, String>> map) {
		dashboardRepository.setItsmDashConnectErrorMap(map);
	}

	public void setItsmDashServerInstTotalProcMap(String service,HashMap<String,String> map) {
		dashboardRepository.setItsmDashServerInstTotalProcMap(service,map);
	}

	public void setItsmDashTranInfoBatch( String batchCount ) {
		dashboardRepository.setItsmDashTranInfoBatch(batchCount) ;
	}

	public void setItsmDashTranInfoBatch2( String batchCount2 ) {
		dashboardRepository.setItsmDashTranInfoBatch2(batchCount2) ;
	}

	public void setItsmDashFepBatchErrorList(HashMap<String,HashMap<String,String>> fepBatchErrorList) {
		dashboardRepository.setItsmDashFepBatchErrorList(fepBatchErrorList);
	}

	public HashMap<String, HashMap<String, String>> getAllDashErrorMap() {

		HashMap<String, HashMap<String, String>> result = new HashMap<>();

		result.putAll(dashboardRepository.itsmDashBizErrorMap());
		result.putAll(dashboardRepository.itsmDashTimeoutErrorMap());
		result.putAll(dashboardRepository.itsmDashConnectErrorMap());
		result.putAll(dashboardRepository.itsmDashEaiBatchErrorList());
		result.putAll(dashboardRepository.itsmDashFepBatchErrorList());

		return result;
	}


	/**
	 * 대시보드타겟 서비스가 ALL 인경우 EAI 서버구분코드값을 정할때,
	 * EAISevrDstcd 필드를 사용하지 않고 DB 로 구분한다.
	 * @param dataSourceType
	 * @param targetService
	 * @param map
	 */
	private HashMap<String,String> reinitEaiSevrDstcd(DataSourceType dataSourceType, String targetService, HashMap<String,String> map ) {

		HashMap<String,String> retMap = new HashMap<String,String>();

		if( "ALL".equals(targetService) ) {
			String eaiSevrDstcd = "" ;

			if( DataSourceTypeManager.MCI.equals(dataSourceType.getName()) ) {
				eaiSevrDstcd = DataSourceTypeManager.MCI; // MCI
			} else if( DataSourceTypeManager.MCU.equals(dataSourceType.getName()) ) {
				eaiSevrDstcd = DataSourceTypeManager.MCU ; // MCU
			} else if( DataSourceTypeManager.EAI.equals(dataSourceType.getName()) ) {
				eaiSevrDstcd = DataSourceTypeManager.EAI ; // EAI
			} else if( DataSourceTypeManager.FEP.equals(dataSourceType.getName()) ) {
				eaiSevrDstcd = DataSourceTypeManager.FEP ; // FEP
			} else if( DataSourceTypeManager.OPA.equals(dataSourceType.getName()) ) {
				eaiSevrDstcd = DataSourceTypeManager.OPA ; // OPA
			}  else if( DataSourceTypeManager.APIGW.equals(dataSourceType.getName()) ) {
				eaiSevrDstcd = DataSourceTypeManager.APIGW ; // APIGW
			}   else if( DataSourceTypeManager.BAP.equals(dataSourceType.getName()) ) {
				eaiSevrDstcd = DataSourceTypeManager.BAP ; // BAP
			} else {
				return map;
			}

			Iterator<String> it = map.keySet().iterator();
			while( it.hasNext() ) {
				String eaiSvcName = it.next();
				retMap.put(eaiSvcName, eaiSevrDstcd);
			}
		} else {
			return map ;
		}

		return retMap ;
	}

	/**
	 * 각 서비스별 EAI서비스코드(EAISvcName) 와 서버구분코드(EAISevrDstcd) 값을 초기화 한다.
	 * @param isForceOverwrite
	 */
	public void initEaiSevrDstcd( boolean isForceOverwrite ) {
		if( isForceOverwrite == false ) {
			if( isInitEAISevrDstcd == true ) {
				return ;
			}
		}

		HashMap<String,String> map = null;

		String targetService = getDashTargetService();
		if( targetService == null || "".equals(targetService) ) {
			targetService = "ALL" ;
		}
		for (DataSourceType d : DataSourceTypeManager.getOnlineDataSourceTypes()){
			try {

				DataSourceContextHolder.setDataSourceType(d);
				map = dashboadTargetService.selectEAISevrDstcd();
				map = reinitEaiSevrDstcd(d, targetService, map );
				dashboardRepository.setRepoEAISevrDstcd(d.getName(), map);
			} catch ( Exception e ) {
				//e.printStackTrace();
				logger.error("initEaiSevrDstcd error", e);
			}
		}

		isInitEAISevrDstcd = true ;
	}

	public DataSourceType getServiceTypeByHost(String host) {
		return dashboardRepository.getServiceTypeByHost(host);
	}

	public boolean isValidHost( String host ) {
// FIXME : CLOUD_ENV 환경에서는 check 하지 않도록 함
//		if( null == dashboardRepository.getServiceTypeByHost(host) ) {
//			return false;
//		}

		return true;
	}

	/**
	 * 호스트명, 인스턴스명 을 초기화 한다.
	 * @param isForceOverwrite
	 */
	public void initDefaultHostInstNames( boolean isForceOverwrite ) {
		if( isForceOverwrite == false ) {
			if( isInitHostInstName == true ) {
				return ;
			}
		}

		List<Map<String,String>> listTmp = null ;
		List<String> hostList = new ArrayList<String>();
		HashMap<String,List<String>> mapInst = new HashMap<String,List<String>>();

		for (DataSourceType d :DataSourceTypeManager.getOnlineDataSourceTypes()){
			try {
				DataSourceContextHolder.setDataSourceType(d);
				listTmp = eaiServerInfoService.getEaiServerIpListDB();
				hostList.clear();
				for( Map<String, String> map : listTmp ) {
					String host = map.get("HOSTNAME") ;
					String inst = map.get("EAISVRINSTNM");
					hostList.add(host);

					List<String> l = mapInst.get(host);
					if( l == null ) {
						l = new ArrayList<String>();
					}
					l.add( inst );
					mapInst.put(host, l);
				}

				List<String> hostSide = CommonUtil.getDistinctList(hostList, true);
				setHostNames(d.getName(), hostSide);
				if( hostSide != null ) {
					for( String host : hostSide ) {
						List<String> l = mapInst.get(host);
						if( l != null ) {
							l = CommonUtil.getDistinctList(l, true);
							setInstNames(host, l);
						}
					}
				}
			}
			catch(Exception e) {
				logger.warn("Fail to get DataSourceType = " + d.getJndiName(), e);
			}
		}

		isInitHostInstName = true ;
	}

	public void setMemTradeVo(String host, String inst, MemStaticsVo vo) {
		logger.info("host=" + host +", inst="+ inst +", MemStaticsVo="+vo);
		dashboardRepository.setMemTradeVo(host, inst, vo);
	}

	public MemStaticsVo getMemTradeVo(String host, String inst) {
		return dashboardRepository.getMemTradeVo(host, inst);
	}

	public MemStaticsVo getMemTradeVoByHost(String host,List<Map<String, String>> ipList) {
		HashMap<String, String> instMap = new HashMap<String, String>();
		if( ipList != null ) {
			for( Map<String,String> map : ipList ) {
				String inst = map.get("EAISVRINSTNM");
				instMap.put(inst, inst);
			}
		}

		MemStaticsVo totalVo = new MemStaticsVo();
		totalVo.setHostName(host);

		List<MemStaticsVo> list = dashboardRepository.getMemTradeVoByHost(host);
		if( list != null ) {
			for( MemStaticsVo vo : list ) {
				if( instMap.get(vo.getInstName()) != null ) {
					totalVo.add(vo);
				}

				if( logger.isDebugEnabled() ) {
					logger.debug( "host=" + host + ", procIn=" + vo.getProcIn() + ", procOut=" + vo.getProcOut());
				}
			}
		} else {
			logger.warn("MEM_TRADE_REPOSITORY : list is null !(host=" + host + ")");

		}

		return totalVo;
	}

	public MemStaticsVo getMemTradeVoByHost(String host) {
		MemStaticsVo totalVo = new MemStaticsVo();
		totalVo.setHostName(host);

		List<MemStaticsVo> list = dashboardRepository.getMemTradeVoByHost(host);
		if( list != null ) {
			for( MemStaticsVo vo : list ) {
				totalVo.add(vo);
				if( logger.isDebugEnabled() ) {
					logger.debug( "host=" + host + ", procIn=" + vo.getProcIn() + ", procOut=" + vo.getProcOut());
				}
			}
		} else {
			logger.warn("MEM_TRADE_REPOSITORY : list is null !(host=" + host + ")");

		}

		return totalVo;
	}

	public MemStaticsVo getMemTradeVoByHost(String host, String inst) {
		MemStaticsVo totalVo = new MemStaticsVo();
		totalVo.setHostName(host);
		totalVo.setInstName(inst);

		List<MemStaticsVo> list = dashboardRepository.getMemTradeVoByHost(host);
		if( list != null ) {
			for( MemStaticsVo vo : list ) {
				if(vo.getInstName().equals(inst)) {
					totalVo.add(vo);
				}

				if( logger.isDebugEnabled() ) {
					logger.debug( "host=" + host + ", procIn=" + vo.getProcIn() + ", procOut=" + vo.getProcOut());
				}
			}
		} else {
			logger.warn("MEM_TRADE_REPOSITORY : list is null !(host=" + host + ")");
		}

		return totalVo;
	}

	public MemStaticsVo getDefaultMemTradeVoByService(String service) {
		MemStaticsVo totalVo = new MemStaticsVo();

		List<MemStaticsVo> list = dashboardRepository.getMemTradeVoByService(service);

		List<String >instList = new ArrayList<String>();
		List<Map<String, String>>iplist = eaiServerInfoService.getEaiServerIpListDB();
		if( list != null ) {
			for( Map<String,String> map : iplist ) {
				String inst = map.get("EAISVRINSTNM");
				instList.add(inst);
			}
		}
		if( list != null ) {
			for( MemStaticsVo vo : list ) {
				for(String inst : instList) {
					if( vo.getInstName().equals(inst)) {
						totalVo.add(vo);
						//						break;
					}
				}
			}
		}

		return totalVo;
	}


	public void initHostAlive() {
		if( dashboardRepository.isInitHostRepository() ) {
			return ;
		}
		//동적
		for(DataSourceType d : DataSourceTypeManager.getOnlineDataSourceTypes()){
			DataSourceContextHolder.setDataSourceType(d);  // 스케쥴러에서만 initHostAlive 를 쓰므로 Datasource를 미리 할당해준다.

			List<Map<String,String>> list = null ;
			list = eaiServerInfoService.getEaiServerIpListDB();
			ArrayList<String> listHost = new ArrayList<String>();
			for( Map<String,String> map : list ) {
				//String inst = map.get("EAISVRINSTNM");
				String ip   = map.get("EAISVRIP");
				String port = map.get("EAISVRLSNPORT");
				//String host = map.get("HOSTNAME");

				listHost.add( ip + ":" + port ); // 참고 : 중복된 ip 가 있을 수 있으나, 맵에 추가하기에 상관없음.
			}

			dashboardRepository.addHostKey( listHost );

		}
		//BATCH
		List<Map<String,String>> list = null ;
		DataSourceType d = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAT);
		if (d != null){
			list = eaiServerInfoService.getEaiServerIpListDB();
		}
		ArrayList<String> listHost = new ArrayList<String>();

		if(list != null) {
			for( Map<String,String> map : list ) { //취약점소스 수정 2020.08.25
				//String inst = map.get("EAISVRINSTNM");
				String ip   = map.get("EAISVRIP");
				String port = map.get("EAISVRLSNPORT");
				//String host = map.get("HOSTNAME");
				listHost.add( ip + ":" + port ); // 참고 : 중복된 ip 가 있을 수 있으나, 맵에 추가하기에 상관없음.
			}
		}

		dashboardRepository.addHostKey( listHost );
	}

	public List<String> getHostIPList() {
		return dashboardRepository.getHostIPList();
	}

	public List<String> getHostNames(String service) {
		return dashboardRepository.getHostNames(service);
	}

	public boolean isHostAlive(String ipaddress, String port) {
		return dashboardRepository.isHostAlive(ipaddress, port);
	}

	public boolean isHostAlive(String ipaddress) {
		return dashboardRepository.isHostAlive(ipaddress);
	}

	// 해당 IP 의 인스턴스중 한개만 살아 있어도 true
	public String getHostAlive( String ipaddress ) {
		if( isHostAlive(ipaddress) ) {
			return "1" ;
		} else {
			return "0" ;
		}
	}

	public void setHostAlive(String ipaddress, String port, boolean alive) {
		dashboardRepository.setHostAlive(ipaddress, port, alive);
	}

	public void setPeakTps(String service, String val) {
		dashboardRepository.setPeakTps(service, val);
	}

	public void reloadPeakTpsTrade( ) {
		DataSourceType ds = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING);
		DataSourceContextHolder.setDataSourceType(ds);
		// PEAK TPS
		monitoringContext.refresh(MonitoringContext.RMS_PEAK_TPS);		// RMS_PEAK_TPS의 property값을 DB에 있는 값으로 리셋
		String prop = monitoringContext.getStringProperty(MonitoringContext.RMS_PEAK_TPS,"");
		if( prop == null || "".equals(prop)) {
			logger.error("RMS_PAEK_TPS value not found.");
		} else {
			String[] lines = prop.split(";");
			for( String line : lines ) {
				String [] data = line.split(",");
				if( data.length > 2 ) {
					dashboardRepository.setPeakTps(data[0], line);
				}
			}
		}

		// PEAK TRADE
		monitoringContext.refresh(MonitoringContext.RMS_PEAK_TRADE);	// RMS_PEAK_TRADE의 property값을 DB에 있는 값으로 리셋
		prop = monitoringContext.getStringProperty(MonitoringContext.RMS_PEAK_TRADE,"");
		if( prop == null || "".equals(prop)) {
			logger.error("RMS_PEAK_TRADE value not found.");
		} else {
			String[] lines = prop.split(";");
			for( String line : lines ) {
				String [] data = line.split(",");
				if( data.length > 2 ) {
					dashboardRepository.setPeakTrade(data[0], line);
				}
			}
		}
	}

	public String getPeakTps(String service) {
		String val = dashboardRepository.getPeakTps(service);

		if( val == null || "".equals(val) ) {
			String m = monitoringContext.getStringProperty(MonitoringContext.RMS_PEAK_TPS,"");
			String[] lines = m.split(";");
			for( String line : lines ) {
				String [] data = line.split(",");
				if( data.length > 3 && service.equals(data[0]) ) {
					dashboardRepository.setPeakTps(service, line);
					return line ;
				}
			}
		}

		return val ;
	}

	public String getPeakTpsAll() {
		StringBuffer sb = new StringBuffer();
		String val ="";
		for (DataSourceType d : DataSourceTypeManager.getOnlineDataSourceTypes()){
			val = dashboardRepository.getPeakTps(d.getName() );
			sb.append( CommonUtil.rightTrim(val, ",") ).append(";");
		}
		DataSourceType d =  DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAP);
		if(d != null) {
			val = dashboardRepository.getPeakTps(d.getName() );
			sb.append( CommonUtil.rightTrim(val, ",") ).append(";");
		}
		DataSourceType d2 =  DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAT);
		if(d2 != null) {
			val = dashboardRepository.getPeakTps(d2.getName());
			sb.append( CommonUtil.rightTrim(val, ",") ).append(";");
		}
		return sb.toString();
	}

	public void setPeakTrade(String service, String val) {
		dashboardRepository.setPeakTrade(service, val);
	}

	public String getPeakTrade(String service) {
		String val = dashboardRepository.getPeakTrade(service);

		if( val == null || "".equals(val) ) {
			String m = monitoringContext.getStringProperty(MonitoringContext.RMS_PEAK_TRADE,"");
			String[] lines = m.split(";");
			for( String line : lines ) {
				String [] data = line.split(",");
				if( data.length > 2 && service.equals(data[0]) ) {
					return line ;
				}
			}
		}

		return val ;
	}

	public String getPeakTradeAll() {
		StringBuffer sb = new StringBuffer();
		String val = "";
		for (DataSourceType d : DataSourceTypeManager.getOnlineDataSourceTypes()){
			val = dashboardRepository.getPeakTrade(d.getName() );
			sb.append( CommonUtil.rightTrim(val, ",") ).append(";");
		}
		DataSourceType d =  DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAP);
		if(d != null) {
			val = dashboardRepository.getPeakTrade(d.getName() );
			sb.append( CommonUtil.rightTrim(val, ",") ).append(";");
		}
		DataSourceType d2 =  DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAT);
		if(d2 != null) {
			val = dashboardRepository.getPeakTrade(d2.getName());
			sb.append( CommonUtil.rightTrim(val, ",") ).append(";");
		}

		return sb.toString();
	}


	public String getProcBatch( ) {
		return dashboardRepository.getProcBatch();
	}
	public String getProcEaiBatch( ) {
		return dashboardRepository.getProcEaiBatch();
	}

	public void setProcBatch( int[] p ) {
		if( p != null && p.length == 6 )
			dashboardRepository.setProcBatch( p[0], p[1], p[2], p[3], p[4], p[5] );
	}

	public void setProcEaiBatch( int[] p ) {
		if( p != null && p.length == 6 )
			dashboardRepository.setProcEaiBatch( p[0], p[1], p[2], p[3], p[4], p[5] );
	}


	private String getTargetService() {
		String local = "";
		try {
			InetAddress addr = InetAddress.getLocalHost();
			local = addr.getHostAddress();
		} catch ( UnknownHostException e ) {
			//e.printStackTrace();
			logger.error("getTargetService error", e);
		}

		// 타겟서비스에 해당하는 DB 의 거래현황 데이터를 읽어서 해당DB 의 RM11 테이블에 집계데이터를 추가한다.
		// ALL : 온라인용 ( 전체 서비스 )
		// OUTSIDE : 테스트용  ( ZAUA - 192.168.175.82 )
		// COMMON  : 테스트용  ( ZAPA - 192.168.175.54 )
		// 현재 사용되고 있지 않은곳이 내부(ZADA) 이므로 일단 ALL 데이터는 ZADA 로 WRITE 한다.
		String targetSvc = "ALL" ;
		String target = monitoringContext.getStringProperty(MonitoringContext.RMS_TRADE_COUNT_TARGET, "");
		String arrTmp[] = target.split(",");
		if( arrTmp != null && arrTmp.length > 0 ) {
			for( int i = 0 ; i < arrTmp.length ; i++ ) {
				String arrTmp2[] = arrTmp[i].split("=");
				if( arrTmp2 != null && arrTmp2.length == 2 && local.equals(arrTmp2[0]) ) {
					targetSvc = arrTmp2[1];
					break;
				}
			}
		}

		return targetSvc ;
	}

	public MemStaticsVo getMemTradeVoByService(String service){
		return this.getDefaultMemTradeVoByService(service);
	}

	public void initHostInstNames(boolean isForceOverwrite, EAIEngineStatusVo vo){
		this.initDefaultHostInstNames(isForceOverwrite);
	}

}
