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

import com.eactive.eai.adapter.socket2.common.CommonLib;
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.eactive.eai.adapter.socket2.protocol.xecure.XecureFilter;
import com.sf.xc3.Base64;
import com.sf.xc3.XCException;
import com.sf.xc3.XC_v3;
import org.apache.commons.lang3.StringUtils;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoSession;

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

abstract public class XecureFixedHeaderFilter extends XecureFilter {

	public XecureFixedHeaderFilter(ISocketAdapter adapter) {
		super(adapter);
	}

	
	@Override
    public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
		ByteMessage m = 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");
		}

		/*
		if ( context.getTraceLevel() >= context.TRACE_LEVEL_DEBUG ) {
			logger.debug(context.getAdapterName() + " | XecureFilter | <SEND> " + m.hexDump());
		    adapter.addRecentSend(m.hexDump());
		}
		*/	    

		try {
			FilterState filterState = (FilterState) session.getAttribute(FILTER_STATE_KEY);
//			XC_v3 xc = (XC_v3) session.getAttribute(XecureConstants.XECURE);
	
			switch (filterState.state) {			
			case STATE_MESSAGE:
//				String sessionState = (String) session.getAttribute(ProtocolHandler.SESSION_STATE);
				m = encrypt(m, session);
				if ( context.getTraceLevel() >= context.TRACE_LEVEL_DEBUG ) {
					logger.debug(context.getAdapterName() + " | XecureFixedHeaderFilter | filterWrite() - after encryption - " + m.hexDump());
				}

				break;
				
			default:
				/*
				if ( context.getTraceLevel() >= context.TRACE_LEVEL_DEBUG ) {
					logger.debug(context.getAdapterName() + " | XecureFixedClientFilter - <SEND> " + filterState.state + " - " + m.hexDump());
				}
				*/
				break;
			}
		} 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() + " | xecure error - " + e.getMessage() + " | " + xcMessage);
		}

		nextFilter.filterWrite(session, new WriteRequest(m, writeRequest.getFuture(), writeRequest.getDestination()));
    }
	
	protected byte[] format(byte[] msg, byte[] part, IoSession session) throws Exception {
		FilterState filterState = (FilterState) session.getAttribute(FILTER_STATE_KEY);
//		XC_v3 xc = (XC_v3) session.getAttribute(XecureConstants.XECURE);

		if (filterState == null) {
			filterState = new FilterState();
			session.setAttribute(FILTER_STATE_KEY, filterState);
		}
		
		ByteMessage m = new ByteMessage(StringUtils.leftPad("0", context.getLlFieldLength()));
		m.append(part);
		m.append(msg);

		return m.getBytes();
	}
	
	protected ByteMessage encrypt(ByteMessage m, IoSession session) throws Exception {
		XC_v3 xc = (XC_v3) session.getAttribute(XecureConstants.XECURE);

//		ByteMessage hdr = new ByteMessage(m.getBytes(0, context.getLlFieldLength() + XecureConstants.FIXED_HEADER_PART_LEHGTH));
//		ByteMessage bm = new ByteMessage(m.getBytes(context.getLlFieldLength() + XecureConstants.FIXED_HEADER_PART_LEHGTH));
		ByteMessage bm = new ByteMessage(Base64.encode(xc.encode(m.getBytes())));
		
		String lenStr = CommonLib.getFormatString(bm.size(), context.getLlFieldLength());
		ByteMessage encrypted = new ByteMessage();
		encrypted.append(lenStr.getBytes());
		encrypted.append(XecureConstants.FIXED_HEADER_MESSAGE.getBytes());
		encrypted.append(bm.getBytes());
		
		return encrypted;		
	}

	protected ByteMessage decrypt(ByteMessage m, IoSession session) throws Exception {
		XC_v3 xc = (XC_v3) session.getAttribute(XecureConstants.XECURE);
		ByteMessage result = null;
		
		/**
		 * input
		 */
//		byte[] headerPart = m.getBytes(context.getLlFieldLength(), XecureConstants.FIXED_HEADER_PART_LEHGTH);
		m.getBytes(context.getLlFieldLength(), XecureConstants.FIXED_HEADER_PART_LEHGTH);
		ByteMessage bm = new ByteMessage(m.getBytes(context.getLlFieldLength() + XecureConstants.FIXED_HEADER_PART_LEHGTH));
		byte[] input = bm.getBytes();

		/**
		 * output
		 */
		byte[] output = null;		
		try {
			output = Base64.decode(input);
			output = xc.decode(output, true).getBytes();
			output = Base64.decode(output);
		} catch(Exception e) {
			String xcMessage = "";
			Matcher matcher = Pattern.compile("(\\-[0-9]+)").matcher(e.getMessage());
			
			if (matcher.find()) {
			    String key = matcher.group(1);
			    xcMessage = XecureErrorMessage.getErrorMessage(key);
			}
			
			throw new Exception("xecure - decode error. " + e.getMessage() + " | " + xcMessage);
		}
	
		/**
		 * formatting
		 */
		result = new ByteMessage(output);
		ByteBuffer buffer = ByteBuffer.allocate(
				context.getLlFieldLength() + XecureConstants.FIXED_HEADER_PART_LEHGTH + output.length);
		
		String lenStr = CommonLib.getFormatString(output.length, context.getLlFieldLength());
		buffer.put(lenStr.getBytes());
//		buffer.put(headerPart);	// '전문구분' 정보는 업무팀에 보내지 않음
        buffer.put(result.getBytes());
        buffer.flip();
        result.setByteBuffer(buffer);
		
		if ( context.getTraceLevel() >= context.TRACE_LEVEL_DEBUG ) {
			logger.debug(context.getAdapterName() + " | XecureFixedHeaderFilter | <RECV> | " + result.hexDump());
		}
		
		return result;
	}
}
