package cn.hmsoft.helper.http;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import cn.hmsoft.frame.exception.BusinessException;
import cn.hmsoft.helper.BeanHelper;
import cn.hmsoft.helper.JsonHelper;
import cn.hmsoft.helper.StringHelper;
import cn.hmsoft.log.LogHelper;

/***************************
 * 
 * @note http辅助类
 * @author revisit@126.com
 * @Company: www.hmsoft.cn
 * @create 2017年8月22日 下午5:58:39
 * @version 4.0.0
 */
public class HttpHelper {
	/*****************************
	 * 获取请求的字符串
	 */
	public static String getRequestString(HttpServletRequest request) {
		StringBuilder buffer = new StringBuilder();
		BufferedReader reader = null;
		try {
			// utf-8防止乱码
			reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));
			String line = null;
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != reader) {
				try {
					reader.close();
				} catch (IOException e) {
					// e.printStackTrace();
				}
			}
		}
		return buffer.toString();
	}

	/****************************
	 * 获取请求的字符串并转换为对象
	 */
	public static <T> T getRequestEntity(HttpServletRequest request, Class<T> clazz) {
		String value = getRequestString(request);
		if (StringHelper.isEmpty(value))
			return null;
		return JsonHelper.toObject(value, clazz);
	}

	/****************************
	 * 获取请求的字符串并转换为对象,请求的字符串为xml
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getRequestEntityWithXml(HttpServletRequest request, Class<T> clazz) {
		String value = getRequestString(request);
		if (StringHelper.isEmpty(value))
			return null;
		try {
			JAXBContext jc = JAXBContext.newInstance(clazz);
			Unmarshaller u = jc.createUnmarshaller();
			return (T) u.unmarshal(new StringReader(value));
		} catch (Exception e) {
			return null;
		}
	}

	/********************************
	 * 回复一个xml的字符串
	 */
	public static void writeXmlString(HttpServletResponse response, Object entity) {
		try {
			JAXBContext jc = JAXBContext.newInstance(entity.getClass());
			Marshaller m = jc.createMarshaller();
			// 是否格式化生成的xml串
			// m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			// 是否省略xml头信息
			m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
			// 编码格式
			m.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
			// 理论上应该试用sun的类库处理特殊字符，但目前版本存在bug，临时办法处理，先放到字符串中，然后替换掉特殊字符
			StringWriter swriter = new StringWriter();
			m.marshal(entity, swriter);
			writeString(response, swriter.getBuffer().toString().replaceAll("&lt;", "<").replaceAll("&gt;", ">")
					.replaceAll("&amp;", "&"));
		} catch (Exception e) {
			throw new BusinessException("无法将对象转换为xml字符串");
		}
	}

	/*****************************
	 * 直接回复字符串
	 */
	public static void writeString(HttpServletResponse response, String msg) {
		try {
			response.setHeader("Content-type", "text/html;charset=utf-8");
			response.getOutputStream().write(msg.getBytes("utf-8"));
			response.getOutputStream().flush();
			response.getOutputStream().close();
		} catch (Exception e) {
		}
	}

	public static final String URL_PARAM_CONNECT_FLAG = "&";
	public static final String POST = "post";
	public static final String GET = "get";
	public static final int SIZE = 1024 * 1024;

	private static String formatString(String text) {
		return (text == null ? "" : text.trim());
	}

	public static boolean download(String source, File file) {
		OutputStream out = null;
		BufferedInputStream bin = null;
		HttpURLConnection connection = null;
		try {
			URL url = new URL(source);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.setRequestProperty("Charset", "UTF-8");
			connection.connect();
			bin = new BufferedInputStream(connection.getInputStream());
			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
			out = new FileOutputStream(file);
			byte[] buffer = new byte[1024];
			int count = 0;
			while ((count = bin.read(buffer)) > 0) {
				out.write(buffer, 0, count);
			}

		} catch (Exception e) {
			return false;
		} finally {
			try {
				bin.close();
			} catch (Exception e) {

			}
			try {
				out.close();
			} catch (Exception e) {

			}
			try {
				connection.disconnect();
			} catch (Exception e) {

			}
		}
		return true;

	}

	@SuppressWarnings("deprecation")
	public static <T> T httpRequest(HttpRequestEntity entity, Class<T> clazz) {
		List<String> rArray = null;
		try {
			if (entity.getMethod().equalsIgnoreCase(GET))
				rArray = URLGet(entity);
			else
				rArray = URLPost(entity);
		} catch (Exception e) {
			// e.printStackTrace();
		}
		if (rArray == null)
			return null;

		Iterator<String> iter = rArray.iterator();
		Map<String, Object> map = new HashMap<String, Object>();
		while (iter.hasNext()) {
			String temp = formatString((String) iter.next());
			if (temp.equals("")) {
				continue;
			}
			int i = temp.indexOf("=");
			int j = temp.length();
			if (i >= 0) {
				String tempKey = temp.substring(0, i);
				String tempValue = URLDecoder.decode(temp.substring(i + 1, j));
				map.put(tempKey, tempValue);
				// System.out.println("private String " + tempKey + " = \"" +
				// tempValue + "\";");
			}
		}

		return BeanHelper.fromMap(map, clazz);

	}

	public static <T> T jsonRequest(HttpRequestEntity entity, Class<T> clazz) {
		List<String> rArray = null;
		try {
			if (entity.getMethod().equals(GET))
				rArray = URLGet(entity);
			else
				rArray = URLPost(entity);
		} catch (Exception e) {

		}
		if (rArray == null || rArray.size() < 1)
			return null;
		return JsonHelper.toObject(rArray.get(0), clazz);
	}

	/**
	 * http请求
	 */
	public static List<String> URLGet(HttpRequestEntity entity) throws IOException {
		String strtTotalURL = "";
		List<String> resultArray = new ArrayList<String>();
		if (strtTotalURL.indexOf("?") == -1) {
			strtTotalURL = entity.getHttp_url() + "?" + getUrl(entity.getRequestMap());
		} else {
			strtTotalURL = entity.getHttp_url() + "&" + getUrl(entity.getRequestMap());
		}
		URL url = new URL(strtTotalURL);
		HttpURLConnection.setFollowRedirects(true);
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		con.setUseCaches(false);
		BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()), SIZE);
		while (true) {
			String line = in.readLine();
			if (line == null) {
				break;
			} else {
				resultArray.add(line);
			}
		}
		in.close();
		return (resultArray);
	}

	public static List<String> URLPost(HttpRequestEntity entity) throws Exception {

		String content = "";
		content = getUrl(entity.getRequestMap());
		// String totalURL = null;
		// if (entity.getHttp_url().indexOf("?") == -1) {
		// totalURL = entity.getHttp_url() + "?" + content;
		// } else {
		// totalURL = entity.getHttp_url() + "&" + content;
		// }
		URL url = new URL(entity.getHttp_url());
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		con.setDoInput(true);
		con.setDoOutput(true);
		con.setAllowUserInteraction(false);
		con.setUseCaches(false);
		con.setRequestMethod("POST");
		con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset="+entity.getCharset());
		con.setRequestProperty("Accept-Charset", entity.getCharset());
		con.setConnectTimeout(entity.getConnect_timeout());
		con.setReadTimeout(entity.getRead_timeout());
		DataOutputStream  bout = new DataOutputStream(con.getOutputStream());
		bout.write(content.getBytes(entity.getCharset()));
		bout.flush();
		bout.close();
		BufferedReader bin = new BufferedReader(new InputStreamReader(con.getInputStream(), entity.getCharset()), SIZE);
		List<String> result = new ArrayList<String>();
		while (true) {
			String line = bin.readLine();
			if (line == null) {
				break;
			} else {
				// System.out.println(line);
				result.add(line);
			}
		}
		return (result);
	}

	/**
	 * 生成URL
	 */
	public static String getUrl(Map<String, Object> map) {
		if (null == map || map.keySet().size() == 0) {
			return ("");
		}
		StringBuffer url = new StringBuffer();
		Set<String> keys = map.keySet();
		for (Iterator<String> i = keys.iterator(); i.hasNext();) {
			String key = String.valueOf(i.next());
			if (map.containsKey(key)) {
				Object val = map.get(key);
				String str = val != null ? val.toString() : "";
				try {
					// str = URLEncoder.encode(str, "GBK");
					// str = URLEncoder.encode(str, "GBK");
				} catch (Exception e) {
					e.printStackTrace();
				}
				url.append(key).append("=").append(str).append(URL_PARAM_CONNECT_FLAG);
			}
		}
		String strURL = "";
		strURL = url.toString();
		if (URL_PARAM_CONNECT_FLAG.equals("" + strURL.charAt(strURL.length() - 1))) {
			strURL = strURL.substring(0, strURL.length() - 1);
		}
		return (strURL);
	}
	
	public static String post(String url,  String params)
            throws Exception {
        String contentType = "application/x-www-form-urlencoded";
        return post(url, contentType, params);
    }

    public static String post(String url,  String contentType, String params)
            throws Exception {
        String encoding = "UTF-8";
        if (url.contains("nlp")) {
            encoding = "GBK";
        }
        return post(url, contentType, params, encoding);
    }

	public static String post(String vUrl, String contentType, String params, String encoding)
			throws Exception {
		URL url = new URL(vUrl);
		// 打开和URL之间的连接
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setRequestMethod("POST");
		// 设置通用的请求属性
		connection.setRequestProperty("Content-Type", contentType);
		connection.setRequestProperty("Connection", "Keep-Alive");
		connection.setUseCaches(false);
		connection.setDoOutput(true);
		connection.setDoInput(true);

		// 得到请求的输出流对象
		DataOutputStream out = new DataOutputStream(connection.getOutputStream());
		out.write(params.getBytes(encoding));
		out.flush();
		out.close();

		// 建立实际的连接
		connection.connect();
		// 获取所有响应头字段
		//Map<String, List<String>> headers = connection.getHeaderFields();
		// 遍历所有的响应头字段
//		for (String key : headers.keySet()) {
//			System.err.println(key + "--->" + headers.get(key));
//		}
		// 定义 BufferedReader输入流来读取URL的响应
		BufferedReader in = null;
		in = new BufferedReader(new InputStreamReader(connection.getInputStream(), encoding));
		String result = "";
		String getLine;
		while ((getLine = in.readLine()) != null) {
			result += getLine;
		}
		in.close();
		return result;
	}
	
	/**
	 * 显示所有参数
	 * @param request
	 */
	public void allParams(HttpServletRequest request) {
		Map<String, String> map = new HashMap<String, String>();
		Enumeration paramNames = request.getParameterNames();
		while (paramNames.hasMoreElements()) {
			String paramName = (String) paramNames.nextElement();
			String[] paramValues = request.getParameterValues(paramName);
			if (paramValues.length == 1) {
				if (paramValues[0].length() != 0) {
					map.put(paramName, paramValues[0]);
				}
			}
		} // 打印map所有值
		Set<Map.Entry<String, String>> set = map.entrySet();
		LogHelper.info("===========================");
		for (Map.Entry entry : set) {
			LogHelper.info(entry.getKey() + ":" + entry.getValue());
		}
		LogHelper.info("===========================");
	}

}
