package cn.util.http;

import cn.constant.CharsetKit;
import cn.util.core.IsKit;
import cn.util.core.LogKit;
import cn.util.core.TypeKit;

import javax.net.ssl.*;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 通用http发送方法
 */
public class HttpKit
{
	/** 是否需要synchronized？*/
	public static synchronized String sendPostByList(
			String url, 
			List<NameValuePair> nameValuePairList) throws Exception 
	{
		CloseableHttpResponse response = null;
		try (CloseableHttpClient client = HttpClients.createDefault()) 
		{
			//获取请求地址
			HttpPost post = new HttpPost(url);
			//设置参数
			StringEntity entity = new UrlEncodedFormEntity(nameValuePairList, "UTF-8");
			post.setEntity(entity);
			post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
			//post.setHeader(new BasicHeader("Accept", "text/plain;charset=utf-8"));
			post.setHeader(new BasicHeader("Accept", "application/json;charset=utf-8"));
			
			//通过请求获取相应对象
			response = client.execute(post);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				//返回json格式
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} catch (Exception e) {
			LogKit.error("send post error", e);
		} finally {
			if(IsKit.isNotNull(response)) {
				response.close();
			}
		}
		return null;
	}
	/**
	 * post请求传输map数据
	 * 
	 * @param url
	 * @param map
	 * @param encoding
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * String url = "http://localhost:8080/httpService/sendPostDataByMap";
			Map<String, String> map = new HashMap<String, String>();
			map.put("name", "wyj");
			map.put("city", "南京");
			String body = sendPostDataByMap(url, map, "utf-8");
	 */
	public static String sendPostDataByMap(String url,Map<String, Object> map) {
		return sendPostDataByMap(url, map, "utf-8");
	}
	public static String sendPostDataByMap(
			String url, 
			Map<String, Object> map, 
			String encoding)
	{
		CloseableHttpResponse response = null;
		// 创建httpclient对象
		try (CloseableHttpClient httpClient = HttpClients.createDefault()) 
		{
			// 创建post方式请求对象
			HttpPost httpPost = new HttpPost(url);
			// 装填参数
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
			if (map != null) {
				for (Entry<String,Object> entry : map.entrySet()) {
					nameValuePairs.add(
							new BasicNameValuePair(entry.getKey(), 
							TypeKit.objToStr(entry.getValue())));
				}
			}
			//设置参数到请求对象中
			httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, encoding));

			// 设置header信息
			// 指定报文头【Content-type】、【User-Agent】
			httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
			httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
			// 执行请求操作，并拿到结果（同步阻塞）
			response = httpClient.execute(httpPost);
			// 获取结果实体
			// 判断网络连接状态码是否正常(0--200都数正常)
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				return EntityUtils.toString(response.getEntity(), "utf-8");
			}
		} catch (Exception e) {
			LogKit.error("send post error", e);
		} finally {
			if(IsKit.isNotNull(response)) {
				try {
					response.close();
				} catch (IOException e) {}
			}
		}
		return null;
	}

	/**
	 * post请求传输json数据
	 * 
	 * @param url
	 * @param json
	 * @param encoding
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * String url = "http://localhost:8080/httpService/sendPostDataByJson";
			Map<String, String> map = new HashMap<String, String>();
			map.put("name", "wyj");
			map.put("city", "南京");
			String body = sendPostDataByJson(url, JSON.toJSONString(map), "utf-8");
	 */
	public static String sendPostDataByJson(
			String url, String json, 
			String encoding) throws Exception 
	{
		CloseableHttpResponse response = null;
		// 创建httpclient对象
		try (CloseableHttpClient httpClient = HttpClients.createDefault()) 
		{
			// 创建post方式请求对象
			HttpPost httpPost = new HttpPost(url);
			// 设置参数到请求对象中
			StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
			stringEntity.setContentEncoding("utf-8");
			httpPost.setEntity(stringEntity);
			// 执行请求操作，并拿到结果（同步阻塞）
			response = httpClient.execute(httpPost);
			// 获取结果实体
			// 判断网络连接状态码是否正常(0--200都数正常)
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				return EntityUtils.toString(response.getEntity(), "utf-8");
			}
		} catch (Exception e) {
			LogKit.error("send post error", e);
		} finally {
			if(IsKit.isNotNull(response)) {
				response.close();
			}
		}
		return null;
	}

	/**
	 * get请求传输数据
	 * 
	 * @param url
	 * @param encoding
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * 	String url = "http://localhost:8080/httpService/sendGetData?name=wyj&city=南京";
			String body = sendGetData(url, "utf-8");
			System.out.println("响应结果：" + body);
	 */
	public String sendGetData(String url, String encoding) throws Exception 
	{
		CloseableHttpResponse response = null;
		// 创建httpclient对象
		try (CloseableHttpClient httpClient = HttpClients.createDefault()) 
		{
			// 创建get方式请求对象
			HttpGet httpGet = new HttpGet(url);
			httpGet.addHeader("Content-type", "application/json");
			// 通过请求对象获取响应对象
			response = httpClient.execute(httpGet);

			// 获取结果实体
			// 判断网络连接状态码是否正常(0--200都数正常)
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				return EntityUtils.toString(response.getEntity(), "utf-8");
			}
		} catch (Exception e) {
			LogKit.error("send post error", e);
		} finally {
			if(IsKit.isNotNull(response)) {
				response.close();
			}
		}
		return null;
	}



	/**
	 * 向指定 URL 发送GET方法的请求
	 *
	 * @param url 发送请求的 URL
	 * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
	 * @return 所代表远程资源的响应结果
	 * @throws IOException 
	 */
	public static String sendGet(String url, String param) throws IOException
	{
		return sendGet(url, param, CharsetKit.UTF8);
	}

	/**
	 * 向指定 URL 发送GET方法的请求
	 *
	 * @param url 发送请求的 URL
	 * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
	 * @param contentType 编码类型
	 * @return 所代表远程资源的响应结果
	 * @throws IOException 
	 */
	public static String sendGet(String url, String param, String contentType) throws IOException
	{
		StringBuilder result = new StringBuilder();
		BufferedReader in = null;
		try
		{
			String urlNameString = url + "?" + param;
			LogKit.info("sendGet - {}", urlNameString);
			URL realUrl = new URL(urlNameString);
			URLConnection connection = realUrl.openConnection();
			connection.setRequestProperty("accept", "*/*");
			connection.setRequestProperty("connection", "Keep-Alive");
			connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			connection.connect();
			in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
			String line;
			while ((line = in.readLine()) != null){
				result.append(line);
			}
			LogKit.info("recv - {}", result);
		}
		catch (Exception e){
			LogKit.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
		}
		finally{
			if(IsKit.isNotNull(in)) {
				in.close();
			}
		}
		return result.toString();
	}

	/**
	 * 向指定 URL 发送POST方法的请求
	 *
	 * @param url 发送请求的 URL
	 * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
	 * @return 所代表远程资源的响应结果
	 * @throws IOException 
	 */
	public static String sendPost(String url, String param)
	{
		PrintWriter out = null;
		BufferedReader in = null;
		StringBuilder result = new StringBuilder();
		try
		{
			String urlNameString = url;
			LogKit.info("sendPost - {}", urlNameString);
			URL realUrl = new URL(urlNameString);
			URLConnection conn = realUrl.openConnection();
			conn.setRequestProperty("accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			conn.setRequestProperty("Accept-Charset", "utf-8");
			conn.setRequestProperty("contentType", "utf-8");
			conn.setDoOutput(true);
			conn.setDoInput(true);
			out = new PrintWriter(conn.getOutputStream());
			out.print(param);
			out.flush();
			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
			String line;
			while ((line = in.readLine()) != null){
				result.append(line);
			}
			LogKit.info("recv - {}", result);
		}
		catch (Exception e){
			LogKit.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
		}
		finally {
			if(IsKit.isNotNull(out)) {
				out.close();
			}
			if(IsKit.isNotNull(in)) {
				try {
					in.close();
				} catch (IOException e) {}
			}
		}
		return result.toString();
	}

	public static String sendSSLPost(String url, String param) throws IOException
	{
		StringBuilder result = new StringBuilder();
		String urlNameString = url + "?" + param;
		HttpsURLConnection conn = null;
		BufferedReader br = null;
		try
		{
			LogKit.info("sendSSLPost - {}", urlNameString);
			SSLContext sc = SSLContext.getInstance("SSL");
			sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
			URL console = new URL(urlNameString);
			conn = (HttpsURLConnection) console.openConnection();
			conn.setRequestProperty("accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			conn.setRequestProperty("Accept-Charset", "utf-8");
			conn.setRequestProperty("contentType", "utf-8");
			conn.setDoOutput(true);
			conn.setDoInput(true);

			conn.setSSLSocketFactory(sc.getSocketFactory());
			conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
			conn.connect();
			InputStream is = conn.getInputStream();
			br = new BufferedReader(new InputStreamReader(is));
			String ret = "";
			while ((ret = br.readLine()) != null){
				if (ret != null && !ret.trim().equals("")){
					result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
				}
			}
			LogKit.info("recv - {}", result);
		}
		catch (Exception e){
			LogKit.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
		}finally {
			if(IsKit.isNotNull(conn)) {
				conn.disconnect();
			}
			if(IsKit.isNotNull(br)) {
				br.close();
			}
		}
		return result.toString();
	}

	private static class TrustAnyTrustManager implements X509TrustManager
	{
		@Override
		public void checkClientTrusted(X509Certificate[] chain, String authType)
		{
		}

		@Override
		public void checkServerTrusted(X509Certificate[] chain, String authType)
		{
		}

		@Override
		public X509Certificate[] getAcceptedIssuers()
		{
			return new X509Certificate[] {};
		}
	}

	private static class TrustAnyHostnameVerifier implements HostnameVerifier
	{
		@Override
		public boolean verify(String hostname, SSLSession session)
		{
			return true;
		}
	}
}
