package com.dev.swms.server.utils;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.InitializingBean;

import com.dev.swms.server.model.interfaceLog.ResponseCode;
/**
 * 接口连接工具类
 * @author  dev
 * @version $Id: ConnectionHelper.java,v 1.2 2010/06/01 09:14:16 peng.lei Exp $
 */

public class ConnectionHelper implements InitializingBean {
	protected final Log logger = LogFactory.getLog(this.getClass());
	/** 默认传输协议 */
	private static String DEFAULT_TRANSPORT_PROTOCOL = "http";
	
	/** Webmethod要求的PostMethod的输入参数 */
	private static String INPUT_PARAM_KEY = "indata";
	
	/** 默认字符编码 */
	private static String DEFAULT_ACCESS_URI = "/service/mk.edi.service";
	
	/** 默认URI */
	private static String DEFAULT_CHARACTOR_SET = "utf-8";
	
	/** 协议 */
	protected String protocol = DEFAULT_TRANSPORT_PROTOCOL;//
	
	protected String contextName = "/adapter";
	
	/** 主机地址 */
	protected String host = "localhost";//
	
	/** 编码 */
	protected String charset = DEFAULT_CHARACTOR_SET;
	
	/** 默认端口:80 */
	protected int port = 80;//端口
	
	protected String uri = DEFAULT_ACCESS_URI;//WebMethods的uri路径
	
	/** 重试次数 */
	protected int numOfReTry = 2;//
	
	/**http连接超时 @see org.apache.commons.httpclient.params.HttpConnectionParams#CONNECTION_TIMEOUT */
	protected int connectionTimeout = 0;
	/**so超时 @see org.apache.commons.httpclient.params.HttpConnectionParams#SO_TIMEOUT */
	protected int soTimeout = 0;
	
	private HttpClient httpclient;
	
	private HttpConnectionManager connectionManager;
	
	/**
	 * 是否连接
	 */
	protected boolean isAlive = false;

	/** 一个主机的最大并发连接数 */
	protected int maxConnectionPerHost = 10;

	/** 总的最大并发连接数 */
	protected int maxConnectionOverrall = 20;
	
	public ConnectionHelper() {
	}
	
	public int getMaxConnectionOverrall() {
		return maxConnectionOverrall;
	}

	public void setMaxConnectionOverrall(int maxConnectionOverrall) {
		this.maxConnectionOverrall = maxConnectionOverrall;
	}

	public int getMaxConnectionPerHost() {
		return maxConnectionPerHost;
	}

	public void setMaxConnectionPerHost(int maxConnectionPerHost) {
		this.maxConnectionPerHost = maxConnectionPerHost;
	}

	public boolean isAlive() {
		return isAlive;
	}

	/**
	 * 发送ＸＭＬ文档
	 * @param xml 内容
	 * @return 服务器端响应：1表示成功，否则为出错信息
	 */
	public String sendMessage(String xml) {
		if(!isAlive) {
			//如果不连通则再试着连一次，如果还不通则抛异常
			if(!isHostReachable()) {
				throw new ServerUnreachableException(new Date() + ":Fail to connect to host[" + protocol + "://" + host + ":" + port + contextName + uri + "]," +
						"thus no data will be exchanged between OMS-TMS module and WebMethods module");
			}
		}
		return sendMessage(xml, 0);
	}
	
	/**
	 * 发送ＸＭＬ文档
	 * @param xml 内容
	 * @param times 第几次发送
	 * @return 服务器端响应：1表示成功，否则为出错信息
	 */
	protected String sendMessage(String xml, int times) {
	    if(times > numOfReTry) {
	    	isAlive = false;
	    	throw new RetryFailureException("fail to send message after retrying for " + numOfReTry + " times, " +
	    			"host[" + protocol + "://" + host + ":" + port + "] maybe down!");
	    }
		PostMethod post = new PostMethod(contextName + uri) {
			public String getRequestCharSet() {
				return "UTF-8";
			}
		};
//	    post.setRequestHeader( "Content-type" , "charset=" + charset);
		//用Name-Value方式传
		post.addParameter(new NameValuePair(INPUT_PARAM_KEY, xml));
//	    RequestEntity entity = new ByteArrayRequestEntity(xml.getBytes());
//	    post.setRequestEntity(entity);
		//System.out.println(new Date() + "[SSSSSSSSSSSSSSSSSent]:" + xml);
	    try {
	         int result = httpclient.executeMethod(post);
	         //System.out.println(new Date() + "[1AAAAAAAAAFeedBack]: statusCode="+result+"; content="+post.getResponseBodyAsString());
	         if(result == 200) {
	        	 return digestResponse(post.getResponseBodyAsString());
	         } else {
	        	 return post.getResponseBodyAsString();
	         }
		} catch (IOException e) {
			if(logger.isDebugEnabled()) {
				e.printStackTrace();
			}
			return e.getMessage();
		} finally {
			post.releaseConnection();
	    }
		//return sendMessage(xml, times + 1);
	}
	
	/**
	 * 解析响应
	 * @param xml 响应的ＸＭＬ文档
	 * @return 1表示成功,否则为具体的出错信息
	 */
	protected String digestResponse(String xml) {
		Document xmlDoc;
		try {
			xmlDoc = DocumentHelper.parseText(xml);
			Element root = xmlDoc.getRootElement();
			String sender = root.elementTextTrim("MSGCODE");
			String content = root.elementTextTrim("MSGCONTENT");
			if(ResponseCode.SUCCESS.equals(sender)) {
				return ResponseCode.SUCCESS;
			}else {
				return content;
			}
		} catch (DocumentException e) {
			if(logger.isDebugEnabled()) {
				e.printStackTrace();
			}
			return e.getMessage();
		}
	}
	
	/**
	 * 判断主机是否可连通
	 * @return
	 */
	public boolean isHostReachable() {
		 boolean results = false;
		GetMethod get = new GetMethod(contextName + uri);
	     try {
	    	 int result = httpclient.executeMethod(get);
	    	 results =  (result < 300 && result >=200);
	     } catch (HttpException e) {
	    	if(logger.isDebugEnabled()) {
	    		e.printStackTrace();
	    	}
		} catch (IOException e) {
			if(logger.isDebugEnabled()) {
	    		e.printStackTrace();
	    	}
		} finally {
			get.releaseConnection();
		}
		if(results) {
			logger.info("[info]success to connect to host[" + protocol + "://" + host + ":" + port + contextName + uri + "]," );
			//System.out.println("[out]success to connect to host[" + protocol + "://" + host + ":" + port + contextName + uri + "]," );
		} else {
			this.outputWarnMessage();
		}
		isAlive = results;
		return results;
	}
	public void afterPropertiesSet() throws Exception {
		httpclient = new HttpClient(connectionManager);
		HostConfiguration config = new HostConfiguration();
		httpclient.setHostConfiguration(config);
	    httpclient.getHostConfiguration().setHost(host, port, protocol);
	    int ct = connectionTimeout == 0 ? 3000 : connectionTimeout;
	    int sot = soTimeout == 0 ? 3000 : soTimeout;
	    httpclient.getHostConfiguration().getParams().setParameter(HttpConnectionParams.CONNECTION_TIMEOUT, ct);
	    httpclient.getHostConfiguration().getParams().setParameter(HttpConnectionParams.SO_TIMEOUT, sot);
		HttpConnectionManagerParams params = new HttpConnectionManagerParams();
		Map map = new HashMap();
		map.put(httpclient.getHostConfiguration(), Integer.valueOf(maxConnectionPerHost));
		params.setParameter(HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, map);
		params.setParameter(HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, Integer.valueOf(maxConnectionOverrall));
		connectionManager.setParams(params);
//	    isHostReachable();
	}

	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public HttpConnectionManager getConnectionManager() {
		return connectionManager;
	}

	public void setConnectionManager(HttpConnectionManager connectionManager) {
		this.connectionManager = connectionManager;
	}

	public int getConnectionTimeout() {
		return connectionTimeout;
	}

	public void setConnectionTimeout(int connectionTimeout) {
		this.connectionTimeout = connectionTimeout;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public HttpClient getHttpclient() {
		return httpclient;
	}

	public void setHttpclient(HttpClient httpclient) {
		this.httpclient = httpclient;
	}

	public int getNumOfReTry() {
		return numOfReTry;
	}

	public void setNumOfReTry(int numOfReTry) {
		this.numOfReTry = numOfReTry;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getProtocol() {
		return protocol;
	}

	public void setProtocol(String protocol) {
		this.protocol = protocol;
	}

	public int getSoTimeout() {
		return soTimeout;
	}

	public void setSoTimeout(int soTimeout) {
		this.soTimeout = soTimeout;
	}

	public String getUri() {
		return uri;
	}

	public void setUri(String uri) {
		this.uri = uri;
	}
	public String getContextName() {
		return contextName;
	}

	public void setContextName(String contextName) {
		if(contextName != null) {
			this.contextName = contextName;
		} else {
			this.contextName = "";
		}
	}
	
	public void outputWarnMessage() {
		logger.error(new Date() + ":Fail to connect to host[" + protocol + "://" + host + ":" + port + contextName + uri + "]," +
		"thus no data will be exchanged between OMS-TMS module and WebMethods module");
		//System.out.println(new Date() + ":Fail to connect to host[" + protocol + "://" + host + ":" + port + contextName + uri + "]," +
		//"thus no data will be exchanged between OMS-TMS module and WebMethods module");
	}
}

