package com.eactive.eai.adapter.socket2.protocol.cisco.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.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 CiscoEncoder implements ProtocolEncoder {
	final protected Logger logger;
    final protected Logger errLogger;

    SocketAdapterContext context;
    ISocketAdapter adapter;
	
	public CiscoEncoder(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 {
	
		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.");
		}
		
		ByteBuffer buffer = ByteBuffer.allocate(6);
		buffer.setAutoExpand(true); // Enable auto-expand for easier encoding

        int toSendLen = 0;
        int sentLen = 0;
        
        while (true) {        
            if (m.getBytes().length - sentLen <= CiscoConstants.CISCO_PACKET_SIZE) {
                toSendLen = m.getBytes().length - sentLen;
            } else {
                toSendLen = CiscoConstants.CISCO_PACKET_SIZE;
            }

            buffer.put((byte) 0xD7);
            buffer.put((byte) 0x4A);
            buffer.put((byte) (toSendLen/256));
            buffer.put((byte) (toSendLen%256));
            buffer.put((byte) (sentLen + toSendLen >= m.getBytes().length ? 0x00 : 0x01));
            buffer.put((byte) 0x00);

            byte[] payload   = new byte[toSendLen];
            System.arraycopy(m.getBytes(), sentLen, payload, 0, toSendLen);
            buffer.put(payload);
    
            sentLen += toSendLen;

            if( sentLen >= m.getBytes().length) {
                break;
            }
            //continue;
        }
        
        int mark = buffer.position();
        buffer.position(0);
		if ( context.getTraceLevel() >= context.TRACE_LEVEL_TRACE ) {
			logger.debug(context.getAdapterName() + " | CiscoEncoder | encode : " + CommonLib.hexDump(buffer, context));
			adapter.addRecentSendTrace(session, "CiscoEncoder | encode : " + CommonLib.hexDump(buffer, context));
		}
        buffer.position(mark);
	
        buffer.flip();
		out.write(buffer);
	}

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