package com.eactive.eai.adapter.socket2.protocol.xecure.welcome.codec;

import com.eactive.eai.adapter.socket2.common.CommonLib;
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.adapter.socket2.protocol.xecure.welcome.codec.XecureWelcomeDecoder.CodecState;
import com.eactive.eai.common.util.Logger;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

public class XecureWelcomeEncoder implements ProtocolEncoder {	
	final protected Logger logger;
    final protected Logger errLogger;
	
	SocketAdapterContext context;
	ISocketAdapter adapter;

	public XecureWelcomeEncoder(ISocketAdapter adapter) {
		this.adapter = adapter;
		this.context = adapter.getContext();

	    logger    = SocketLoggerManager.getInstance().getLogger(context.getAdapterGroupName());
	    errLogger = SocketLoggerManager.getInstance().getErrLogger();
	}

	public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
			throws Exception {

		CodecState codecState = (CodecState) session.getAttribute(XecureWelcomeConstants.CODEC_KEY);

		if (codecState == null) {
			codecState = new CodecState();
			//codecState.buffer.limit(Constants.HEADER_LENGTH);
			session.setAttribute(XecureWelcomeConstants.CODEC_KEY, codecState);
		}
		
		ByteMessage m = null;
		if (message == null) {
			throw new Exception("cannot write null message.");
		} else if (message instanceof ByteMessage) {
			m = (ByteMessage) message;
		} else if (message instanceof String) {
			m = new ByteMessage((String) message);
		} else if (message instanceof byte[]) {
			m = new ByteMessage((byte[]) message);
		} else {
			throw new Exception("cannot write unknow format message.");
		}

		String sessionState = (String) session.getAttribute(ProtocolHandler.SESSION_STATE);
		
		ByteBuffer buffer = null;
		if (sessionState.startsWith("STATE_WELCOME")) {
			buffer = formatWelcomeWelcome(m, codecState);
		} else if (sessionState.startsWith("STATE_KEY_")) {
			buffer = formatWelcomeHandshake(m, codecState);
		} else {
			buffer = formatWelcomeMessage(m, codecState);
		}
		
			
        int mark = buffer.position();
        buffer.position(0);
        
		if ( context.getTraceLevel() >= context.TRACE_LEVEL_TRACE ) {
			logger.debug(context.getAdapterName() + " | "  + sessionState + " - encode - " + CommonLib.hexDump(buffer, context));
			adapter.addRecentSendTrace(session, sessionState + " - encode - " + CommonLib.hexDump(buffer, context));
		}
		
        buffer.position(mark);
        buffer.flip();
        out.write(buffer);
	}
	
	private ByteBuffer formatWelcomeWelcome(ByteMessage message, CodecState codecState) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(message.getBytes().length);
		//buf.setAutoExpand(true); // Enable auto-expand for easier encoding

		/**
		 * write header (ll.field.include)
		 */		 
		String lenStr = CommonLib.getFormatString(message.getBytes().length, 7);	
		buffer.put(lenStr.getBytes());  							// tatal message length
		// tatal message length - left padding '0'
		//buffer.put(StringUtils.leftPad(String.valueOf(m.getValue().length + Constants.HEADER_LENGTH + Constants.TAIL_LENGTH), 7, '0').getBytes());	

		/**
		 * padding - 17 bytes
		 */
		/*
		// 암호화 타입 (0:plain 1:DES 2:Xecure Connect)
		buffer.put(codecState.securityType);
		
		// 판매점 아이디 (16 Byte 고정으로 앞 또는 뒤를 공백문자로 채운다)
		buffer.put(StringUtils.leftPad(" ", 16, ' ').getBytes());
		*/
		buffer.put(message.getBytes(7, 17));
		
		/**
		 * write payload 
		 */		 
        buffer.put(message.getBytes(7+17, message.size()-7-17-2));

		/**
		 * write tail
		 */		 
        buffer.put((byte) 0x0D);  // CR '\r'
        buffer.put((byte) 0x0A);  // LF '\n'
		
        return buffer;
	}
	
	private ByteBuffer formatWelcomeHandshake(ByteMessage message, CodecState codecState) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(message.getBytes().length);
		//buf.setAutoExpand(true); // Enable auto-expand for easier encoding

		/**
		 * write header (ll.field.include)
		 */		 
		String lenStr = CommonLib.getFormatString(message.getBytes().length, 7);	
		buffer.put(lenStr.getBytes());  							// tatal message length

		// tatal message length - left padding '0'
		//buffer.put(StringUtils.leftPad(String.valueOf(m.getValue().length + Constants.HEADER_LENGTH + Constants.TAIL_LENGTH), 7, '0').getBytes());	

		/**
		 * padding - 23 bytes
		 */
		/*
		// 암호화 타입 (0:plain 1:DES 2:Xecure Connect)
		buffer.put(codecState.securityType);
		
		// 판매점 아이디 (22 Byte 고정으로 앞 또는 뒤를 공백문자로 채운다)
		buffer.put("KB_DEV          |4001|".getBytes());
		*/	
		buffer.put(message.getBytes(7, 23));
	
		/**
		 * write payload 
		 */		 
        buffer.put(message.getBytes(7+23, message.size()-7-23-3));

		/**
		 * write tail
		 */		 
        buffer.put((byte) '|');   // '|'
        buffer.put((byte) 0x0D);  // CR '\r'
        buffer.put((byte) 0x0A);  // LF '\n'
		
        return buffer;
	}
	
	private ByteBuffer formatWelcomeMessage(ByteMessage message, CodecState codecState) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(message.getBytes().length+2);
		//buf.setAutoExpand(true); // Enable auto-expand for easier encoding

		/**
		 * write header (ll.field.include)
		 */		 
		String lenStr = CommonLib.getFormatString(message.getBytes().length+2, 7);	
		buffer.put(lenStr.getBytes());  							// tatal message length
		// tatal message length - left padding '0'
		//buffer.put(StringUtils.leftPad(String.valueOf(m.getValue().length + Constants.HEADER_LENGTH + Constants.TAIL_LENGTH), 7, '0').getBytes());	

		/**
		 * padding - 17 bytes
		 */
		/*
		// 암호화 타입 (0:plain 1:DES 2:Xecure Connect)
		buffer.put(codecState.securityType);
		
		// 판매점 아이디 (16 Byte 고정으로 앞 또는 뒤를 공백문자로 채운다)
		buffer.put(StringUtils.leftPad(" ", 16, ' ').getBytes());
		*/
		buffer.put(message.getBytes(7, 17));
		
		/**
		 * write payload 
		 */		 
        buffer.put(message.getBytes(7+17, message.size()-7-17));

		/**
		 * write tail
		 */		 
        buffer.put((byte) 0x0D);  // CR '\r'
        buffer.put((byte) 0x0A);  // LF '\n'
		
        return buffer;
	}

	public void dispose(IoSession session) throws Exception {
	}
}
