package com.eactive.eai.adapter.socket2.protocol.xecure.fixed.handshake;

import com.eactive.eai.adapter.socket2.common.SMSLogger;
import com.eactive.eai.adapter.socket2.protocol.ByteMessage;
import com.eactive.eai.adapter.socket2.protocol.ISocketAdapter;
import com.eactive.eai.adapter.socket2.protocol.xecure.XecureConstants;
import com.eactive.eai.adapter.socket2.protocol.xecure.XecureErrorMessage;
import com.sf.xc3.Base64;
import com.sf.xc3.XCException;
import com.sf.xc3.XC_v3;
import org.apache.mina.common.IoSession;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class XecureFixedServerFilter extends XecureFixedFilter {
	public XecureFixedServerFilter(ISocketAdapter adapter) {
		super(adapter);
	}	
	
	@Override
    public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
		try {
			/**
			 * xc -init
			 */
//			XC_v3 xc = new XC_v3(cert, key, password);
			XC_v3 xc = null;//TODO kb version => 우체국 version
			int ret = xc.init(password, context.getXecureConfigPath(), 2);
			if (ret < 0) {
				throw new Exception("cannot init xecure connector. ret=" + ret + " : " + XecureErrorMessage.getErrorMessage(ret));
			}
			
			xc.msgLong();

			/**
			 * put xc into session
			 */
			session.setAttribute(XecureConstants.XECURE, xc);
			
			/**
			 * change state
			 */
			FilterState filterState = (FilterState) session.getAttribute(FILTER_STATE_KEY);
			if (filterState == null) {
				filterState = new FilterState();
				session.setAttribute(FILTER_STATE_KEY, filterState);
			}
			filterState.state = State.STATE_KEY_FINAL;
			setSessionState(session, filterState.state.toString());
		} catch(XCException e) {
			String xcMessage = "";
			Matcher matcher = Pattern.compile("(\\-[0-9]+)").matcher(e.getMessage());
			if (matcher.find()) {
			    String key = matcher.group(1);
			    xcMessage = XecureErrorMessage.getErrorMessage(key);
			}
			adapter.addRecentError(context.getAdapterName() + " | xecure error - " + e.getMessage() + " | " + xcMessage, e);
			logger.error(context.getAdapterName() + " | xecure error - " + e.getMessage() + " | " + xcMessage, e);
			errLogger.error(context.getAdapterName() + " | xecure error - " + e.getMessage() + " | " + xcMessage, e);
//			SMSLogger.loggingSMSWithCode(context.getAdapterName(), "RECEAINNA012");
			SMSLogger.loggingSMS4Soc(context.getAdapterName(), context.getDescription(), "RECEAINNA012");
			throw new XCException(context.getAdapterName() + " | " + e.getMessage() + " | " + xcMessage);
		}
	}
	
	
	@Override
	public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
		ByteMessage m = (ByteMessage) message;
		XC_v3 xc = null;

		try {
			FilterState filterState = (FilterState) session.getAttribute(FILTER_STATE_KEY);
			xc = (XC_v3) session.getAttribute(XecureConstants.XECURE);
	
			switch (filterState.state) {
			case STATE_KEY_FINAL:
				if ( context.getTraceLevel() >= context.TRACE_LEVEL_TRACE ) {
					logger.debug(context.getAdapterName() + " | XecureFixedServerFilter | <RECV> KEY_FINAL | " + m.hexDump());
				}

//				String sessionState = (String) session.getAttribute(ProtocolHandler.SESSION_STATE);
				
				if ("Y".equals(context.getLlInclude())) {
					ByteMessage bm = new ByteMessage(m.getBytes(0, context.getLlFieldOffset()));
					bm.append(m.getBytes(context.getLlFieldOffset() + context.getLlFieldLength()));
					m = bm;
				} 
	
				byte[] bytes = Base64.decode(m.getBytes());
	
				String token = xc.keyFinal(bytes, 2);
				//String token = xc.keyFinal(bytes, 2, cert, key, password);
	
				filterState.key = token.getBytes(); //Base64.decode(token);
				
				if ( context.getTraceLevel() >= context.TRACE_LEVEL_TRACE ) {
					logger.debug(context.getAdapterName() + " | XecureFixedServerFilter | <SEND> KEY_FINAL | " + token.substring(0,40) + "...");
				}
				
//				WriteFuture future = session.write(format(filterState.key, session));
				session.write(format(filterState.key, session));
				//future.join(context.getTimeout() * 1000L);
	
				filterState.state = State.STATE_MESSAGE;
				setSessionState(session, filterState.state.toString());
	
				nextFilter.sessionCreated(session);
				nextFilter.sessionOpened(session);
				break;
				
			case STATE_MESSAGE:
				if (!"ENVELOPE".equals(context.getXecureType())) {
					/**
					 * 전자 봉투 방식 아닌 경우만.. 
					 */
					m = decrypt(m, session);
				}
				nextFilter.messageReceived(session, m);
				break;
		
			default:
				throw new Exception("<RECV> invalid message during handshake .. : " + m);
			}
		} catch(XCException e) {
			String xcMessage = "";
			Matcher matcher = Pattern.compile("(\\-[0-9]+)").matcher(e.getMessage());
			
			if (matcher.find()) {
			    String key = matcher.group(1);
			    xcMessage = XecureErrorMessage.getErrorMessage(key);
			}
			
			adapter.addRecentError(context.getAdapterName() + " | xecure error - " + e.getMessage() + " | " + xcMessage, e);
			logger.error(context.getAdapterName() + " | xecure error - " + e.getMessage() + " | " + xcMessage, e);
			errLogger.error(context.getAdapterName() + " | xecure error - " + e.getMessage() + " | " + xcMessage, e);
//			SMSLogger.loggingSMSWithCode(context.getAdapterName(), "RECEAINNA012");
			SMSLogger.loggingSMS4Soc(context.getAdapterName(), context.getDescription(), "RECEAINNA012");

			nextFilter.filterClose(session);
			if (xc != null) {
				xc.close();
			}
			adapter.getSessionPool().remove(session);
			session.close();
			
			throw new XCException(context.getAdapterName() + " | xecure error - " + e.getMessage() + " | " + xcMessage);
		}
	}
}
