package cn.hmsoft.application.web;

import java.beans.PropertyEditorSupport;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

import cn.hmsoft.exception.AppException;
import cn.hmsoft.helper.JsonHelper;
import cn.hmsoft.helper.StringHelper;
import cn.hmsoft.jdbc.entity.QueryOrder;
import cn.hmsoft.jdbc.entity.QueryOrder.QueryOrderType;
import cn.hmsoft.log.LogHelper;

/*********************
 * 所有请求的基类
 * 
 * @author zxq
 * @create 2019-05-06 08:09:09
 * @version 2.0.0
 * @email: revisit@126.com
 * @Company: www.hmsoft.cn
 */
public class AjaxControl {
	/*****
	 * 权限判断，默认返回true
	 */
	public Object validRole() {

		return true;
	}

	// 不必在意的错误信息
	private static Map<String, String> IgnorErrorMap = new HashMap<String, String>();
	static {
		synchronized (AjaxControl.class) {
			IgnorErrorMap.put("org.springframework.http.converter.HttpMessageNotWritableException",
					"你的主机中的软件中止了一个已建立的连接。");
			IgnorErrorMap.put("org.apache.catalina.connector.ClientAbortException", "你的主机中的软件中止了一个已建立的连接。");
			IgnorErrorMap.put("java.lang.IllegalArgumentException",
					"further occurrences of HTTP header parsing errors will be logged at DEBUG level。");

		}
	}

	/*************************************************************************
	 * Web Control错误处理,以ajax字符串方式返回，拦截所有Exception 和RunTimeException
	 */
	@ExceptionHandler(value = { Exception.class })
	public void handle(HttpServletResponse response, Exception ex) {
		String error_name = ex.getClass().getName();
		Ajax ajax = null;
		if (ex instanceof AppException)
			ajax = new Ajax((AppException) ex);
		else
			ajax = new Ajax();
		
		// Ajax请求失败
		ajax.setSuccess(false);

		if (error_name.equals("org.springframework.web.bind.MissingServletRequestParameterException")
				|| error_name.equals("java.lang.IllegalStateException")) {
			// mvc提交时候参数错误
			ajax.setErrorMsg("提交参数缺失");
		} else if (error_name.equals("org.springframework.web.method.annotation.MethodArgumentTypeMismatchException")) {
			ajax.setErrorMsg("提交参数格式异常");
		} else if (error_name.equalsIgnoreCase("org.springframework.validation.BindException")) {
			ajax.setErrorMsg("提交参数格式异常");
		} else if (IgnorErrorMap.containsKey(error_name)) {
			//
			return;
		} else if (error_name.equals("cn.hmsoft.frame.exception.LoginAuthException")
				|| error_name.equals("cn.hmsoft.exception.web.LoginTimeoutException")) {
			// 错误类型
			ajax.setLogin(false);
		} else if (error_name.contains("cn.hmsoft.jdbc.exception")) {
			// JdbcException j = (JdbcException)ex;
			// LogHelper.error(j.getMessage());
			ajax.setErrorMsg("code DB");
			// jdbc错误，如果不是调试期间，显示统一错误
			LogHelper.error(ex);
		} else if (error_name.contains("cn.hmsoft.")) {

		} else if (error_name.equals("Exception")) {
			LogHelper.error(ex);
		} else {
			System.err.println(ex);
			int i = 0;
			do {
				System.err.println("\tat " + ex.getStackTrace()[i]);
			} while (i++ < 5);
			LogHelper.error(ex.getMessage());
		}
		if (StringHelper.isEmpty(ajax.getErrorMsg()))
			ajax.setErrorMsg("code ");
		writeJson(JsonHelper.fromObject(ajax));
	}

	/************************************************
	 * 直接输出text字符串
	 */
	protected void writeText(String message) {
		HttpServletResponse response = this.getResponse();
		try {
			response.setHeader("Content-type", "text/html;charset=utf-8");
			response.getOutputStream().write(message.getBytes("utf-8"));
			response.getOutputStream().flush();
			response.getOutputStream().close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/************************************************
	 * 直接输出JSON字符串
	 */
	protected void writeJson(String message) {
		HttpServletResponse response = this.getResponse();
		try {
			response.setHeader("Content-type", "text/json;charset=utf-8");
			response.getOutputStream().write(message.getBytes("utf-8"));
			response.getOutputStream().flush();
			response.getOutputStream().close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void writeAlert(String msg) {
		String value = "<script>alert('" + msg + "');window.close();window.history.back();</script>";
		writeText(value);
	}

	/******
	 * 对所有的Date类型进行绑定,所有Date类型的传输必须为yyyy-MM-dd HH:mm:ss
	 */
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) throws IllegalArgumentException {
				setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
			}

			@Override
			public String getAsText() throws IllegalArgumentException {
				return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format((LocalDateTime) getValue());
			}
		});
		binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) throws IllegalArgumentException {
				setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
			}

			@Override
			public String getAsText() throws IllegalArgumentException {
				return DateTimeFormatter.ofPattern("yyyy-MM-dd").format((LocalDate) getValue());
			}
		});
		binder.registerCustomEditor(LocalTime.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) throws IllegalArgumentException {
				setValue(LocalTime.parse(text, DateTimeFormatter.ofPattern("HH:mm:ss")));
			}

			@Override
			public String getAsText() throws IllegalArgumentException {
				return DateTimeFormatter.ofPattern("HH:mm:ss").format((LocalDate) getValue());
			}
		});

	}

	/*******************
	 * 获取Request(单例)
	 */
	protected HttpServletRequest getRequest() {
		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	}

	/*******************
	 * 获取Response(单例)
	 */
	protected HttpServletResponse getResponse() {
		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
	}

	/*************************
	 * 获取session(单例)
	 */
	protected HttpSession getSession() {
		return getRequest().getSession();
	}

	/*************************
	 * 简单进行页面跳转
	 */
	protected ModelAndView getModelAndView(String url) {
		ModelAndView mav = new ModelAndView();
		mav.setViewName(url);
		return mav;
	}

	/************************************************
	 * 生成排序参数
	 */
	protected QueryOrder getQueryOrder(String order, String type) {
		if (StringHelper.isEmpty(order))
			return null;
		if (StringHelper.isEmpty(type) || type.toLowerCase().toString().equals("asc"))
			return new QueryOrder(order, QueryOrderType.ASC);
		return new QueryOrder(order, QueryOrderType.DESC);
	}

	/************************************
	 * 下载一个文件，向客户端重命名文件，保留源文件
	 */
	protected void downloadFile(File file, String file_name) {
		this.downloadFile(file, file_name, false);
	}

	/************************************
	 * 下载一个文件，向客户端重命名文件，并根据选择是否 删除源文件
	 */
	protected void downloadFile(File file, String file_name, boolean delete) {
		HttpServletResponse response = this.getResponse();
		try {

			if (!file.exists()) {
				response.sendError(404, "File not found!");
			}

			BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
			byte[] buf = new byte[1024];
			int len = 0;

			file_name = URLEncoder.encode(file_name, "UTF-8");
			String fName = new String(file_name.getBytes(), "ISO-8859-1");

			response.reset();
			response.setContentType("application/x-msdownload");
			response.setHeader("Content-Disposition", "attachment; filename=" + fName);
			OutputStream outStream = response.getOutputStream();
			while ((len = br.read(buf)) > 0)
				outStream.write(buf, 0, len);
			br.close();
			outStream.close();
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
		}
		if (delete) {
			try {
				file.delete();
			} catch (Exception e) {
			}
		}
	}
	 
}
