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

import com.eactive.eai.adapter.socket2.common.CommonLib;
import com.eactive.eai.adapter.socket2.common.Env;
import com.eactive.eai.adapter.socket2.common.SMSLogger;
import com.eactive.eai.adapter.socket2.config.SocketAdapterContext;
import com.eactive.eai.adapter.socket2.config.SocketAdapterManager;
import com.eactive.eai.adapter.socket2.protocol.ByteMessage;
import com.eactive.eai.adapter.socket2.protocol.ISocketAdapter;
import org.apache.mina.common.IoSession;


public class BindClientFilter extends BindFilter {
	public BindClientFilter(ISocketAdapter adapter) {
		super(adapter);
	}	

	
	@Override
    public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
		process(nextFilter, session, null);
	}
	
	@Override
	public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
		ByteMessage m = (ByteMessage) message;		
		process(nextFilter, session, m);
	}	
	
	protected void process(NextFilter nextFilter, IoSession session, ByteMessage message) throws Exception {
		try {
			FilterState filterState = (FilterState) session.getAttribute(FILTER_STATE_KEY);
			if (filterState == null) {
				filterState = new FilterState();
				session.setAttribute(FILTER_STATE_KEY, filterState);
			}
			/**
			 * State machine
			 */
//			ByteBuffer buffer = null;
			
			switch (filterState.state) {
			case STATE_BIND_SEND:
				
				
//				session.getRemoteAddress()
				
				/**
				 * change state to SEND
				 */
				filterState.state = State.STATE_BIND_SEND;
				session.setAttribute(SESSION_STATE, filterState.state.toString());

				/**
				 * create send data
				 */
				
				ByteMessage data = new ByteMessage();
				String line = context.getLoginSend();
				while(line.indexOf("0x") != -1) {
						data.append(line.substring(0, line.indexOf("0x")));
						String hex = line.substring(line.indexOf("0x"), line.indexOf("0x")+4);	
						data.append((byte) Integer.parseInt(hex.substring(2), 16));
						line = line.substring(line.indexOf("0x")+4);				
				}
				data.append(line);
		        
				if (context.getTraceLevel() >= SocketAdapterContext.TRACE_LEVEL_DEBUG) {
					logger.debug(context.getAdapterName() + " | LoginClientFilter | <SEND> LOGIN_SEND" + CommonLib.hexDump(data.getBytes(), true, context));
				}
				session.write(data.getBytes());
				
				/**
				 * change state to UPDATE
				 */
				filterState.state = State.STATE_BIND_RECV;
				setSessionState(session, filterState.state.toString());
				break;
				
			case STATE_BIND_RECV:
				if (context.getTraceLevel() >= SocketAdapterContext.TRACE_LEVEL_DEBUG) {
					logger.debug(context.getAdapterName() + " | LoginClientFilter | <RECV> LOGIN_RECV response");
				}
				
				if(message == null) {
					throw new Exception("LOGIN_RECV message is null");
				}	
				/**
				 * get ip port
				 */	
				int offset = 12;
				byte[] firstIp     = message.getBytes(offset, 16); offset = offset + 16;
				byte[] firstTPort  = message.getBytes(offset, 4);  offset = offset + 4;
				byte[] firstRPort  = message.getBytes(offset, 4);  offset = offset + 4;
				byte[] secondIp    = message.getBytes(offset, 16); offset = offset + 16;
				byte[] secondTPort = message.getBytes(offset, 4);  offset = offset + 4;
				byte[] secondRPort = message.getBytes(offset, 4);
//				byte[] result = message.getBytes(offset, 4);offset = offset + 4;
				
				
				String[] sIp = {new String(firstIp),new String(secondIp)}; 
				int[] iTport = {0,0};
				int[] iRport = {0,0};
				for (int i=0; i<4; i++) {
					iTport[0] += ((int) firstTPort[i] & 0xFF) * Math.pow(256, 4-i-1);
					iRport[0] += ((int) firstRPort[i] & 0xFF) * Math.pow(256, 4-i-1);
					iTport[1] += ((int) secondTPort[i] & 0xFF) * Math.pow(256, 4-i-1);
					iRport[1] += ((int) secondRPort[i] & 0xFF) * Math.pow(256, 4-i-1);
				}
				logger.debug("firstIp  = "+sIp[0]);
				logger.debug("tport    = "+iTport[0]);
				logger.debug("rport    = "+iRport[0]);
				logger.debug("secondIp = "+sIp[1]);
				logger.debug("tport    = "+iTport[1]);
				logger.debug("rport    = "+iRport[1]);
				
				
				/**
				 * change state
				 */
				filterState.state = State.STATE_MESSAGE;
				setSessionState(session, filterState.state.toString());	

				/**
				 * finish handshake
				 */
				if ( context.getTraceLevel() >= SocketAdapterContext.TRACE_LEVEL_DEBUG ) {
					adapter.addRecentLog(context.getAdapterName() + " | LoginClientFilter | handshake finished ...");
					logger.debug(context.getAdapterName() + " | LoginClientFilter | handshake finished ...");
				}	
				/**
				 * start lazy pair socket adapter (in same socket adapter group)
				 */
				int index = 0;
				ISocketAdapter[] adapters = SocketAdapterManager.getInstance().getSocketAdapters(adapter.getContext().getAdapterGroupName());
				if(adapters == null) return; 
				for (int i=0; i<adapters.length; i++) {
					if ("LAZY".equals(adapters[i].getContext().getProtocol())
						&& adapters[i].getState() == ISocketAdapter.State.STOPPED) {
						index ++;
						//ip port
						if (!Env.isWindows()){
							if ("DELIVER".equals(context.getBindType())){
								adapters[i].getContext().setHostName(sIp[index]);
								adapters[i].getContext().setPortNumber(iTport[index]);
							}else if ("REPORT".equals(context.getBindType())){
								adapters[i].getContext().setHostName(sIp[index]);
								adapters[i].getContext().setPortNumber(iRport[index]);
							}
							
						}
//							adapters[i].start().join();
						break;
					}
				}

				nextFilter.sessionCreated(session);
				nextFilter.sessionOpened(session);
				

				break;
				
			case STATE_MESSAGE:			
				nextFilter.messageReceived(session, message);
				break;
				
			default:
				throw new Exception("<RECV> invalid message during handshake .. : " + message);
			}
		} catch(Exception e) {
			adapter.addRecentError(context.getAdapterName() + " | login error - " + e.getMessage(), e);
			logger.error(context.getAdapterName() + " | login error - " + e.getMessage(), e);
			errLogger.error(context.getAdapterName() + " | login error - " + e.getMessage(), e);
			SMSLogger.loggingSMS4Soc(context.getAdapterName(), context.getDescription(), "RECEAINNA012");
			throw new Exception(context.getAdapterName() + " | login error - " + e.getMessage(), e);
		}
	}	
	
	

}
