
package com.eactive.eai.adapter.http.client.impl;

import com.eactive.eai.adapter.http.HttpMemoryLogger;
import com.eactive.eai.adapter.http.HttpStatusException;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceSupport;
import com.eactive.eai.adapter.http.client.HttpClientAdapterVO;
import com.eactive.eai.adapter.http.secure.CustomHttpsSocketFactory;
import com.eactive.eai.adapter.http.secure.EasySSLProtocolSocketFactory;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.CommonLib;
import com.eactive.eai.util.UrlUtil;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.Properties;

// NexCore F/W과 통신하기 위한 Adapter로 관련 Site 전용
public class HttpClientAdapterServiceNexCore extends HttpClientAdapterServiceSupport {

	public static String DEFAULT_ENCODE = "UTF-8";

	public Object execute(Properties prop, Object data, Properties tempProp) throws Exception {
		HttpClientAdapterVO vo = super.setting(prop, tempProp);
		String svcName = tempProp.getProperty(TRAN_CODE, "");

		if (StringUtils.isEmpty(svcName)) {
			throw new Exception("service name is empty");
		}

		boolean isAsync = false;

		if (vo.getUrl() == null) {
			throw new Exception("URL is NULL");
		}

		if (vo.getUrl().endsWith(".ajmd") || vo.getUrl().endsWith(".axmd")) {
			isAsync = true;
		}

		String nKesaUrl = vo.getUrl().replace("%" + TRAN_CODE + "%", svcName);

		// ENVR_INFO_DVSN_CD = L
		// FRST_DMND_SYS_IP_VAL 로 라우팅하도록 함
		boolean localCall = LOCAL_CALL_Y.equals(tempProp.getProperty(LOCAL_CALL, "N"));
		if (localCall) {
			String newIp = tempProp.getProperty(LOCAL_IP);
			if (newIp == null) {
				if (logger.isWarn()) {
					logger.warn("HttpClientAdapterServiceNexCore] LOCAL_CALL FRST_DMND_SYS_IP_VAL is empty, SKIP : "
							+ nKesaUrl);
				}
			} else {
				String newPort = PropManager.getInstance().getProperty("LOCAL", "port", "7001");
				nKesaUrl = UrlUtil.replaceIpAddress(nKesaUrl, newIp, newPort);
				if (logger.isWarn()) {
					logger.warn("HttpClientAdapterServiceNexCore] LOCAL_CALL REPLACED_URL : " + nKesaUrl);
				}
			}
		}

		PostMethod method = new PostMethod(nKesaUrl);
		HttpClient mclient = this.client;
		
		configureHttpClient(mclient, method, vo, vo.getUrl(), vo.getContentType());

		logger.debug("HttpClientAdapterServiceNexCore] ENCODE(" + vo.getEncode() + ")");

		try {
			mclient.getParams().setContentCharset(vo.getEncode());
		} catch (Exception e) {
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceNexCore] ENCODE(" + vo.getEncode() + ") ERROR : " + e.toString());
				logger.error("HttpClientAdapterServiceNexCore] ENCODE(" + vo.getEncode() + ") SKIP ");
			}
		}

		String contentTypeValue = null;
		if (StringUtils.isNotEmpty(vo.getContentType())) {
			if (StringUtils.isNotEmpty(vo.getEncode())) {
				contentTypeValue = vo.getContentType() + "; charset=" + vo.getEncode();
			} else {
				contentTypeValue = vo.getContentType();
			}
			method.setRequestHeader(CONTENT_TYPE_KEY, contentTypeValue);
		}
		if (vo.getAdapterHeaders() != null) {
			for (String key : vo.getAdapterHeaders().keySet()) {
				method.addRequestHeader(key, vo.getAdapterHeaders().get(key));
			}
		}
		if (logger.isInfoEnabled()) {
			logger.info("HttpClientAdapterServiceNexCore] " + CONTENT_TYPE_KEY + "(" + contentTypeValue + ")");
		}

		byte[] sendBytes = null;
		if (data instanceof String) {
			sendBytes = ((String) data).getBytes(vo.getEncode());
		} else if (data instanceof byte[]) {
			sendBytes = (byte[]) data;
		}

		InputStream in = new ByteArrayInputStream(sendBytes); // "utf-8"
		method.setRequestBody(in);

		int status = -1;

		try {
			if (logger.isDebug() && "N".equals(vo.getTestCallYn())) {
				logger.debug("HttpClientAdapterServiceNexCore] SEND (" + vo.getAdapterGroupName() + ") = ["
						+ new String(sendBytes, vo.getEncode()) + "]");
				logger.debug("HttpClientAdapterServiceNexCore] SEND (" + vo.getAdapterGroupName() + ") = "
						+ CommonLib.getDumpMessage(sendBytes));
			}
			StopWatch stopWatch = new StopWatch();
			stopWatch.start();

			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.txlog(vo.getAdapterGroupName() + vo.getAdapterName(),
						"SEND [" + new String(sendBytes, vo.getEncode()) + "]" + CommonLib.getDumpMessage(sendBytes));
			}
			if (vo.getUrl() != null && vo.getUrl().startsWith("https")) {
				Protocol.registerProtocol("https",
						new Protocol("https", new CustomHttpsSocketFactory(new EasySSLProtocolSocketFactory()), 443));
			}
			status = mclient.executeMethod(method);
			stopWatch.stop();

			String responseCharSet = getResponseCharSet(method.getResponseCharSet(), vo.getAdapterGroupName());

			if (status != 200) {
				try {
					logger.error("HttpClientAdapterServiceNexCore] receive status[" + status + "] data["
							+ new String(method.getResponseBody()) + "]");
				} catch (Exception e) {
					logger.error(e);
				}
				throw new HttpStatusException("수신시스템을 확인하세요. HTTP 에러[ " + status + "] adapterName="
						+ vo.getAdapterGroupName() + "." + vo.getAdapterName(), status);
			}

			// 응답으로 온 byte[]를 그대로 전달한다.
			byte[] responseMessage = method.getResponseBody();
			;
			if (isAsync && stopWatch.getTime() > vo.getSlowTranTime()) {
				if (logger.isWarn()) {
					logger.warn("HttpClientAdapterServiceNexCore] URL[" + nKesaUrl + "] lazy async response time = "
							+ stopWatch.toString() + " responseMessage="
							+ new String(responseMessage, responseCharSet));
				}
			}

			responseMessage = getEncodingConvert(responseCharSet, vo.getAdapterGroupName(), responseMessage);

			if (logger.isDebug() && "N".equals(vo.getTestCallYn())) {
				logger.debug("HttpClientAdapterServiceNexCore] responseType =" + vo.getResponseType()
						+ ", responseCharSet=" + responseCharSet);
				logger.debug("HttpClientAdapterServiceNexCore] RECV (" + vo.getAdapterGroupName() + ") = ["
						+ new String(responseMessage, responseCharSet) + "]");
				logger.debug("HttpClientAdapterServiceNexCore] RECV (" + vo.getAdapterGroupName() + ") = "
						+ CommonLib.getDumpMessage(responseMessage));
			}

			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.txlog(vo.getAdapterGroupName() + vo.getAdapterName(),
						"RECV [" + new String(responseMessage, responseCharSet) + "]"
								+ CommonLib.getDumpMessage(responseMessage));
			}

			return responseMessage;
		} catch (SocketTimeoutException ste) { // Read Timeout :: HttpClient 3.1일 경우
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceNexCore] SocketTimeoutException : " + ste.toString() + " url="
								+ nKesaUrl,
						ste);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceNexCore] SocketTimeoutException : " + ste.toString() + " url="
						+ nKesaUrl, ste);
			}
			throw ste;
		} catch (ConnectException ce) {
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceNexCore] Connection Exception : " + ce.toString() + " url=" + nKesaUrl,
						ce);
			}
			if (logger.isError()) {
				logger.error(
						"HttpClientAdapterServiceNexCore] Connection Exception : " + ce.toString() + " url=" + nKesaUrl,
						ce);
			}
			throw ce;
		} catch (Exception e) {
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceNexCore] Exception : " + e.toString() + " url=" + nKesaUrl, e);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceNexCore] Exception : " + e.toString() + " url=" + nKesaUrl, e);
			}
			throw e;
		} finally {
			method.releaseConnection();
			if (status != HttpStatus.SC_OK) {
				String[] msgArgs = new String[1];
				msgArgs[0] = String.valueOf(status);
				String resMsg = ExceptionUtil.make("RDCEAIAHA013", msgArgs);
				if (logger.isDebug()) {
					logger.debug(resMsg);
				}
			}
		}
	}
}
