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

import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
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;
import com.eactive.eai.common.util.MessageUtil;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.methods.GetMethod;
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.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.util.Properties;

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

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

		String sendData = "";
		if (data instanceof String) {
			sendData = URLEncoder.encode((String) data, vo.getEncode());
		} else if (data instanceof byte[]) {
			sendData = URLEncoder.encode(new String((byte[]) data, vo.getEncode()), vo.getEncode());
		}
		StringBuilder querySb = new StringBuilder();
		if (logger.isDebug()) {
			logger.debug("HttpClientAdapterServiceGet] GET Method URLEncoder");
		}

		if (RESPONSE_TYPE_ASYNC.equals(vo.getResponseType())) {
			isAsync = true;
			querySb.append("type=async&");
		}
		querySb.append(vo.getParameterName()).append("=");
		querySb.append(sendData);
		method.setQueryString(querySb.toString());

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

		int status = -1;
		try {
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.txlog(vo.getAdapterGroupName() + vo.getAdapterName(),
						"SEND [" + sendData + "]" + CommonLib.getDumpMessage(sendData));
			}

			StopWatch stopWatch = new StopWatch();
			stopWatch.start();
			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());

			// status 200(정상) 이외에는 error 처리
			if (status != 200) {
				try {
					logger.error("HttpClientAdapterServiceGet] 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[] responseMessage = method.getResponseBody();
			if (isAsync && stopWatch.getTime() > vo.getSlowTranTime() && logger.isWarn()) {
				logger.warn("HttpClientAdapterServiceGet] URL[" + vo.getUrl() + "] lazy async response time = "
						+ stopWatch.toString() + " responseMessage=" + new String(responseMessage, responseCharSet));
			}

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

			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.txlog(vo.getAdapterGroupName() + vo.getAdapterName(),
						"RECV [" + new String(responseMessage, responseCharSet) + "]"
								+ CommonLib.getDumpMessage(responseMessage));
			}
			AdapterManager m = AdapterManager.getInstance();
			AdapterGroupVO agvo = m.getAdapterGroupVO(vo.getAdapterGroupName());
			if (MessageUtil.isBytesMessage(agvo.getMessageType())) {
				return responseMessage;
			} else {
				return new String(responseMessage, vo.getEncode());
			}
		} catch (SocketTimeoutException ste) { // Read Timeout :: HttpClient 3.1일 경우
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceGet] SocketTimeoutException : " + ste.toString(), ste);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceGet] SocketTimeoutException : " + ste.toString(), ste);
			}
			throw ste;
		} catch (ConnectException ce) {
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceGet] Connection Exception : " + ce.toString(), ce);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceGet] Connection Exception : " + ce.toString(), ce);
			}
			throw ce;
		} catch (Exception e) {
			if (vo.getTraceLevel() >= 3) {
				HttpMemoryLogger.error(vo.getAdapterGroupName() + vo.getAdapterName(),
						"HttpClientAdapterServiceGet] Exception : " + e.toString(), e);
			}
			if (logger.isError()) {
				logger.error("HttpClientAdapterServiceGet] 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("RDCEAIAHA014", msgArgs);
				if (logger.isDebug()) {
					logger.debug(resMsg);
				}
			}
		}
	}

}
