package com.eactive.eai.adapter.webt;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;

import javax.resource.NotSupportedException;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.adapter.RequestDispatcher;
import com.eactive.eai.common.util.Logger;
import com.tmax.nio.jtmax.JTmaxNJGMessageHandler;
import com.tmax.nio.jtmax.JTmaxNServer;
import com.tmax.nio.jtmax.JTmaxNServiceHandler;
import com.tmax.nio.util.TmaxAliveInfo;

import jeus.transaction.TxHelper;
import tmax.webt.WebtBuffer;
import tmax.webt.io.WebtStringBuffer;
import tmax.webt.jeus.TmaxXid;

public class CustomJTmaxNJGMessageHandler implements JTmaxNJGMessageHandler {
	private AdapterVO vo;
	private Properties prop;
	private JTmaxNServer server;
	private String serverName;
	private int port;

	public static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);

	public CustomJTmaxNJGMessageHandler(AdapterVO vo, Properties prop) {
		this.vo = vo;
		this.prop = prop;
		this.serverName = vo.getAdapterGroupName() + "." + vo.getName();
		try {
			this.port = Integer.parseInt(prop.getProperty("port.number", "-1"));
		} catch (Exception e) {
			this.port = -1;
		}
	}

	private String getJTmaxServerSimpeInfo() {
		StringBuilder sb = new StringBuilder();
		sb.append("JTmaxNServer = [").append(serverName).append(":").append(port).append("]");
		return sb.toString();
	}

	private XAResource getXAResource() {
		return TxHelper.getTMXAResource();
	}

	@Override
	public void bulkRecover(Xid[] xids) throws NotSupportedException {
		if (logger.isDebug()) {
			logger.debug("bulkRecover start " + getJTmaxServerSimpeInfo());
		}

		if (xids == null) {
			logger.debug("xids is null");
			return;
		}

		TmaxXid tmaxXid = null;
		for (int i = 0; i < xids.length; i++) {
			tmaxXid = (TmaxXid) xids[i];
			int decision = tmaxXid.getDecision();

			if (logger.isDebug()) {
				logger.debug("xids[" + i + "] = " + xids[i] + ", decision = " + decision + ", isRecover = "
						+ tmaxXid.isRecover());
			}

			switch (decision) {
			case tmax.webt.io.Webt.TM_XA_COMMIT:
			case tmax.webt.io.Webt.TM_XA_COMMIT2:
				xaCommit(-1, xids[i], false, null);
				break;
			case tmax.webt.io.Webt.TM_XA_RBACK:
			case tmax.webt.io.Webt.TM_XA_RBACK2:
				xaRollback(-1, xids[i], null);
				break;
			default:
				if (logger.isDebug()) {
					logger.debug("decision is invalid");
				}
				break;
			}
		}
		if (logger.isDebug()) {
			logger.debug("bulkRecover end");
		}
	}

	@Override
	public void closeSession(int sessionId) {
		if (logger.isDebug()) {
			logger.debug("closeSession start " + getJTmaxServerSimpeInfo());
			logger.debug("closed sessionId = " + sessionId);
			logger.debug("closeSession end");
		}
	}

	@Override
	public void closeTrunk(TmaxAliveInfo info) {
		if (logger.isDebug()) {
			logger.debug("closeTrunk start " + getJTmaxServerSimpeInfo());
		}

		for (int i = 0; i < info.getTrunkSize(); i++) {
			Hashtable<Integer, String> table = info.getTrunk(i);
			Iterator<Integer> it = table.keySet().iterator();

			while (it.hasNext()) {
				Integer key = it.next();
				String ip = table.get(key);
				if (logger.isDebug()) {
					logger.debug("client index = " + key + ", ip = " + ip);
				}
			}
		}
		if (logger.isDebug()) {
			logger.debug("closeTrunk end");
		}

	}

	@Override
	public Xid[] recover() {
		if (logger.isDebug()) {
			logger.debug("recover start " + getJTmaxServerSimpeInfo());
		}
		Xid[] xids = null;
		try {
			xids = getXAResource().recover(XAResource.TMSTARTRSCAN);
			if (xids != null && xids.length == 0) {
				xids = getXAResource().recover(XAResource.TMNOFLAGS);
				if (logger.isDebug())
					logger.debug("[TMNOFLAGS] recover xids = " + xids);
			}
			if (xids != null && xids.length == 0) {
				xids = getXAResource().recover(XAResource.TMFAIL);
				if (logger.isDebug())
					logger.debug("[TMFAIL] recover xids = " + xids);
			}
			if (xids != null && xids.length == 0) {
				xids = getXAResource().recover(XAResource.TMSUSPEND);
				if (logger.isDebug())
					logger.debug("[TMSUSPEND] recover xids = " + xids);
			}
		} catch (XAException e) {
			e.printStackTrace();
			return null;
		}

		if (logger.isDebug())
			logger.debug("recover xids = " + xids);

		if (xids != null) {
			if (logger.isDebug()) {
				logger.debug("recover xids length = " + xids.length);
				for (int i = 0; i < xids.length; i++) {
					logger.debug("xid[" + i + "] = " + xids[i]);
				}
			}
		}

		if (logger.isDebug())
			logger.debug("recover end");

		return xids;
	}

	@Override
	public void serviceExecute(int sessionId, String serviceName, WebtBuffer receiveBuffer) {
		if (logger.isDebug()) {
			logger.debug("serviceExcute(int, String, WebtBuffer) " + "start " + getJTmaxServerSimpeInfo());

			StringBuilder sb = new StringBuilder();
			sb.append("\nsessionId = ").append(sessionId);
			sb.append("\nserviceName = ").append(serviceName);
			sb.append("\nreceiveBuffer = ").append(receiveBuffer);
			logger.debug(sb.toString());

			logger.debug("tpacall with TPNOREPLY flag");
		}

		serviceExecute(sessionId, null, serviceName, receiveBuffer, null);

		if (logger.isDebug())
			logger.debug("serviceExcute(int, String, WebtBuffer) end");
	}

	@Override
	public void serviceExecute(int sessionId, Xid xid, String serviceName, WebtBuffer receiveBuffer,
			JTmaxNServiceHandler serviceHandler) {
		if (logger.isDebug()) {
			// "FIELD_TYPE", "STRING_TYPE", "CARRAY_TYPE"
			logger.debug("@@@@@@@Service Name=" + serviceName + " : BufferTypeString = "
					+ receiveBuffer.getBufferTypeString());
			logger.debug("@@@@@@@Service Name=" + serviceName + new String(receiveBuffer.getBytes()));
			logger.debug("======= serviceExcute(int, String, WebtBuffer, JTmaxNServiceHandler) " + "start ======="
					+ getJTmaxServerSimpeInfo());
		}

		// 서비스 처리 로직 부분
		byte[] request = receiveBuffer.getBytes();
		byte[] response = request;
		try {
			RequestDispatcher dispatcher = RequestDispatcher.getRequestDispatcher(vo.getAdapterGroupName());
			response = (byte[]) dispatcher.handle(vo.getName(), request, prop);
		} catch (Exception e) {
			logger.error("RequestDispatcher call error", e);
		}

		WebtBuffer sendBuffer = new WebtStringBuffer();
		sendBuffer.setBytes(response);
		if (serviceHandler != null) {
			serviceHandler.serviceFinished(JTmaxNServiceHandler.TPSUCCESS, 0, sendBuffer);
		}
	}

	@Override
	public void xaCommit(int sessionId, Xid xid, boolean flag, JTmaxNServiceHandler jtmaxnservicehandler) {
		if (logger.isDebug()) {
			logger.debug("xaCommit start " + getJTmaxServerSimpeInfo());
			logger.debug("xaCommit end");
		}
	}

	@Override
	public void xaPrepare(int sessionId, Xid xid, JTmaxNServiceHandler jtmaxnservicehandler) {
		if (logger.isDebug()) {
			logger.debug("xaPrepare start " + getJTmaxServerSimpeInfo());
			logger.debug("xaPrepare end");
		}
	}

	@Override
	public void xaRollback(int sessionId, Xid xid, JTmaxNServiceHandler jtmaxnservicehandler) {
		if (logger.isDebug()) {
			logger.debug("xaRollback start " + getJTmaxServerSimpeInfo());
			// new Thread(new XARollbackWorker(sessionId, xid, serviceHandler)).start();
			logger.debug("xaRollback end");
		}
	}

	public void setJTmaxNServer(JTmaxNServer server) {
		this.server = server;
	}
}
