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

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.Properties;

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 com.eactive.eai.adapter.Keys;
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.util.CommonLib;

public class HttpClientAdapterServiceBody extends HttpClientAdapterServiceSupport {
	public Object execute(Properties prop, Object data, Properties tempProp) throws Exception {
		HttpClientAdapterVO vo = super.setting(prop, tempProp);

		boolean isAsync = false;
		if (RESPONSE_TYPE_ASYNC.equals(vo.getResponseType())) {
			isAsync = true;
		}
		PostMethod method = new PostMethod(vo.getUrl());
		HttpClient mclient = this.client;
		
		configureHttpClient(mclient, method, vo, vo.getUrl(), vo.getContentType());

		String sendData = "";
		if (data instanceof String) {
			sendData = (String) data;
		} else if (data instanceof byte[]) {
			sendData = new String((byte[]) data, vo.getEncode());
		}

		mclient.getParams().setContentCharset(vo.getEncode());

		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("HttpClientAdapterServiceBody] " + CONTENT_TYPE_KEY + "(" + contentTypeValue + ")");
		}

		if ("Y".equals(vo.getUrlEncodeYn())) {
			sendData = java.net.URLEncoder.encode(sendData);
		}

		method.setRequestBody(sendData);

		int status = -1;

		try {

			if (logger.isDebug() && "N".equals(vo.getTestCallYn())) {
				logger.debug(
						"HttpClientAdapterServiceBody] SEND (" + vo.getAdapterGroupName() + ") = [" + sendData + "]");
				logger.debug("HttpClientAdapterServiceBody] SEND (" + vo.getAdapterGroupName() + ") = "
						+ CommonLib.getDumpMessage(sendData));
			}
			StopWatch stopWatch = new StopWatch();
			stopWatch.start();

			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.txlog(vo.getAdapterGroupName() + vo.getAdapterName(),
						"SEND [" + sendData + "]" + CommonLib.getDumpMessage(sendData));
			}
			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());

			byte[] responseMessage = method.getResponseBody();
			// status 200(정상) 이외에는 error 처리
			if (status != 200) {
				logger.error("HttpClientAdapterServiceBody] receive status[" + status + "] data["
						+ new String(responseMessage) + "]");
				throw new HttpStatusException("수신시스템을 확인하세요. HTTP 에러[ " + status + "] adapterName="
						+ vo.getAdapterGroupName() + "." + vo.getAdapterName(), status);
			}

			if (isAsync && stopWatch.getTime() > vo.getSlowTranTime() && (logger.isWarn())) {
				logger.warn("HttpClientAdapterServiceBody] URL[" + vo.getUrl() + "] lazy async response time = "
						+ stopWatch.toString() + " responseMessage=" + new String(responseMessage, responseCharSet));

			}

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

			return responseMessage;

		} catch (SocketTimeoutException ste) { // Read Timeout :: HttpClient 3.1일 경우
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceBody] SocketTimeoutException : " + ste.toString(), ste);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceBody] SocketTimeoutException : " + ste.toString(), ste);
			}
			throw ste;
		} catch (ConnectException ce) {
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceBody] Connection Exception : " + ce.toString(), ce);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceBody] Connection Exception : " + ce.toString(), ce);
			}
			throw ce;
		} catch (Exception e) {
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceBody] Exception : " + e.toString(), e);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceBody] Exception : " + e.toString(), 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);
				}
			}
		}
	}
}