/**
 * FileName:     MessageAletsByJavaClient.java
 * @Description: TODO(本类封装所有关于短信提醒工具类提供给第三方平台使用)
 * All rights Reserved, Designed By 上海神洲数港有限公司
 * Copyright:    Copyright(C) 2010-2011
 * Company       上海神洲数港有限公司 LTD.
 * @author:    chivalrous
 * @version    V1.0
 * Createdate:         2012-8-26 上午10:56:22
 * Modification  History:
 * Date         Author        Version        Discription
 *  ----------------------------------------------------------------------------------
 * 2012-8-26      chivalrous         1.0             1.0
 * Why & What is modified: <修改原因描述>
 */
package org.dromara.settlement.common;


import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.settlement.common.http.MyX509TrustManager;
import org.dromara.settlement.common.http.SynRequestThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMethod;
import org.dromara.common.core.constant.Constants;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class PostDataTools {

	private static Logger log = LoggerFactory.getLogger(PostDataTools.class);

	// 定义一个私有构造方法
    private PostDataTools() {
    }
    //定义一个静态私有变量(不初始化，不使用final关键字，使用volatile保证了多线程访问时instance变量的可见性，避免了instance初始化时其他变量属性还没赋值完时，被另外线程调用)
    private static volatile PostDataTools instance;

    //定义一个共有的静态方法，返回该类型实例
    public static PostDataTools getIstance() {
        // 对象实例化时与否判断（不使用同步代码块，instance不等于null时，直接返回对象，提高运行效率）
        if (instance == null) {
            //同步代码块（对象未初始化时，使用同步代码块，保证多线程访问时对象在第一次创建后，不再重复被创建）
            synchronized (PostDataTools.class) {
                //未初始化，则初始instance变量
                if (instance == null) {
                    instance = new PostDataTools();
                }
            }
        }
        return instance;
    }

	private int HTTP_CONNECTTIMEOUT = 10000;//连接超时时间（10秒）

	private int HTTP_READTIMEOUT = 20000;//读取内容超时时间（20秒）
	/**
	 * 采用HTTP BASIC AUTHENTICATION 进行加密帐号
	 */
	private String userName;

	/**
	 * 采用HTTP BASIC AUTHENTICATION 进行加密密码
	 */
	private String passwd;

	/**
	 * 异步请求线程
	 */
	private SynRequestThread synThread;

	public SynRequestThread getSynThread() {
		if (synThread == null || !synThread.isRunning()) {
            //同步代码块（对象未初始化时，使用同步代码块，保证多线程访问时对象在第一次创建后，不再重复被创建）
            synchronized (this) {
                //未初始化，则初始instance变量
                if (synThread == null || !synThread.isRunning()) {
                	if(synThread != null)
                		synThread.close();
                	synThread = new SynRequestThread();
                	synThread.start();
                }
            }
        }
        return synThread;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPasswd() {
		return passwd;
	}

	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}

	public void setBasicAuth(String userName, String passwd) {
		this.userName = userName;
		this.passwd = passwd;
	}

	/**
	 *
	 * @Title: sendMessageInfo
	 * @Description: TODO(使用该工具类下需要手动将{@code SendInfoMessage}所用需要配置的字段
	 *               一定必须SET相应的参数)
	 * @param: @param sendInfoMessage
	 * @param: @return
	 * @return: boolean
	 * @throws
	 */
	public String sendMessageInfo(String hostURl,Object o) {
		return sendMessageInfo(hostURl,o,new String[]{"Content-Type:application/json;charset=utf-8"},true,true);
	}

	public String sendMessageInfo(String hostURl,Object o,boolean auth) {
		return sendMessageInfo(hostURl,o,new String[]{"Content-Type:application/json;charset=utf-8"},auth,true);
	}

	/**
	 * 发送ajax请求，不等待结果
	 * @author 张涛
	 * @date 2016年12月3日
	 * @param o 参数对象
	 */
	public void sendMessageInfoOfAjax(String hostURl,Object o) {
		sendMessageInfoOfAjax(hostURl,o,new String[]{"Content-Type:application/json;charset=utf-8"},true,true);
	}

	/**
	 * 发送ajax请求，不等待结果
	 * @author 张涛
	 * @date 2016年12月3日
	 * @param requestHeaders 请求头部内容
	 * @param auth 是否有Basic验证
	 * @param isJsonParam 是否json参数
	 * @param o 参数对象
	 */
	public void sendMessageInfoOfAjax(String hostURl,Object o,String[] requestHeaders,boolean auth,boolean isJsonParam) {
		//sendMessageInfo(o,new String[]{"Content-Type:application/json;charset=utf-8"},true,true,false);
		try {
			String bodyContent = "";
			if(isJsonParam && o != null)
				bodyContent = JSONObject.toJSONString(o);// 将内容转换为JSON字符串进行转码
			else if(o != null)
				bodyContent = o+"";
			log.info("request url："+hostURl + ",request body:" + bodyContent);
			HttpPost postMethod = new HttpPost(hostURl);
			postMethod.setConfig(RequestConfig.custom().setSocketTimeout(HTTP_READTIMEOUT).setConnectTimeout(HTTP_CONNECTTIMEOUT).build());
			if (requestHeaders != null && requestHeaders.length > 0) {
				for (String string : requestHeaders) {
					postMethod.addHeader(string.split(":")[0],
							string.split(":")[1]);
				}
			}
			if(auth){
				postMethod.addHeader("Authorization", "Basic " + getAuthToken());
			}
			if(StringUtils.isNotBlank(bodyContent)){
				if(isJsonParam)
					postMethod.setEntity(new StringEntity(bodyContent,ContentType.APPLICATION_JSON));
				else
					postMethod.setEntity(new StringEntity(bodyContent,ContentType.create(ContentType.APPLICATION_FORM_URLENCODED.getMimeType(), Constants.UTF8)));
			}
			getSynThread().sendRequest(postMethod);
		} catch (Exception e) {
			// TODO 自动生成的 catch 块
			log.error(e.getMessage(), e);
		}
	}

	/**
	 * 获取接口Basic认证token
	 * @author 张涛
	 * @date 2016年10月17日
	 * @param userName
	 * @param passwd
	 * @return
	 */
	public String getAuthToken(){
		String authString = this.userName + ":" + this.passwd;
		byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
		return new String(authEncBytes);
	}

	public String sendMessageInfo(String hostURl,Object o,String[] requestHeaders,boolean auth){
		return sendMessageInfo(hostURl,o, requestHeaders, auth, true);
	}

	public String sendMessageInfo(String hostURl,Object o,String[] requestHeaders,boolean auth,boolean isJsonParam) {
		return sendMessageInfo(hostURl,o, requestHeaders, auth, isJsonParam,true,null,null);
	}

	public String sendHttpsMessageInfo(String hostURl,Object o,String[] requestHeaders,boolean auth,boolean isJsonParam) {
		return sendHttpsMessageInfo(hostURl,o, requestHeaders, auth, isJsonParam,true);
	}

	/**
	 * 以表单方式发送请求
	 * @author 张涛
	 * @date 2017年5月12日
	 * @param o
	 * @return
	 */
	public String sendFormMessageInfo(String hostURl,Object o) {
		return sendMessageInfo(hostURl,
				o,
				new String[] { "Content-Type:application/x-www-form-urlencoded;charset=utf-8" },
				false, false);
	}

	/**
	 * 以表单方式发送请求
	 * @author 张涛
	 * @date 2017年5月31日
	 * @param o
	 * @param readTimeout 读取请求结果最长时间（毫秒）
	 * @return
	 */
	public String sendFormMessageInfo(String hostURl,Object o,Integer readTimeout) {
		return sendMessageInfo(hostURl,
				o,
				new String[] { "Content-Type:application/x-www-form-urlencoded;charset=utf-8" },
				false, false,true,readTimeout,null);
	}

	/**
	 * 以表单方式发送请求
	 * @author 张涛
	 * @date 2017年5月31日
	 * @param o
	 * @param readTimeout 读取请求结果最长时间（毫秒）
	 * @param connectTimeout 请求连接最长时间（毫秒）
	 * @return
	 */
	public String sendFormMessageInfo(String hostURl,Object o,Integer readTimeout,Integer connectTimeout) {
		return sendMessageInfo(hostURl,
				o,
				new String[] { "Content-Type:application/x-www-form-urlencoded;charset=utf-8" },
				false, false,true,readTimeout,connectTimeout);
	}

	/**
	 * 发送http请求
	 * @author 张涛
	 * @date 2016年12月3日
	 * @param o 参数对象
	 * @param requestHeaders 请求头部内容
	 * @param auth 是否有Basic验证
	 * @param isJsonParam 是否json参数
	 * @param returnResult 是否等待返回结果
	 * @param readTimeout 读取请求结果最长时间（毫秒）
	 * @param connectTimeout 请求连接最长时间（毫秒）
	 * @return
	 */
	public String sendMessageInfo(String hostURl,Object o,String[] requestHeaders,boolean auth,boolean isJsonParam,boolean returnResult,Integer readTimeout,Integer connectTimeout) {

		String output = "";
		String s;
		HttpURLConnection conn = null;
		OutputStream os = null;
		BufferedReader br = null;
		try {
			// 接口URL
			URL url = new URL(hostURl);
			conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod(RequestMethod.POST.toString());
			if(connectTimeout == null)
				conn.setConnectTimeout(HTTP_CONNECTTIMEOUT);//设置连接主机超时（单位：毫秒）
			else
				conn.setConnectTimeout(connectTimeout);
			if(readTimeout == null)
				conn.setReadTimeout(HTTP_READTIMEOUT);//设置从主机读取数据超时（单位：毫秒）
			else
				conn.setReadTimeout(readTimeout);
			conn.setDoOutput(true);
			if(!returnResult)
				conn.setDoInput(false);
			if (requestHeaders != null && requestHeaders.length > 0) {
				for (String string : requestHeaders) {
					conn.setRequestProperty(string.split(":")[0],
							string.split(":")[1]);
				}
			}
			if(auth){
				conn.setRequestProperty("Authorization", "Basic " + getAuthToken());
			}
			String bodyContent = "";
			if(isJsonParam)
				bodyContent = JSONObject.toJSONString(o);// 将内容转换为JSON字符串进行转码
			else if(o != null)
				bodyContent = o.toString();
			log.info("request body:" + bodyContent);
			os = conn.getOutputStream();
			os.write(bodyContent.getBytes("utf-8"));
			os.flush();
			if(returnResult){
				log.info("request url："+hostURl+ ",result code：" + conn.getResponseCode());
				br = new BufferedReader(new InputStreamReader(
						(conn.getInputStream()), "utf-8"));

				while ((s = br.readLine()) != null) {
					output += s;
				}
			}else
				log.info("request url："+hostURl);
		} catch (Exception e) {
			log.error("request url："+hostURl, e);
		}finally{
			try {
				if(br != null)
					br.close();
				if(os != null)
					os.close();
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				log.error(e.getMessage(), e);
			}
			if(conn != null)
				conn.disconnect();
		}
		return output;
	}

	/**
	 * 发送https请求
	 * @author 张涛
	 * @date 2016年12月3日
	 * @param o 参数对象
	 * @param requestHeaders 请求头部内容
	 * @param auth 是否有Basic验证
	 * @param isJsonParam 是否json参数
	 * @param returnResult 是否等待返回结果
	 * @return
	 */
	public String sendHttpsMessageInfo(String hostURl,Object o,String[] requestHeaders,boolean auth,boolean isJsonParam,boolean returnResult) {
		String output = "";
		String s;
		HttpsURLConnection conn = null;
		OutputStream os = null;
		BufferedReader br = null;
		try {
			//创建SSLContext
		    SSLContext sslContext=SSLContext.getInstance("SSL");
		    TrustManager[] tm={new MyX509TrustManager()};
		    //初始化
		    sslContext.init(null, tm, new java.security.SecureRandom());;
		    //获取SSLSocketFactory对象
		    SSLSocketFactory ssf=sslContext.getSocketFactory();
			// 接口URL
			URL url = new URL(hostURl);
			conn = (HttpsURLConnection) url.openConnection();
			conn.setRequestMethod(RequestMethod.POST.toString());
			//设置当前实例使用的SSLSoctetFactory
		    conn.setSSLSocketFactory(ssf);
			conn.setConnectTimeout(30000);//设置连接主机超时（单位：毫秒）
			conn.setReadTimeout(30000);//设置从主机读取数据超时（单位：毫秒）
			conn.setDoOutput(true);
			if(!returnResult)
				conn.setDoInput(false);
			if (requestHeaders != null && requestHeaders.length > 0) {
				for (String string : requestHeaders) {
					conn.setRequestProperty(string.split(":")[0],
							string.split(":")[1]);
				}
			}
			if(auth){
				conn.setRequestProperty("Authorization", "Basic " + getAuthToken());
			}
			String bodyContent = "";
			if(isJsonParam)
				bodyContent = JSONObject.toJSONString(o);// 将内容转换为JSON字符串进行转码
			else if(o != null)
				bodyContent = o.toString();
			log.info("request body:" + bodyContent);
			os = conn.getOutputStream();
			os.write(bodyContent.getBytes("utf-8"));
			os.flush();
			if(returnResult){
				log.info("request url："+hostURl+ ",result code：" + conn.getResponseCode());
				br = new BufferedReader(new InputStreamReader(
						(conn.getInputStream()), "utf-8"));

				while ((s = br.readLine()) != null) {
					output += s;
				}
			}else
				log.info("request url："+hostURl);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
			try {
				if(br != null)
					br.close();
				if(os != null)
					os.close();
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				log.error(e.getMessage(), e);
			}
			if(conn != null)
				conn.disconnect();
		}
		return output;
	}

	/**
	 *
	 * @Title: sendMessageInfo
	 * @Description: TODO(使用该工具类下需要手动将{@code SendInfoMessage}所用需要配置的字段
	 *               一定必须SET相应的参数)
	 * @param: @param sendInfoMessage
	 * @param: @return
	 * @return: boolean
	 * @throws
	 */
	public String sendMessageInfoWithTimeOut(String hostURl,Object o) {

		String output = "error";
		String s;
		HttpURLConnection conn = null;
		OutputStream os = null;
		BufferedReader br = null;
		try {
			URL url = new URL(hostURl);
			conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(HTTP_CONNECTTIMEOUT);//设置连接主机超时（单位：毫秒）
			conn.setReadTimeout(HTTP_READTIMEOUT);//设置从主机读取数据超时（单位：毫秒）
			conn.setDoOutput(true);
			conn.setRequestMethod(RequestMethod.POST.toString());
			conn.setRequestProperty("Content-Type",
					"application/json;charset=utf-8");
			conn.setRequestProperty("Authorization", "Basic " + getAuthToken());
			// 将短信内容转换为JSON字符串进行转码
			String jsonString = JSONObject.toJSONString(
					o);
			os = conn.getOutputStream();
			os.write(jsonString.getBytes("utf-8"));
			os.flush();
			log.info("request url："+hostURl+ ",result code：" + conn.getResponseCode());

			br = new BufferedReader(new InputStreamReader(
					(conn.getInputStream()), "utf-8"));

			while ((s = br.readLine()) != null) {
				output = s;
			}

		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
			try {
				if(br != null)
					br.close();
				if(os != null)
					os.close();
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				log.error(e.getMessage(), e);
			}
			if(conn != null)
				conn.disconnect();
		}
		System.out.println(output);
		return output;
	}

	/**
	 * 发送
	 * @param hostURl
	 * @param o
	 * @return
	 */
	public String sendPRCUrlWithParam(String hostURl,Object o) {

		String output = "error";
		String s;
		HttpURLConnection conn = null;
		OutputStream os = null;
		BufferedReader br = null;
		try {
			URL url = new URL(hostURl);
			conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(HTTP_CONNECTTIMEOUT);//设置连接主机超时（单位：毫秒）
			conn.setReadTimeout(HTTP_READTIMEOUT);//设置从主机读取数据超时（单位：毫秒）
			conn.setDoOutput(true);
			conn.setRequestMethod(RequestMethod.POST.toString());
			conn.setRequestProperty("Content-Type",
					"application/json;charset=utf-8");
			conn.setRequestProperty("Authorization", "Basic " + getAuthToken());
			// 将短信内容转换为JSON字符串进行转码
			String jsonString = JSONObject.toJSONString(
					o);
			os = conn.getOutputStream();
			os.write(jsonString.getBytes("utf-8"));
			os.flush();
			log.info("request url："+hostURl+ ",result code：" + conn.getResponseCode());

			if(200 == conn.getResponseCode()){
				return "1";
			}

		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
			try {
				if(br != null)
					br.close();
				if(os != null)
					os.close();
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				log.error(e.getMessage(), e);
			}
			if(conn != null)
				conn.disconnect();
		}
		return output;
	}

	/**
	 * 无参数传递调用
	 *
	 * @return
	 */
	public String sendMessageNullParam(String hostURl) {
		return sendMessageNullParam(hostURl,RequestMethod.POST,
				new String[] { "Content-Type:application/json" },null);
	}

	/**
	 * 无参数指定请求
	 * @author 张涛
	 * @date 2017年5月27日
	 * @param method
	 * @return
	 */
	public String sendFormMessageNullParam(String hostURl,RequestMethod method,Integer readTimeout) {
		return sendMessageNullParam(hostURl,method,
				new String[] { "Content-Type:application/x-www-form-urlencoded;charset=utf-8" },readTimeout);
	}

	/**
	 * 无参数传递调用
	 *
	 * @author 张涛
	 * @date 2015年12月21日
	 * @param method
	 *            get post
	 * @return
	 */
	public String sendMessageNullParam(String hostURl,RequestMethod method,
			String[] requestHeaders,Integer readTimeout){
		return sendMessageNullParam(hostURl,method, requestHeaders, true,readTimeout);
	}

	public String sendMessageNullParam(String hostURl,RequestMethod method,
			String[] requestHeaders,boolean auth){
		return sendMessageNullParam(hostURl,method, requestHeaders, auth,null);
	}

	/**
	 * 无参数传递调用
	 *
	 * @author 张涛
	 * @date 2015年12月21日
	 * @param method
	 *            get post
	 * @return
	 */
	public String sendMessageNullParam(String hostURl,RequestMethod method,
			String[] requestHeaders,boolean auth,Integer readTimeout) {
		String output = "";
		String s;
		HttpURLConnection conn = null;
		BufferedReader br = null;
		try {
			// 接口URL
			URL url = new URL(hostURl);
			conn = (HttpURLConnection) url.openConnection();
			conn.setDoOutput(true);
			conn.setRequestMethod(method.toString());
			conn.setConnectTimeout(HTTP_CONNECTTIMEOUT);//设置连接主机超时（单位：毫秒）
			if(readTimeout != null)
				conn.setReadTimeout(readTimeout);//设置从主机读取数据超时（单位：毫秒）
			else
				conn.setReadTimeout(HTTP_READTIMEOUT);//设置从主机读取数据超时（单位：毫秒）
			if (requestHeaders != null && requestHeaders.length > 0) {
				for (String string : requestHeaders) {
					conn.setRequestProperty(string.split(":")[0],
							string.split(":")[1]);
				}
			}
			if(auth){
				conn.setRequestProperty("Authorization", "Basic " + getAuthToken());
			}

			br = new BufferedReader(new InputStreamReader(
					(conn.getInputStream()), "utf-8"));

			while ((s = br.readLine()) != null) {
				output += s;
			}

			log.info("request url："+hostURl+ ",result code：" + conn.getResponseCode()+ ",response：" + output);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}finally{
			try {
				if(br != null)
					br.close();
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				log.error(e.getMessage(), e);
			}
			if(conn != null)
				conn.disconnect();
		}
		return output;
	}
}
