package com.paic.umap.ucm.common.utils;

import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.paic.pafa.app.lwc.core.util.CollectionUtils;
/**
 * ESG调用公共类
 */
public class ESGAccesser {
    private static final Logger LOGGER = Logger.getLogger(ESGAccesser.class);
    private static final String HTTP_POST = "POST";
    private static final Map<String, String> TOKEN_CACHE = new HashMap<String, String>();
    public static final String ERROR_TOKEN = "13002";
    public static final String INVALID_TOKEN = "13012";
    //ESG平台的
    public static final String RET_STATUS = "ret";
    //ESG平台返回标识成功的代码
    public static final String STATUS_SUCCESS = "0";
    
    private String getTokenUrl;//token加签认证地址
    private String accessUrl;//接口地址
    private String vUserId;//第三方应用ID
    private String vUserPassword;//第三方应用密码
    
    public ESGAccesser(String getTokenUrl, String accessUrl, String vUserId, String vUserPassword) {
		super();
		this.getTokenUrl = getTokenUrl;
		this.accessUrl = accessUrl;
		this.vUserId = vUserId;
		this.vUserPassword = vUserPassword;
	}
    public ESGAccesser() {}


    /**
     * 调用外网工具类  JSON报文
     *
     * @param esgUrlCode esg平台注册的接口CODE
     * @param paramsMap  传入参数
     * @param httpMethod 请求的类型
     * @return 返回JSON结果
     * @throws Exception
     */
    public String inAccessOutByJson(String esgUrlCode, Map paramsMap, String httpMethod) throws Exception {
        if (StringUtils.isBlank(esgUrlCode) || StringUtils.isBlank(httpMethod)) {
            return "";
        }
        String resultString = invoke(esgUrlCode, paramsMap, httpMethod);
        JSONObject jsonObject = JSON.parseObject(resultString);
        String retStatus = jsonObject.getString(RET_STATUS);
        //13002:非法的access_token  13012:已失效的Invalid access_token
        if (ERROR_TOKEN.equals(retStatus) || INVALID_TOKEN.equals(retStatus)) {
            getAccessToken();
            resultString = invoke(esgUrlCode, paramsMap, httpMethod);
            jsonObject = JSON.parseObject(resultString);
            retStatus = jsonObject.getString(RET_STATUS);
        }
        if (!STATUS_SUCCESS.equals(retStatus)) {
            return "";
        }
        return jsonObject.getString("data");
    }
    
    
    /**
     * 调用外网工具类 XML报文
     *
     * @param esgUrlCode esg平台注册的接口CODE
     * @param xml  传入xml报文
     * @return 返回JSON结果
     * @throws Exception
     */
    public String inAccessOutByXml(String esgUrlCode, String xmlStr) throws Exception {
        if (StringUtils.isBlank(esgUrlCode) || StringUtils.isBlank(xmlStr)) {
            return "";
        }
        String resultString = this.invokeForXml(esgUrlCode, xmlStr);
        JSONObject jsonObject = JSON.parseObject(resultString);
        String retStatus = jsonObject.getString(RET_STATUS);
        //13002:非法的access_token  13012:已失效的Invalid access_token
        if (ERROR_TOKEN.equals(retStatus) || INVALID_TOKEN.equals(retStatus)) {
            getAccessToken();
            resultString = this.invokeForXml(esgUrlCode, xmlStr);
            jsonObject = JSON.parseObject(resultString);
            retStatus = jsonObject.getString(RET_STATUS);
        }
        if (!STATUS_SUCCESS.equals(retStatus)) {
            return "";
        }
        
        return jsonObject.getString("data");
    }

    /**
     * 获得认签token(有效时长1小时)
     */
    private void getAccessToken() throws Exception {
        StringBuffer url = new StringBuffer();
        url.append(getTokenUrl).append("?client_id=" + vUserId).append("&grant_type=out_agent")
                .append("&client_secret=").append(vUserPassword);
        LOGGER.info("开始获取token:url:[[" + url);
        String tokenResult = doGet(url.toString(), null);
        LOGGER.info("结束获取token:tokenResult:[[" + tokenResult);
        JSONObject jsonObject = JSON.parseObject(tokenResult);
        String retStatus = jsonObject.getString(RET_STATUS);
        if (!STATUS_SUCCESS.equals(retStatus)) {
            return;
        }
        TOKEN_CACHE.put("token", jsonObject.getJSONObject("data").getString("access_token"));
    }

    /**
     * 执行http请求 
     * @param esgUrlCode  esg平台接口编码
     * @param paramsMap	      参数
     * @param httpMethod  调用方式 post get
     * @return
     */
    private String invoke(String esgUrlCode, Map paramsMap, String httpMethod) throws Exception {
        LOGGER.info("开始调用:esgUrlCode:[[" + esgUrlCode + "]],paramsMap:[[" +
                JSON.toJSONString(paramsMap) + "]],httpMethod:[[" + httpMethod);
        StringBuffer url = new StringBuffer();
        url.append(accessUrl).append(esgUrlCode).append("?esg_outer_access_token=").append(TOKEN_CACHE.get("token"))
                .append("&esg_outer_request_id=").append(System.currentTimeMillis());
        String resultString;
        if (HTTP_POST.equalsIgnoreCase(httpMethod)) {
            resultString = doPost(url.toString(), paramsMap);
        } else {
            resultString = doGet(url.toString(), paramsMap);
        }
        LOGGER.info("结果调用:resultString:[[" + resultString);
        return resultString;
    }

    /**
     * 执行http请求 Xml报文专用
     * @param esgUrlCode  esg平台接口编码
     * @param paramsMap	  xml报文
     * 默认 post请求
     * @return
     */
    private String invokeForXml(String esgUrlCode, String xmlStr) {
        LOGGER.info("开始调用:esgUrlCode:[[" + esgUrlCode + "]],xml:[[" + xmlStr + "]]");
        StringBuffer url = new StringBuffer();
        url.append(accessUrl).append(esgUrlCode).append("?esg_outer_access_token=").append(TOKEN_CACHE.get("token"))
                .append("&esg_outer_request_id=").append(System.currentTimeMillis());
        String resultString;
        resultString = doPostXml(url.toString(), xmlStr);
        LOGGER.info("结果调用:resultString:[[" + resultString);
        return resultString;
    }

    
    /**
     * 执行一个HTTP GET请求,返回请求响应的HTML
     *
     * @param url    请求的URL地址
     * @param params 请求的查询参数,可以为null
     * @return 返回请求响应的HTML
     */
    private String doGet(String url, Map<String, String> params) throws Exception{
        String queryString = getUrlFromParaMap(params);
        GetMethod method = new GetMethod(url);
        String response = "";
        try {
            if (StringUtils.isNotBlank(queryString)) {
                method.setQueryString(URIUtil.encodeQuery(queryString));
            }
            method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
            method.addRequestHeader("Accept", "application/json;charset=utf-8");
            HttpClient client = new HttpClient();
            client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
            client.executeMethod(method);
            if (method.getStatusCode() == HttpStatus.SC_OK) {
                response = method.getResponseBodyAsString();
            }
        } catch (URIException e) {
            LOGGER.error("执行HTTP get请求时,编码查询字符串[[" + queryString + "]]发生异常!", e);
        } catch (ConnectTimeoutException e) {
        	LOGGER.error("执行HTTP get请求[[" + url + "]]超时,无法连接主机!", e);
        	throw new ConnectTimeoutException("执行HTTP Post请求[[" + url + "]]超时,无法连接主机!",e);
        } catch (SocketTimeoutException e) {
            LOGGER.error("执行HTTP get请求[[" + url + "]]超时,等待主机返回结果超时!", e);
            throw new SocketTimeoutException("执行HTTP Post请求[[" + url + "]]超时,等待主机返回结果超时!");
        } catch (Exception e) {
            LOGGER.error("执行HTTP get请求[[" + url + "]]时,发生异常!", e);
            throw new Exception("执行HTTP Post请求[[" + url + "]]时,发生异常",e);
        } finally {
            method.releaseConnection();
        }
        return response;
    }
    /**
     * get请求解析map参数
     * @param params
     * @return
     */
    private String getUrlFromParaMap(Map<String, String> params) {
        if (CollectionUtils.isEmpty(params)) {
            return "";
        }
        StringBuffer queryString = new StringBuffer();
        queryString.append("?");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            queryString.append("&").append(entry.getKey()).append("=").append(entry.getValue());
        }
        return queryString.toString();
    }

    /**
     * 执行一个HTTP POST请求,返回请求响应的HTML
     *
     * @param url    请求的URL地址
     * @param params 请求的查询参数,可以为null
     * @return 返回请求响应的HTML
     */
    private String doPost(String url, Map<String, String> params) throws Exception {
        NameValuePair[] valuePairs = getPostPair(params);
        PostMethod method = new PostMethod(url);
        if (valuePairs != null) {
            method.setRequestBody(valuePairs);
        }
        method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");//关键代码
        method.addRequestHeader("Accept", "application/json;charset=utf-8");//关键代码
        String response = "";
        try {
            HttpClient client = new HttpClient();
            client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
            client.executeMethod(method);
            if (method.getStatusCode() == HttpStatus.SC_OK) {
                response = method.getResponseBodyAsString();
            }
        } catch (ConnectTimeoutException e) {
        	LOGGER.error("执行HTTP Post请求[[" + url + "]]超时,无法连接主机!", e);
        	throw new ConnectTimeoutException("执行HTTP Post请求[[" + url + "]]超时,无法连接主机!",e);
        } catch (SocketTimeoutException e) {
            LOGGER.error("执行HTTP Post请求[[" + url + "]]超时,等待主机返回结果超时!", e);
            throw new SocketTimeoutException("执行HTTP Post请求[[" + url + "]]超时,等待主机返回结果超时!");
        } catch (Exception e) {
            LOGGER.error("执行HTTP Post请求[[" + url + "]]时,发生异常!", e);
            throw new Exception("执行HTTP Post请求[[" + url + "]]时,发生异常",e);
        } finally {
            method.releaseConnection();
        }
        return response;
    }
    /**
     * post请求解析map参数
     * @param params
     * @return
     */
    private NameValuePair[] getPostPair(Map<String, String> params) {
        if (CollectionUtils.isEmpty(params)) {
            return new NameValuePair[0];
        }
        NameValuePair[] pairs = new NameValuePair[params.size()];
        NameValuePair tempPair;
        int size = 0;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            tempPair = new NameValuePair(entry.getKey(), entry.getValue());
            pairs[size] = tempPair;
            size++;
        }
        return pairs;
    }
    
    /**
     * 执行一个HTTP POST请求,返回请求响应的HTML
     *
     * @param url    请求的URL地址
     * @param params 请求的查询参数,可以为null
     * @return 返回请求响应的HTML
     */
    private String doPostXml(String url, String xmlStr) {
        PostMethod method = new PostMethod(url);
        if (StringUtils.isNotEmpty(xmlStr)) {
        	try {
				StringRequestEntity requestEntity = new StringRequestEntity(xmlStr,"application/text", "UTF-8");
				method.setRequestEntity(requestEntity);
			}
			catch (UnsupportedEncodingException e) {
				LOGGER.error("执行HTTP Post请求[[" + url + "]]时,构建参数报文发生异常!", e);
			}
        }
        String response = "";
        try {
            HttpClient client = new HttpClient();
            client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
            client.executeMethod(method);
            if (method.getStatusCode() == HttpStatus.SC_OK) {
                response = method.getResponseBodyAsString();
            }
        } catch (Exception e) {
            LOGGER.error("执行HTTP Post请求[[" + url + "]]时,执行发生异常!", e);
        } finally {
            method.releaseConnection();
        }
        return response;
    }

  

}

  

/**
	 * 支持https和http协议的httptClient实例
	 * @param url 网络地址
	 * @param json json参数
	 * @return
	 */
	public static String doPost(String url,String json) {
        try {
        	HttpClient httpclient = getInstance();  
        	HttpPost httppost = new HttpPost(url);  
        	httppost.setEntity(new StringEntity(json, "UTF-8"));
            System.out.println("executing request " + httppost.getURI());  
            HttpResponse response = httpclient.execute(httppost);  
        	int stateCode = response.getStatusLine().getStatusCode();
        	if (HttpStatus.SC_OK == stateCode) {
				HttpEntity responseEntity = response.getEntity();
				String body = EntityUtils.toString(responseEntity);
				return body;
			}else{
				return null;
			}
           
        } catch (ClientProtocolException e) {  
            e.printStackTrace();  
        } catch (UnsupportedEncodingException e1) {  
            e1.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} 
        return null;
    }  
	public static DefaultHttpClient getInstance() throws KeyManagementException, NoSuchAlgorithmException {

			DefaultHttpClient client = new DefaultHttpClient();
			SSLContext ctx = SSLContext.getInstance("SSL");
			// SSLContext ctx = SSLContext.getInstance("TLS");

			ctx.init(null, new TrustManager[] { trustManager }, null);

			SSLSocketFactory ssf = new SSLSocketFactory(ctx);

			// 忽略掉HostName的比较,否则访问部分地址可能会报异常
			ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

			ClientConnectionManager ccm = client.getConnectionManager();

			SchemeRegistry sr = ccm.getSchemeRegistry();

			sr.register(new Scheme("https", 443, ssf));

			client = new DefaultHttpClient(ccm, client.getParams());

			return client;

	}
	private static X509TrustManager trustManager = new X509TrustManager() {
		public void checkClientTrusted(
				java.security.cert.X509Certificate[] chain, String authType)
				throws java.security.cert.CertificateException {
		}

		public void checkServerTrusted(
				java.security.cert.X509Certificate[] chain, String authType)
				throws java.security.cert.CertificateException {
		}

		public java.security.cert.X509Certificate[] getAcceptedIssuers() {
			return null;
		}
	};