package com.eactive.eai.common.message;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;

public class EAIMessage implements EAIMessageKeys, Serializable, Comparable<EAIMessage>, Cloneable {

	private static final long serialVersionUID = 1L;

	private		String		eaiSvrInstNm;			// EAI서버인스턴스명[Runtime 정보]                                   - EAIServerInstanceName
	private		String		eaiSvcCd;				// EAI서비스명[TSEAIHE01.EAISvcName]                      - EAIServiceCode
	private		String		svcTmEn;				// 서비스시각유무[TSEAIHE01.SvcHMSEonot]                   - ServiceTimeExistenceOrNot		- [Y|N]
	private		String		svcOgNo;				// 서비스고유번호                                          - ServiceOriginNumber			- [UUID]
	private		String		svcTsmtUsgTp;			// 서비스동기사용구분코드[TSEAIHE01.SvcMotivUseDstcd]       - ServiceTheSameTimeUsgaeType 	- [SYNC|ASYN|AKON]
	private		String		svcPssTp;				// 서비스프로세스구분명[TSEAIHE01.SvcPrcesDsticName]        - ServiceProcessType			- [SINGLE|COMPLEX|PCOMPLEX]
	private		String		flwCntlRtnNm;			// 흐름통제라우팅명[TSEAIHE01.FlowCtrlRoutName]            - FlowControlRoutingName		
	private		String		unifTp;					// 통합구분명[TSEAIHE01.IntgraDsticName]				     - UnificationType				- [ONLINE|BATCH|FTP]
	private		String		sngSvcCls;				// 기동서비스구분                                          - StartingServiceClassification	- [TIMER|EXCEPTION]
	private		int			svcPssSeq	= 1;		// 서비스처리순서                                          - ServiceProcessSequence		- [1,2,3, etc]
	private		int			logPssSno;				// 로그처리일련번호                                         - LogProcessSequenceNUmber		- [100,200,300,400 | 100,211,212,221,222,...,400]
	private		String		svcWlColLogYn;			// 서비스전컬럼로그여부[TSEAIHE01.SvcBfClmnLogYn]           - ServiceWholeColumnLogYesOrNo	- [Y|N]
	private		String		internalExternalDvcd;	// 서비스전컬럼로그여부[TSEAIHE01.internalExternalDvcd]     - [1|2]
	private		String		bwkCls;					// EAI업무구분코드[TSEAIHE01.EAIBzwkDstcd]                 - BusinessWorkClassification	- 3|4자리 KB표준업무구분코드 사용
	private		String		stdMsgUsgCls;			// 표준메시지사용구분[Runtime 정보]                                   - StandardMessageUsageClassification - [Y|N]
	private		String		sngSysItfTp;			// 기동시스템어댑터업무그룹명[TSEAIHE01.GstatSysAdptrBzwkGroupName]                              - StartingSystemInterfaceType	- [Adapter_업무명_IN]
	private		String		lydMsgID;				// 레이어메시지ID                                           - vlf		
	private		String		rspErrCd;				// 응답에러코드                                            - ResponseErrorCode				- [12 BYTE EAI에러코드]
	private		int			statErrorCode = 0;		// 통계용 에러코드 (0:정상, 1:업무에러, 2:타임아웃, 3:시스템에러)
	private		String		rspErrMsg;				// 응답에러메시지                                          - ResponseErrorMessage			- [ 200 BYTE ]
	private		long		msgRcvTm;				// 메시지수신시각                                           - MessageReceiveTime			- RequestProcessor에서 설정한다.
	private		long		msgPssTm;				// 메시지처리시각                                          - MessageProcessTime			- LOGGER에서 로깅전 설정한다. Queue로 Push하기전에...
	private		int			svrLogLvl;				// 서버로그레벨번호[TSEAIHE01.SevrLogLvelNo]               - ServerLogLevel				- DEFAULT(WARNING, ERROR, FATAL)-0, INFO-1, DEBUG-2
	private		int			svcLogLvl;				// 서비스로그레벨번호[TSEAIHE01.SvcLogLvelNo]			   - ServiceLogLevel				- [0|1|2|3]
	private		List<ServiceMessage>	svcMsgs;	// 서비스처리정보리스트-ArrayList
	
	private InterfaceMapper mapper;
	private StandardMessage standardMessage;
	private StandardMessage subMessage;
    
	private     String      errEAISvcName;           //오류EAI서비스명[TSEAIHE01.ErrEAISvcName]            -ErrorEAIServiceName
    private     String      dmndErrChngIDName;       //요청오류변환ID명[TSEAIHE01.DmndErrChngIDName]       -RequestErrorConversionID
    private     String      dmndErrFldName;         //요청에러필드명[TSEAIHE01.DmndErrFldName]             -RequestErrorColumnName
    private     String      rspnsErrChngIDName;     //응답오류변환ID명[TSEAIHE01.RspnsErrChngIDName]       -ResponseErrorConversionID
    private     String      rspnsErrFldName;        //응답에러필드명[TSEAIHE01.RspnsErrFldName]            -ResponseErrorColumnName
    
    private     String      eaiSvcDesc;              //EAI서비스 설명 [ TSEAIHE01.EAISvcDesc]
	private     String      extBizCd;                //대외업무구분코드[ TSEAIHE01.ExtBizCd]                //경우에따라서는 다른컬럼이 아니라 인터페이스 앞3자리일수 있음 //TODO ※JBBEXT※ 인터페이스앞3자리

	private     String      clientIp;                // 요청 시스템 IP 주소

	/**
	 * EAI서버구분코드 (내부-1/대외-2/공동망-3/DMZ-4/OPEN-5)
	 */
	private String sevrDstcd;

	/**
	 * 그룹회사코드 (KB0/KC0)
	 */
	private String groupCoCd;

	/**
	 * 거래처리구분 (R 실제거래/T TAS/S EAI중단거래/F TAS 기동거래/D 더미단말거래 라우팅됨)
	 */
	private String tranType;

	/**
	 * 응답변환유형(0 기본응답변환, 1 에러응답변환)
	 */
	private String rspnsChngMsgType;

	/**
	 * 거래로그때문에 추가됨 로그용 휘발성 데이터 companyCode : 업체코드 splizLength : 전문길이 adptrInstiCode
	 * : 어댑터기관코드명
	 * 
	 */
	private String companyCode;
	private int splizLength;
	private String adptrInstiCode;
	private String useYn;
	/**
	 * NexCore 용 으로 인터페이스 조회시 참조 txid : 계정계 거래코드 refKey : 대외
	 * 거래코드(대외업무구분코드+전문종별+거래구분코드+기타)
	 */
	private String txId; // 거래ID[ TSEAIHE01.TxId]
	private String refKey;// 참조KEY[ TSEAIHE01.RefKey]
	
    /**
     * Open API 서비스시 client 별 통계용 추가
     */
    private String clientId;

	private String authType;

	private String apiEnabledYn;

	private String apiCacheYn;

	private String apiCacheType;

	private String authkeyfieldname;

	private String authCheckdYn;
	
	private Properties callProp;

	public EAIMessage() {
		this.svcMsgs = new ArrayList<>();
		this.svcPssSeq = 1;
	}

	public String getBwkCls() {
		return bwkCls;
	}

	public void setBwkCls(String bwkCls) {
		this.bwkCls = bwkCls;
	}

	public String getEAISvcCd() {
		return eaiSvcCd;
	}

	public void setEAISvcCd(String svcCd) {
		eaiSvcCd = svcCd;
	}

	public String getEAISvrInstNm() {
		return eaiSvrInstNm;
	}

	public void setEAISvrInstNm(String svrInstNm) {
		eaiSvrInstNm = svrInstNm;
	}

	public String getFlwCntlRtnNm() {
		return flwCntlRtnNm;
	}

	public void setFlwCntlRtnNm(String flwCntlRtnNm) {
		this.flwCntlRtnNm = flwCntlRtnNm;
	}

	public int getLogPssSno() {
		return logPssSno;
	}

	public void setLogPssSno(int logPssSno) {
		this.logPssSno = logPssSno;
	}

	public String getLydMsgID() {
		return lydMsgID;
	}

	public void setLydMsgID(String lydMsgID) {
		this.lydMsgID = lydMsgID;
	}

	public long getMsgPssTm() {
		return msgPssTm;
	}

	public void setMsgPssTm(long msgPssTm) {
		this.msgPssTm = msgPssTm;
	}

	public long getMsgRcvTm() {
		return msgRcvTm;
	}

	public void setMsgRcvTm(long msgRcvTm) {
		this.msgRcvTm = msgRcvTm;
	}

	public String getRspErrCd() {
		return rspErrCd;
	}

	public void setRspErrCd(String rspErrCd) {
		setRspErrCd(rspErrCd, true);
	}

	public void setRspErrCd(String rspErrCd, boolean isSetStandardMessageError) {
		this.rspErrCd = rspErrCd;
		// --------------------------------------------
		// 에러메시지는 뒤의 9자리를 짤라서 설정한다.
		// 에러코드가 아닌경우에는 설정하지 않는다 (RE ,RF )
		// 2008.04.29
		// 2008.07.10 : 8자리로 수정
		// 'S9' + 뒤에 6자리
		// 20080919 - 업무에러일 경우에도 메시지에 설정하도록 수정
		// --------------------------------------------

		if (isSetStandardMessageError && this.mapper != null && this.standardMessage != null && rspErrCd != null && rspErrCd.length() == 12) {
			if (rspErrCd.startsWith("RE") || rspErrCd.startsWith("RF") || rspErrCd.equals(BWK_FAILMSG_CODE)) {
				// migration ExtMessage to StandardMessage
				//getMapper().setErrorCode(standardMessage, rspErrCd);
				StandardMessageManager standardManager = StandardMessageManager.getInstance();
				standardManager.getMessageCoordinator().coordinateSetStandardMessageError(standardMessage, getMapper(), rspErrCd, null);
				getMapper().setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_E);
			}
		}
	}

	public String getRspErrMsg() {
		return rspErrMsg;
	}

	public void setRspErrMsg(String rspErrMsg) {
		this.rspErrMsg = rspErrMsg;

		if (this.mapper != null && this.standardMessage != null && rspErrMsg != null) {
			//getMapper().setErrorMsg(standardMessage, rspErrMsg);
			StandardMessageManager standardManager = StandardMessageManager.getInstance();
			standardManager.getMessageCoordinator().coordinateSetStandardMessageError(standardMessage, getMapper(), null, rspErrMsg);
		}
	}

	public int getStatErrorCode() {
		return statErrorCode;
	}

	public void setStatErrorCode(int statErrorCode) {
		this.statErrorCode = statErrorCode;
	}

	public void setRspErr(String rspErrCd, String rspErrMsg) {
		this.rspErrCd = rspErrCd;
		this.rspErrMsg = rspErrMsg;
		if (this.mapper != null && this.standardMessage != null) {// 표준전문셋팅
			StandardMessageManager standardManager = StandardMessageManager.getInstance();
			String stdErrCd = null;
			String stdErrMsg = null;
			if (rspErrCd != null && rspErrCd.length() == 12 && (rspErrCd.startsWith("RE") || rspErrCd.startsWith("RF") || rspErrCd.equals(BWK_FAILMSG_CODE))) {
				stdErrCd = rspErrCd;
			}
			if (rspErrMsg != null) {
				stdErrMsg = rspErrMsg;
			}
			standardManager.getMessageCoordinator().coordinateSetStandardMessageError(standardMessage, getMapper(),	stdErrCd, stdErrMsg);
		}
	}
	public String getSngSvcCls() {
		return sngSvcCls;
	}

	public void setSngSvcCls(String sngSvcCls) {
		this.sngSvcCls = sngSvcCls;
	}

	public String getSngSysItfTp() {
		return sngSysItfTp;
	}

	public void setSngSysItfTp(String sngSysItfTp) {
		this.sngSysItfTp = sngSysItfTp;
	}

	public String getStdMsgUsgCls() {
		return stdMsgUsgCls;
	}

	public void setStdMsgUsgCls(String stdMsgUsgCls) {
		this.stdMsgUsgCls = stdMsgUsgCls;
	}

	public int getSvcLogLvl() {
		return svcLogLvl;
	}

	public void setSvcLogLvl(int svcLogLvl) {
		this.svcLogLvl = svcLogLvl;
	}

	public List<ServiceMessage> getSvcMsgs() {
		return svcMsgs;
	}

	public void setSvcMsgs(List<ServiceMessage> svcMsgs) {
		this.svcMsgs = svcMsgs;
	}

	public void setSvcMsgs(int pos, ServiceMessage svcMsgs) {
		this.svcMsgs.set(pos, svcMsgs);
	}

	public void addSvcMsg(ServiceMessage svcMsg) {
		this.svcMsgs.add(svcMsg);
	}

	public void removeSvcMsgs() {
		// 제거 후 추가시 에러 방지 - 2008.06.03
		this.svcMsgs.clear();
	}

	public void removeSvcMsg(int pos) {
		this.svcMsgs.remove(pos);
	}

	public ServiceMessage getCurrentSvcMsg() {
		if (getSvcPssSeq() > 0) {
			return this.svcMsgs.get(getSvcPssSeq() - 1);
		} else {
			throw new RuntimeException("EAIMessage] Invalid SvcPssSeq. - " + this.svcPssSeq);
		}
	}

	public ServiceMessage getNextSvcMsg() {
		if (getSvcPssSeq() >= this.svcMsgs.size())
			return null;
		return this.svcMsgs.get(getSvcPssSeq());
	}

	public ServiceMessage getSvcMsg(int i) {
		if (i >= this.svcMsgs.size())
			return null;
		return this.svcMsgs.get(i);
	}

	public String getSvcOgNo() {
		return svcOgNo;
	}

	public void setSvcOgNo(String svcOgNo) {
		this.svcOgNo = svcOgNo;
	}

	public int getSvcPssSeq() {
		return svcPssSeq;
	}

	public void setSvcPssSeq(int svcPssSeq) {
		this.svcPssSeq = svcPssSeq;
	}

	public String getSvcPssTp() {
		return svcPssTp;
	}

	public void setSvcPssTp(String svcPssTp) {
		this.svcPssTp = svcPssTp;
	}

	public String getSvcTmEn() {
		return svcTmEn;
	}

	public void setSvcTmEn(String svcTmEn) {
		this.svcTmEn = svcTmEn;
	}

	public String getSvcTsmtUsgTp() {
		return svcTsmtUsgTp;
	}

	public void setSvcTsmtUsgTp(String svcTsmtUsgTp) {
		this.svcTsmtUsgTp = svcTsmtUsgTp;
	}

	public String getSvcWlColLogYn() {
		return svcWlColLogYn;
	}

	public void setSvcWlColLogYn(String svcWlColLogYn) {
		this.svcWlColLogYn = svcWlColLogYn;
	}

	public int getSvrLogLvl() {
		return svrLogLvl;
	}

	public void setSvrLogLvl(int svrLogLvl) {
		this.svrLogLvl = svrLogLvl;
	}

	public String getUnifTp() {
		return unifTp;
	}

	public void setUnifTp(String unifTp) {
		this.unifTp = unifTp;
	}

	public String getErrEAISvcName() {
		return errEAISvcName;
	}

	public String getDmndErrChngIDName() {
		return dmndErrChngIDName;
	}

	public String getDmndErrFldName() {
		return dmndErrFldName;
	}

	public String getRspnsErrChngIDName() {
		return rspnsErrChngIDName;
	}

	public String getRspnsErrFldName() {
		return rspnsErrFldName;
	}

	public void setErrEAISvcName(String errEAISvcName) {
		this.errEAISvcName = errEAISvcName;
	}

	public void setDmndErrChngIDName(String dmndErrChngIDName) {
		this.dmndErrChngIDName = dmndErrChngIDName;
	}

	public void setDmndErrFldName(String dmndErrFldName) {
		this.dmndErrFldName = dmndErrFldName;
	}

	public void setRspnsErrChngIDName(String rspnsErrChngIDName) {
		this.rspnsErrChngIDName = rspnsErrChngIDName;
	}

	public void setRspnsErrFldName(String rspnsErrFldName) {
		this.rspnsErrFldName = rspnsErrFldName;
	}

	public void setEAISvcDesc(String eaiSvcDesc) {
		this.eaiSvcDesc = eaiSvcDesc;
	}

	public String getEAISvcDesc() {
		return eaiSvcDesc;
	}

	public int compareTo(EAIMessage m) {
		if (getMsgRcvTm() > m.getMsgRcvTm())
			return 1;
		else if (getMsgRcvTm() == m.getMsgRcvTm())
			return 0;
		return -1;
	}

	public String getGroupCoCd() {
		return groupCoCd;
	}

	public void setGroupCoCd(String groupCoCd) {
		this.groupCoCd = groupCoCd;
	}

	public String getSevrDstcd() {
		return sevrDstcd;
	}

	public void setSevrDstcd(String sevrDstcd) {
		this.sevrDstcd = sevrDstcd;
	}

	public String getTranType() {
		return tranType;
	}

	public void setTranType(String tranType) {
		this.tranType = tranType;
	}

	public String getRspnsChngMsgType() {
		return rspnsChngMsgType;
	}

	public void setRspnsChngMsgType(String rspnsChngMsgType) {
		this.rspnsChngMsgType = rspnsChngMsgType;
	}

	public String getCompanyCode() {
		return companyCode;
	}

	public void setCompanyCode(String companyCode) {
		this.companyCode = companyCode;
	}

	public int getSplizLength() {
		return splizLength;
	}

	public void setSplizLength(int splizLength) {
		this.splizLength = splizLength;
	}

	public String getAdptrInstiCode() {
		return adptrInstiCode;
	}

	public void setAdptrInstiCode(String adptrInstiCode) {
		this.adptrInstiCode = adptrInstiCode;
	}

	public String getUseYn() {
		return useYn;
	}

	public void setUseYn(String useYn) {
		this.useYn = useYn;
	}

//	public ExtMessage getExtMsg() {
//		return extMsg;
//	}
//
//	public void setExtMsg(ExtMessage extMsg) {
//		this.extMsg = extMsg;
//	}
	public InterfaceMapper getMapper() {
		return mapper;
	}

	public void setMapper(InterfaceMapper mapper) {
		this.mapper = mapper;
	}

	public StandardMessage getStandardMessage() {
		return standardMessage;
	}

	public void setStandardMessage(StandardMessage standardMessage) {
		this.standardMessage = standardMessage;
	}
	
	
	public StandardMessage getSubMessage() {
		return subMessage;
	}

	public void setSubMessage(StandardMessage subMessage) {
		this.subMessage = subMessage;
	}

	public String getExtBizCd() {
		return extBizCd;
	}

	public void setExtBizCd(String extBizCd) {
		this.extBizCd = extBizCd;
	}

	public String getTxId() {
		return txId;
	}

	public void setTxId(String txId) {
		this.txId = txId;
	}

	public String getRefKey() {
		return refKey;
	}

	public void setRefKey(String refKey) {
		this.refKey = refKey;
	}
	
	public String getClientId() {
		return clientId;
	}

	public void setClientId(String clientId) {
		this.clientId = clientId;
	}

	public String getInternalExternalDvcd() {
		return internalExternalDvcd;
	}

	public void setInternalExternalDvcd(String internalExternalDvcd) {
		this.internalExternalDvcd = internalExternalDvcd;
	}

	public String getApiEnabledYn() {
		return apiEnabledYn;
	}

	public void setApiEnabledYn(String apiEnabledYn) {
		this.apiEnabledYn = apiEnabledYn;
	}

	public String getAuthType() {
		return authType;
	}

	public void setAuthType(String authType) {
		this.authType = authType;
	}

	public String getClientIp() {
		return clientIp;
	}

	public void setClientIp(String clientIp) {
		this.clientIp = clientIp;
	}

	public String getApiCacheYn() {
		return apiCacheYn;
	}

	public void setApiCacheYn(String apiCacheYn) {
		this.apiCacheYn = apiCacheYn;
	}

	public String getApiCacheType() {
		return apiCacheType;
	}

	public void setApiCacheType(String apiCacheType) {
		this.apiCacheType = apiCacheType;
	}

	public String getAuthkeyfieldname() {
		return authkeyfieldname;
	}

	public void setAuthkeyfieldname(String authkeyfieldname) {
		this.authkeyfieldname = authkeyfieldname;
	}

	public String getAuthCheckdYn() {
		return authCheckdYn;
	}

	public void setAuthCheckdYn(String authCheckdYn) {
		this.authCheckdYn = authCheckdYn;
	}



	/**
	 * [주의] 비동기 JMS 전달 전용 - 직접 사용 금지!
	 *
	 * 이 필드는 비동기 거래 시 JMS ObjectMessage 직렬화를 통해
	 * Consumer 스레드로 컨텍스트를 전달하기 위한 용도로만 사용됩니다.
	 *
	 * 컨텍스트 값 읽기/쓰기는 반드시 ElinkTransactionContext를 사용하세요:
	 * - ElinkTransactionContext.setSeedSalt() / getSeedSalt()
	 * - ElinkTransactionContext.setEncryptionKey() / getEncryptionKey()
	 *
	 * 설정 위치:
	 * - FlowRouter: getAll()로 복사하여 이 필드에 설정
	 * - ElinkESBProcessProxy: 이 필드에서 restore()로 복원
	 *
	 * @see com.eactive.eai.common.context.ElinkTransactionContext
	 */
	private Map<String, Object> transactionContextTransfer;

	/**
	 * [비동기 전달 전용] 컨텍스트 전달용 Map 반환
	 * @see #transactionContextTransfer
	 */
	public Map<String, Object> getTransactionContextTransfer() {
		return transactionContextTransfer;
	}
	
	public Properties getCallProp() {
		return callProp;
	}

	public void setCallProp(Properties callProp) {
		this.callProp = callProp;
	}

	/**
	 * [비동기 전달 전용] 컨텍스트 전달용 Map 설정
	 * @see #transactionContextTransfer
	 */
	public void setTransactionContextTransfer(Map<String, Object> transactionContextTransfer) {
		this.transactionContextTransfer = transactionContextTransfer;
	}

	@Override
	public Object clone() throws CloneNotSupportedException {
		EAIMessage cloned = (EAIMessage) super.clone();
		if (svcMsgs != null) {
			cloned.setSvcMsgs((List<ServiceMessage>) ((ArrayList<ServiceMessage>) svcMsgs).clone());
		}
		if (mapper != null)
			cloned.setMapper(mapper);
		if (standardMessage != null)
			cloned.setStandardMessage((StandardMessage) standardMessage.clone());
		if (subMessage != null)
			cloned.setSubMessage((StandardMessage) subMessage.clone());
		if (transactionContextTransfer != null)
			cloned.setTransactionContextTransfer(new HashMap<>(transactionContextTransfer));
		return cloned;
	}
	
	public void clear() {
		String data = null;
		if (standardMessage != null) {
			try {
				standardMessage.setBizData(data, null);
			} catch (Exception e) {
				;
			}
		}
		if (subMessage != null) {
			try {
				subMessage.setBizData(data, null);
			} catch (Exception e) {
				;
			}
		}
		if (svcMsgs != null) {
			svcMsgs.clear();
		}
	}
}
