package com.eactive.eai.rms.onl.common.util;

import java.io.ObjectInputStream;
import java.io.StringReader;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * <pre>
 * 기능 : 원격지의 URI를 실행하여 해당 리소스를 반환한다.
 * GET / POST 모두 지원한다.
 * </pre>
 */
public class CallAgentUtil
{

	private static final Logger logger = Logger.getLogger(CallAgentUtil.class);
	public static MultiThreadedHttpConnectionManager CONNECTION_MANAGER = null;
	public static final String AGENT_CALL = "AGENT_CALL";
	private static int DEFAULT_CONNECT_TIME_OUT = 1000; // 0 값을 입력하면 디폴트 값이 쓰이는 듯.

	private GetMethod get = null;
	private PostMethod post= null;
	private String target = null;

	private static DocumentBuilderFactory dbFactory;
	private DocumentBuilder docBuilder;
	private Document doc;

	static
	{
		CONNECTION_MANAGER = new MultiThreadedHttpConnectionManager();
		CONNECTION_MANAGER.setConnectionStaleCheckingEnabled(true);
		CONNECTION_MANAGER.setMaxConnectionsPerHost(50);
		CONNECTION_MANAGER.setMaxTotalConnections(100);

		dbFactory = DocumentBuilderFactory.newInstance();
	}

	/*
	 * 원격지 호스트에 접속하여 GET방식으로 해당 파일을 실행하고 얻은 결과를 String으로 리턴한다.
	 */
	public String getAgentDataToString(String url)
			throws SocketTimeoutException, Exception
	{
		if (url == null || url.length() < 1)
			throw new IllegalArgumentException("Agent URL is NULL");

		String rtnValue = null;

		try
		{
			target = url;
			HttpClient httpClient = new HttpClient(CallAgentUtil.CONNECTION_MANAGER);

			get = new GetMethod(target);
			get.setFollowRedirects(true);

			// 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(6000));

			int iGetResultCode = httpClient.executeMethod(get);

			// 실행 성공
			if (iGetResultCode >= 200 && iGetResultCode <= 299)
			{
				rtnValue = get.getResponseBodyAsString().trim();
			}
			else
			{
				logger.error("########## CallAgentUtil.getAgentData('" + url + "') ERROR ##########");
				logger.error("########## Receive Data is Nothing : iGetResultCode=" + iGetResultCode);
			}
		}
		catch (SocketTimeoutException e)
		{
			logger.error("AGENT IMPORT TIMEOUT :" + target);
			logger.error(e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("AGENT IMPORT ERROR :" + target);
			logger.error(e);
			throw e;
		}
		finally
		{
			if (get != null)
			{
				try
				{
					get.releaseConnection();
				}
				catch (Exception ex)
				{
					logger.error(" error : ", ex); 
				}
			}
		}

		return rtnValue;
	}

	/*
	 * 원격지 호스트에 접속하여 POST방식으로 해당 파일을 실행하고 얻은 결과를 String으로 리턴한다.
	 */
	public String getAgentDataToString(String url, NameValuePair[] postParameters)
			throws SocketTimeoutException, Exception
	{
		if (url == null || url.length() < 1)
			throw new IllegalArgumentException("Agent URL is NULL");

		String rtnValue = null;

		try
		{
			target = url;
			HttpClient httpClient = new HttpClient(CallAgentUtil.CONNECTION_MANAGER);

			post = new PostMethod(target);
			//post.setFollowRedirects(true);

			if (postParameters != null && postParameters.length > 0)
				post.setRequestBody(postParameters);

			
            // 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(6000));
			
			int iGetResultCode = httpClient.executeMethod(post);

			// 실행 성공
			if (iGetResultCode >= 200 && iGetResultCode <= 299)
			{
				rtnValue = post.getResponseBodyAsString().trim();
			}
			else
			{
				logger.error("########## CallAgentUtil.getAgentData('" + url + "') ERROR ##########");
				logger.error("########## Receive Data is Nothing : iGetResultCode=" + iGetResultCode);
			}
		}
		catch (SocketTimeoutException e)
		{
			logger.error("AGENT IMPORT TIMEOUT :" + target);
			logger.error(e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("AGENT IMPORT ERROR :" + target);
			logger.error(e);
			throw e;
		}
		finally
		{
			if (post != null)
			{
				try
				{
					post.releaseConnection();
				}
				catch (Exception ex)
				{
					logger.error(" error : ", ex); 
				}
			}
		}

		return rtnValue;
	}
	
	public String getPostData( String url, NameValuePair[] postParameters ) throws Exception {
	    String result = "" ;
	    
	    if( url == null || url.length() < 1 ) {
	        throw new IllegalArgumentException("Agent url is null" );
	    }
	    
	    try {
	        target = url ;
	        HttpClient httpClient = new HttpClient(CallAgentUtil.CONNECTION_MANAGER);	        
	        post = new PostMethod(target);
	        
	        //String charset = post.getRequestCharSet();

	        //post.addRequestHeader("Content-Type", "text/html; charset=utf-8");
	        post.setRequestBody(postParameters);
	        
	        
	        // 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(6000));
	        
	        int code = httpClient.executeMethod(post);
	        if( code >= 200 && code <= 299 ) {
	            // 성공
	            result = post.getResponseBodyAsString().trim();
	            result = URLDecoder.decode(result, "utf-8");

	        } else {
	            logger.error("url=" + url );
	            logger.error("result=" + code );
	        }
	    } catch ( SocketTimeoutException e ) {
	        logger.error("AGENT IMPORT TIMEOUT !");
	        logger.error("url=" + url );
	    } catch ( Exception e ) {
	        logger.error("Exception =>" + e.getMessage());
	    } finally {
	        if( post != null ) {
	            try {
	                post.releaseConnection();
	            } catch ( Exception ex ) {
	            	logger.error(" error : ", ex); 
	            }
	        }
	    }
	    
	    return result;
	}

	/*
	 * 원격지 호스트에 접속하여 GET방식으로 해당 파일을 실행하고 얻은 Xml 파일을 Document로 리턴한다.
	 */
	public Document getAgentDataToDocument(String url) throws SAXException,
			SocketTimeoutException, Exception
	{
		if (url == null || url.length() < 1)
			throw new IllegalArgumentException("Agent URL is NULL");

		try
		{
			target = url;
			HttpClient httpClient = new HttpClient(
					CallAgentUtil.CONNECTION_MANAGER);

			get = new GetMethod(target);
			get.setFollowRedirects(true);

            // 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(6000));
			
			int iGetResultCode = httpClient.executeMethod(get);

			// 실행 성공
			if (iGetResultCode >= 200 && iGetResultCode <= 299)
			{
				// YUN_DEBUG : parse Exception debugging (2008-05-20)								
				String retXml = get.getResponseBodyAsString();	
				dbFactory.setIgnoringElementContentWhitespace(true);
				docBuilder = dbFactory.newDocumentBuilder();
				doc = docBuilder.parse(new InputSource(new StringReader(retXml.trim())));				
				// old-code
				//docBuilder = dbFactory.newDocumentBuilder();				
				//doc = docBuilder.parse(get.getResponseBodyAsStream());				
			}
			else
			{
				logger.error("########## CallAgentUtil.getAgentData('" + url
						+ "') ERROR ##########");
				logger.error("########## Receive Data is Nothing : iGetResultCode=" + iGetResultCode);
				return null ;
			}
		}
		catch (SAXException e)
		{
			logger.error("AGENT Parsing Error :" + target);
			logger.error(e);
			throw e;
		}
		catch (SocketTimeoutException e)
		{
			logger.error("AGENT IMPORT TIMEOUT :" + target);
			logger.error(e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("AGENT IMPORT ERROR :" + target);

			// 테스트 환경에서는 전체 인스턴수중 일부인스턴스만 살려두기 때문에
			// 에러로그가 너무 많이 남아서 선택사항으로 한다. ( 2009.08.10. YUN )
			if( logger.isDebugEnabled() ) {
			    logger.error(e);
			}
			
			throw e;
		}
		finally
		{
			if (get != null)
			{
				try
				{
					get.releaseConnection();
				}
				catch (Exception ex){logger.error(" error : ", ex); }
			}
		}

		return doc;
	}

	/*
	 * 원격지 호스트에 접속하여 POST방식으로 해당 파일을 실행하고 얻은 Xml 파일을 Document로 리턴한다.
	 */
	public Document getAgentDataToDocument(String url, NameValuePair[] postParameters) throws SAXException,
			SocketTimeoutException, Exception
	{
		if (url == null || url.length() < 1)
			throw new IllegalArgumentException("Agent URL is NULL");

		try
		{
			target = url;
			HttpClient httpClient = new HttpClient(
					CallAgentUtil.CONNECTION_MANAGER);

			post = new PostMethod(target);
			//post.setFollowRedirects(true);

			if (postParameters != null && postParameters.length > 0)
				post.setRequestBody(postParameters);

			
            // 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(6000));
            
			int iGetResultCode = httpClient.executeMethod(post);

			// 실행 성공
			if (iGetResultCode >= 200 && iGetResultCode <= 299)
			{
				// YUN_DEBUG : parse Exception debugging (2008-05-20)								
				String retXml = post.getResponseBodyAsString();
				
				// 테스트
				if( logger.isDebugEnabled() ) {
				    logger.debug(retXml);
				}
				
				dbFactory.setIgnoringElementContentWhitespace(true);
				docBuilder = dbFactory.newDocumentBuilder();
				doc = docBuilder.parse(new InputSource(new StringReader(retXml.trim())));				
				
				// old-code
				// docBuilder = dbFactory.newDocumentBuilder();
				// doc = docBuilder.parse(post.getResponseBodyAsStream());
			}
			else
			{
				logger.error("########## CallAgentUtil.getAgentData('" + url + "') ERROR ##########");
				logger.error("########## Receive Data is Nothing : iGetResultCode=" + iGetResultCode);
				return null ;
			}
		}
		catch (SAXException e)
		{
			logger.error("AGENT Parsing Error :" + target);
			logger.error(e);
			throw e;
		}
		catch (SocketTimeoutException e)
		{
			logger.error("AGENT IMPORT TIMEOUT :" + target);
			logger.error(e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("AGENT IMPORT ERROR :" + target);
			logger.error(e);
			throw e;
		}
		finally
		{
			if (post != null)
			{
				try
				{
					post.releaseConnection();
				}
				catch (Exception ex){logger.error(" error : ", ex); }
			}
		}

		return doc;
	}

	public Object getAgentDataToObject(String url)
			throws SocketTimeoutException, Exception
	{
		Object obj = null;
		ObjectInputStream ois = null;

		if (url == null || url.length() < 1)
			throw new IllegalArgumentException("Agent URL is NULL");

		try
		{
			target = url;

			HttpClient httpClient = new HttpClient(
					CallAgentUtil.CONNECTION_MANAGER);

			get = new GetMethod(target);
			get.setFollowRedirects(true);

			
            // 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(6000));
			
			int iGetResultCode = httpClient.executeMethod(get);

			// 실행 성공
			if (iGetResultCode >= 200 && iGetResultCode <= 299)
			{
				ois = new ObjectInputStream(get.getResponseBodyAsStream());
				obj = ois.readObject();
			}
			else
			{
				logger.error("########## CallAgentUtil.getAgentData('" + url
						+ "') ERROR ##########");
				logger.error("########## Receive Data is Nothing : iGetResultCode=" + iGetResultCode);
			}
		}
		catch (SocketTimeoutException e)
		{
			logger.error("AGENT IMPORT TIMEOUT :" + target);
			logger.error(e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("AGENT IMPORT ERROR :" + target);
			logger.error(e);
			throw e;
		}
		finally
		{
			if (ois != null)
			{
				ois.close();
			}

			if (get != null)
			{
				try
				{
					get.releaseConnection();
				}
				catch (Exception ex){logger.error(" error : ", ex); }
			}
		}

		return obj;
	}
	
	
	/*
	 * 원격지 호스트에 접속하여 GET방식으로 해당 파일을 실행하고 얻은 Xml 파일을 Document로 리턴한다.
	 */
	public Document getAgentDataToDocument_ETC(String url) throws SAXException,
			SocketTimeoutException, Exception
	{
		if (url == null || url.length() < 1)
			throw new IllegalArgumentException("Agent URL is NULL");

		try
		{
			target = url;
			HttpClient httpClient = new HttpClient(
					CallAgentUtil.CONNECTION_MANAGER);

			get = new GetMethod(target);
			get.setFollowRedirects(true);
			//utf-8 로 인코딩해야함
			logger.info("get.getResponseCharSet() [" + get.getResponseCharSet() +"]");
            // 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(30000));
			
			int iGetResultCode = httpClient.executeMethod(get);

			// 실행 성공
			if (iGetResultCode >= 200 && iGetResultCode <= 299)
			{
				
				// YUN_DEBUG : parse Exception debugging (2008-05-20)								
				String retXml = get.getResponseBodyAsString();	
				dbFactory.setIgnoringElementContentWhitespace(true);
				docBuilder = dbFactory.newDocumentBuilder();			
				doc = docBuilder.parse(new InputSource(new StringReader(retXml.trim())));	
				
				logger.info("getAgentData success");
			}
			else
			{
				logger.error("########## CallAgentUtil.getAgentData('" + url
						+ "') ERROR ##########");
				logger.error("########## Receive Data is Nothing : iGetResultCode=" + iGetResultCode);
				return null ;
			}
		}
		catch (SAXException e)
		{
			logger.error("AGENT Parsing Error :" + target);
			logger.error(e);
			throw e;
		}
		catch (SocketTimeoutException e)
		{
			logger.error("AGENT IMPORT TIMEOUT :" + target);
			logger.error(e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("AGENT IMPORT ERROR :" + target);

			// 테스트 환경에서는 전체 인스턴수중 일부인스턴스만 살려두기 때문에
			// 에러로그가 너무 많이 남아서 선택사항으로 한다. ( 2009.08.10. YUN )
			if( logger.isDebugEnabled() ) {
			    logger.error(e);
			}
			
			throw e;
		}
		finally
		{
			if (get != null)
			{
				try
				{
					get.releaseConnection();
				}
				catch (Exception ex){logger.error(" error : ", ex); }
			}
		}

		return doc;
	}
	
	/*
	 * 원격지 호스트에 접속하여 GET방식으로 해당 파일을 실행하고 얻은 결과를 String으로 리턴한다.(터암아웃을 파라메타로 넘김)
	 */
	public String getAgentDataToString(String url, String timeOutSet)
			throws SocketTimeoutException, Exception
	{
		
		if (url == null || url.length() < 1)
			throw new IllegalArgumentException("Agent URL is NULL");

		String rtnValue = null;

		try
		{
			target = url;
			HttpClient httpClient = new HttpClient(CallAgentUtil.CONNECTION_MANAGER);

			get = new GetMethod(target);
			get.setFollowRedirects(true);

			// 2009.05.22 EAI 서버가 down 되었을 경우 대기시간이 너무 길어 timeout 값을 지정한다.
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(DEFAULT_CONNECT_TIME_OUT);
            httpClient.getParams().setParameter("http.socket.timeout", new Integer(timeOutSet));

			int iGetResultCode = httpClient.executeMethod(get);

			// 실행 성공
			if (iGetResultCode >= 200 && iGetResultCode <= 299)
			{
				rtnValue = get.getResponseBodyAsString().trim();
			}
			else
			{
				logger.error("########## CallAgentUtil.getAgentData('" + url + "') ERROR ##########");
				logger.error("########## Receive Data is Nothing : iGetResultCode=" + iGetResultCode);
			}
		}
		catch (SocketTimeoutException e)
		{
			logger.error("AGENT IMPORT TIMEOUT :" + target);
			logger.error(e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("AGENT IMPORT ERROR :" + target);
			logger.error(e);
			throw e;
		}
		finally
		{
			if (get != null)
			{
				try
				{
					get.releaseConnection();
				}
				catch (Exception ex)
				{
					logger.error(" error : ", ex); 
				}
			}
		}

		return rtnValue;
	}
	
	
	

	/*
	 * Agent URL을 가져온다.
	 */
	public String getUrl()
	{
		return target;
	}

}
