package com.eactive.eai.adapter.socket2.protocol.inisafepayload.handshake;

import com.eactive.eai.adapter.socket2.common.SMSLogger;
import com.eactive.eai.adapter.socket2.common.SimpleFuture;
import com.eactive.eai.adapter.socket2.config.SocketAdapterContext;
import com.eactive.eai.adapter.socket2.config.SocketLoggerManager;
import com.eactive.eai.adapter.socket2.protocol.ByteMessage;
import com.eactive.eai.adapter.socket2.protocol.ISocketAdapter;
import com.eactive.eai.adapter.socket2.protocol.ProtocolHandler;
import com.eactive.eai.common.util.Logger;
import com.initech.inisafenet.HandShakeManager;
import com.initech.inisafenet.util.INISAFENetCryptoUtil;
import com.initech.provider.crypto.InitechProvider;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoFilterAdapter;
import org.apache.mina.common.IoSession;


public abstract class InisafePayloadFilter extends IoFilterAdapter {
	protected final Logger logger;
	protected final Logger errLogger;

	public static final String FILTER_STATE_KEY = InisafePayloadFilter.class.getName() + ".STATE";

	public static final String SESSION_STATE = "SESSION_STATE";
	public static final String INISAFE_SESSION_KEY = "INISAFE_SESSION_KEY";
	
	public enum State {
		STATE_START, 
		STATE_INIT,
		STATE_UPDATE,
		STATE_FINAL,
		STATE_MESSAGE;
	}

	public static class FilterState {
		public State state = null;
		public byte[] key;  // token?
		
		public FilterState() {}
	}	
	
    protected SocketAdapterContext context;
	protected ISocketAdapter adapter;
	
	protected byte[] cert;
	protected byte[] key;
	protected String password;
	protected byte[] remoteCert;		

	static {
		new InitechProvider();
	}

	protected  InisafePayloadFilter(ISocketAdapter adapter) {
		this.adapter = adapter;
		this.context = adapter.getContext();

	    logger    = SocketLoggerManager.getInstance().getLogger(context.getAdapterGroupName());
	    errLogger = SocketLoggerManager.getInstance().getErrLogger();
	}
	
	@Override
	public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
		synchronized(session) {
			FilterState filterState = (FilterState) session.getAttribute(FILTER_STATE_KEY);
			if (filterState == null) {
				filterState = new FilterState();
				filterState.state = State.STATE_INIT;
				session.setAttribute(FILTER_STATE_KEY, filterState);
			}
		}
		
		// handshake future
		session.setAttribute(ProtocolHandler.HANDSHAKE_FUTURE, new SimpleFuture());
	}	
  
	@Override
	public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
//		HandShakeManager inisafeSession = (HandShakeManager) session.getAttribute(INISAFE_SESSION_KEY);
	
		nextFilter.sessionClosed(session);
	}

	
	@Override
    public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
		ByteMessage m = null;
		ByteBuffer buffer = null;
		
		if (writeRequest.getMessage() instanceof byte[]) {
			m = new ByteMessage((byte[]) writeRequest.getMessage());
		} else if (writeRequest.getMessage() instanceof ByteMessage) {
			m = (ByteMessage) writeRequest.getMessage();
		} else if (writeRequest.getMessage() instanceof String) {
			m = new ByteMessage((String) writeRequest.getMessage());
		} else if (writeRequest.getMessage() instanceof ByteBuffer) {
			m = new ByteMessage((ByteBuffer) writeRequest.getMessage());
		} else {
			throw new Exception("Unknown data format");
		}
		
		/**
		 * encrypt
		 */
		try {
			
			FilterState filterState = (FilterState) session.getAttribute(FILTER_STATE_KEY);
			HandShakeManager inisafeSession = (HandShakeManager) session.getAttribute(INISAFE_SESSION_KEY);

			switch (filterState.state) {			
			case STATE_MESSAGE:
				
				buffer = ByteBuffer.allocate(context.getSendPayloadLength()).limit(context.getSendPayloadLength());
				
				/**
				 * 업무전문을 무조건 4047 바이트화 (데이터 + Null) 
				 */
				byte[] encBuffer = new byte[4047];
				System.arraycopy(m.getBytes(), 0, encBuffer, 0, m.getBytes().length);
				
				/**
				 * 4047 바이트를 암호화하면 4048 바이트 리턴 
				 */
				byte[] mBuffer = new byte[4048];
				mBuffer = inisafeSession.i_encrypt(encBuffer);
				buffer.put(mBuffer);

				
				/**
				 * 업무전문의 암호화를 위한 보조 암호키로 사용(데이터 마지막부터 16바이트)
				 */				
				byte[] iv = new byte[16];
				System.arraycopy(mBuffer, mBuffer.length - 16, iv, 0, 16);
				inisafeSession.setIV(iv);
				
				
				/**
				 * 암호검증용 Hash 값 (20바이트)
				 */
				INISAFENetCryptoUtil cryptoUtil = new INISAFENetCryptoUtil();
				byte[] hashBuf = cryptoUtil.getDigest(mBuffer, "SHA1");
				buffer.position(4048);
				buffer.put(hashBuf);
				buffer.position(0);
				/**
				 * 4K 데이터 송신을 위한 버퍼이동 
				 */	
				m = new ByteMessage(buffer);
				logger.debug(context.getAdapterName() + " | InisafePayloadFilter | m : " + m.hexDump());

				
				break;
				
			default:
				break;
			}
		} catch(Exception e) {
			adapter.addRecentError(context.getAdapterName() + " | initech error - " + e.getMessage(), e);
			logger.error(context.getAdapterName() + " | initech error - " + e.getMessage(), e);
			errLogger.error(context.getAdapterName() + " | initech error - " + e.getMessage(), e);
			SMSLogger.loggingSMS4Soc(context.getAdapterName(), context.getDescription(), "RECEAINNA012");
			throw new Exception(context.getAdapterName() + " | initech error - " + e.getMessage());
		}

		nextFilter.filterWrite(session, new WriteRequest(m, writeRequest.getFuture(), writeRequest.getDestination()));
    }
	

	protected String getSessionState(IoSession session) {
		return (String) session.getAttribute(SESSION_STATE);
	}
	
	
	protected void setSessionState(IoSession session, String state) {
		session.setAttribute(SESSION_STATE, state);
	}
}
