package com;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

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

import org.apache.commons.lang.ObjectUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chinaitop.depot.intelligent.utils.RedisUtil;
import com.chinaitop.depot.systemLog.mapper.SystemLogMapper;
import com.chinaitop.depot.systemLog.model.SystemLog;
import com.chinaitop.depot.systemLog.model.SystemLogExample;

/**
 * 功能日志拦截器
 * 
 * @author fanxiongwei
 *
 */
public class LogercostInterceptor implements HandlerInterceptor {

	private static String system_index = "库级系统";

	@Autowired
	private RedisUtil redisUtil;
	
	@Autowired
	private SystemLogMapper systemLogMapper;

	/**
     * preHandle是在请求执行前执行的
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    	//获取URL
        String url = request.getRequestURI();
    	//注销日志
    	if ("/userInfo/exitLogin".equals(url)) {
    		loginLogger(request, response, url);
    	}

        return true;//返回true,postHandler和afterCompletion方法才能执行,否则false为拒绝执行，起到拦截器控制作用
    }

    /**
     * postHandler是在请求结束之后,视图渲染之前执行的,但只有preHandle方法返回true的时候才会执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    	//获取URL
        String url = request.getRequestURI();
        //获取用户信息和单位信息
        String userJson = ObjectUtils.toString(request.getSession().getAttribute("userInfo"),"");
        String orgInfoJson = ObjectUtils.toString(request.getSession().getAttribute("orgInfo"),"");
        //登录日志
    	if (("/userInfo/login".equals(url) || "/userInfo/exitLogin".equals(url))
    			&& !"".equals(userJson) && !"".equals(orgInfoJson)
    			&& null != userJson && null != orgInfoJson) {
    		loginLogger(request, response, url);
    	}
    	//功能操作和访问日志
    	if (!"/userInfo/login".equals(url) && !"/userInfo/exitLogin".equals(url)
    			&& !"".equals(userJson) && !"".equals(orgInfoJson)
    			&& null != userJson && null != orgInfoJson) {
    		operationLogger(request, response, url, handler);
    	}
    }

    /**
     * 封装登录信息
     * 
     * @param userJson
     * @param orgInfoJson
     * @return
     */
    private Map<String, String> getUserOrgInfo(String userJson, String orgInfoJson) {
    	Map<String, String> user_map = new HashMap<String, String>();
    	JSONObject userinfo = JSONObject.parseObject(userJson);
    	JSONObject orginfo = JSONObject.parseObject(orgInfoJson);
    	user_map.put("userId", userinfo == null ? "" : userinfo.get("userId")+"");
    	user_map.put("username", userinfo == null ? "" : userinfo.get("username")+"");
    	user_map.put("realName", userinfo == null ? "" : userinfo.get("realName")+"");
    	user_map.put("orgId", userinfo == null ? "" : userinfo.get("orgId")+"");
    	user_map.put("roleName", userinfo == null ? "" : userinfo.get("roleNames")+"");
    	user_map.put("areaCode", orginfo == null ? "":ObjectUtils.toString(orginfo.get("areaCode")+"",""));
    	user_map.put("areaName", orginfo == null ? "":ObjectUtils.toString(orginfo.get("areaName")+"",""));
    	user_map.put("orgName", orginfo == null ? "":ObjectUtils.toString(orginfo.get("orgName")+"",""));
		return user_map;
	}

    /**
     * 登录日志（包含登录与注销）
     * @param request
     * @param response
     */
    private void loginLogger(HttpServletRequest request, HttpServletResponse response, String url) {
    	//获取用户信息和单位信息
        String userJson = ObjectUtils.toString(request.getSession().getAttribute("userInfo"),"");
        String orgInfoJson = ObjectUtils.toString(request.getSession().getAttribute("orgInfo"),"");
    	//登录
        if ("/userInfo/login".equals(url)) {
	    	SystemLog log = new SystemLog();
	    	Map<String, String> user_map = getUserOrgInfo(userJson, orgInfoJson);
			log.setSystemIdentify(system_index);
			log.setUserZh(ObjectUtils.toString(user_map.get("username"),""));//账号
			log.setUserName(ObjectUtils.toString(user_map.get("realName"),""));//名称
			String device_ip = getClientIpAddress(request);
			log.setDeviceIp(device_ip);
			log.setDlTime(new Date());
			log.setUserRole(ObjectUtils.toString(user_map.get("roleName"),""));//角色
			log.setOrgId(Integer.parseInt(user_map.get("orgId")));//单位
			String enumid = ObjectUtils.toString(user_map.get("areaCode"), "0");
			if (!"0".equals(enumid)) {
				String httpurl = "http://localhost:9022/Enum/findByEnum?id="+Integer.parseInt(enumid);
				String strResult = doGet(httpurl);
				if (!"".equals(strResult)) {
					JSONObject enum_obj = JSONObject.parseObject(strResult);
					log.setUserAddress(ObjectUtils.toString(enum_obj.get("gbcode"), ""));//行政区划
				}
			}
			log.setId(UUID.randomUUID().toString().replace("-", ""));
			log.setUserId(Integer.parseInt(user_map.get("userId")));
			log.setOperationTime(new Date());//操作时间
			log.setType("1");

			//添加保存日志
			systemLogMapper.insert(log);
    	}

        //注销
        if ("/userInfo/exitLogin".equals(url)) {
        	if (null != userJson && null != orgInfoJson
        			&& !"".equals(userJson) && !"".equals(orgInfoJson)) {
        		Map<String, String> user_map = getUserOrgInfo(userJson, orgInfoJson);
        		//修改条件
        		SystemLogExample example = new SystemLogExample();
        		SystemLogExample.Criteria criteria = example.createCriteria();
        		criteria.andUserZhEqualTo(ObjectUtils.toString(user_map.get("username"),""));
        		criteria.andOrgIdEqualTo(Integer.parseInt(user_map.get("orgId")));
        		criteria.andTypeEqualTo("1");
        		example.setOrderByClause(" dl_time desc");
        		List<SystemLog> list = systemLogMapper.selectByExample(example);

        		if (null != list && list.size() > 0) {
        			//注销时间
        			list.get(0).setZxTime(new Date());
        			list.get(0).setOperationTime(new Date());//操作时间

        			//修改登录日志信息
        			systemLogMapper.updateByPrimaryKey(list.get(0));
        		}
        	}
    		
    	}
    }
    
    /**
     * get请求
     * @return
     */
    public static String doGet(String url) {
        try {
            HttpClient client = new DefaultHttpClient();
            //发送get请求
            HttpGet request = new HttpGet(url);
            HttpResponse response = client.execute(request);

            /**请求发送成功，并得到响应**/
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                /**读取服务器返回过来的json字符串数据**/
                String strResult = EntityUtils.toString(response.getEntity());

                return strResult;
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
    
    /**
     * 操作日志实现思路：
     * 1、URL要是可以在菜单里面找到对应菜单，那么当前这个操作属于功能操作日志
     * 2、如果没在菜单里面找到对应菜单，却在按钮中找到了，那么就是功能访问日志
     * 3、如果菜单和按钮中都没有找到对应的URL，那么说明当前这个方位没在功能管理里面配置正确，或者没有加入到功能管理中
     * 
     * @param request
     * @param response
     * @param url
     */
    @SuppressWarnings("all")
	private void operationLogger(HttpServletRequest request, HttpServletResponse response, String url, Object handler) {
    	//获取用户信息和单位信息
        String userJson = ObjectUtils.toString(request.getSession().getAttribute("userInfo"),"");
        String orgInfoJson = ObjectUtils.toString(request.getSession().getAttribute("orgInfo"),"");
        Map<String, String> user_map = getUserOrgInfo(userJson, orgInfoJson);

        //是否还需要继续往下执行
        boolean flag = false;

    	//获取菜单权限并且组装功能日志
    	String func_list = (String) redisUtil.get("hasFuncList");
    	JSONArray array = JSONArray.parseArray(func_list);
    	if (null != array && array.size() > 4) {
    		JSONObject object = null;
    		SystemLog log = new SystemLog();
    		for (Iterator iterator = array.iterator(); iterator.hasNext();) {
    			object = (JSONObject) iterator.next();
    			String func_url = ObjectUtils.toString(object.get("funcUrl"));
    			if (url.equals(func_url)) {
    				log.setId(UUID.randomUUID().toString().replace("-", ""));
    				log.setType("3");//功能访问日志
    				log.setSystemIdentify(system_index);//标识
    				log.setUserId(Integer.parseInt(user_map.get("userId")));//用户ID
    				log.setUserZh(ObjectUtils.toString(user_map.get("username"),""));//账号
    				log.setUserName(ObjectUtils.toString(user_map.get("realName"),""));//名称
    				String device_ip = getClientIpAddress(request);
    				log.setDeviceIp(device_ip);//操作IP
    				log.setFuncId(Integer.parseInt(object.get("funcId").toString()));//功能ID
    				log.setFuncName(ObjectUtils.toString(object.get("funcName")));//功能名称
    				log.setOperationTime(new Date());//操作时间
    				log.setUserRole(ObjectUtils.toString(user_map.get("roleName"),""));//角色
    				log.setOrgId(Integer.parseInt(user_map.get("orgId")));//单位
    				
    				String enumid = ObjectUtils.toString(user_map.get("areaCode"), "0");
    				if (!"0".equals(enumid)) {
    					String httpurl = "http://localhost:9022/Enum/findByEnum?id="+Integer.parseInt(enumid);
    					String strResult = doGet(httpurl);
    					if (!"".equals(strResult)) {
    						JSONObject enum_obj = JSONObject.parseObject(strResult);
    						log.setUserAddress(ObjectUtils.toString(enum_obj.get("gbcode"), ""));//行政区划
    					}
    				}

    				//添加保存日志
    				systemLogMapper.insert(log);

    				//已经是操作日志了，那么没必要在遍历按钮了
    				flag = true;
    				//也不用继续当前循环了
    				break;
    			}
    		}
    	}
        //获取按钮权限并且组装访问日志
    	if (!flag) {
    		String perm_list = (String) redisUtil.get("permissionList");
    		JSONArray but_array = JSONArray.parseArray(perm_list);
        	if (null != but_array && but_array.size() > 4) {
        		JSONObject but_object = null;
        		SystemLog log = new SystemLog();
        		for (Iterator iterator = but_array.iterator(); iterator.hasNext();) {
        			but_object = (JSONObject) iterator.next();
        			if (but_object == null) {
        				continue;
        			}
        			String but_url = ObjectUtils.toString(but_object.get("btnUrl"), "");
        			if (url.equals(but_url)) {
        				log.setId(UUID.randomUUID().toString().replace("-", ""));
        				log.setType("2");//功能操作日志
        				log.setSystemIdentify(system_index);//标识
        				log.setUserId(Integer.parseInt(user_map.get("userId")));//用户ID
        				log.setUserZh(ObjectUtils.toString(user_map.get("username"),""));//账号
        				log.setUserName(ObjectUtils.toString(user_map.get("realName"),""));//名称
        				String device_ip = getClientIpAddress(request);
        				log.setDeviceIp(device_ip);//操作IP
        				String f_name = ObjectUtils.toString(but_object.get("funcName"), "");
        				String b_name = ObjectUtils.toString(but_object.get("btnName"), "");
        				String ramark = ObjectUtils.toString(but_object.get("remark"), "");
        				StringBuffer sbf = new StringBuffer();
        				if (!"".equals(ramark)) {
        					sbf.append(f_name).append("功能").append(ramark).append("操作");
        				} else {
        					sbf.append(f_name).append("功能").append(b_name).append("操作");
        				}
        				log.setFuncId(Integer.parseInt(but_object.get("funcId").toString()));//功能ID
        				log.setFuncName(ObjectUtils.toString(sbf.toString(), ""));//菜单名称
        				HandlerMethod h = (HandlerMethod) handler;  
        				log.setMethodName(h.getMethod().getName());//方法名
        				log.setBtnId(Integer.parseInt(but_object.get("btnId").toString()));//按钮ID
        				log.setUserRole(ObjectUtils.toString(user_map.get("roleName"),""));//角色
        				log.setOperationTime(new Date());//操作时间
        				StringBuilder param = new StringBuilder();
                        Map<String,String[]> map = request.getParameterMap();
                        Set<String> key = map.keySet();
                        for (String eachKey: key) {
                            param.append(eachKey+"="+map.get(eachKey)[0]+"； ");
                        }
        				log.setParameter(param.toString());//传入参数

        				String status = ObjectUtils.toString(response.getStatus(), "");
        				log.setOperResult(status);//操作结果状态
        				if ("200".equals(status)) {
        					log.setRtnParam("请求成功");//返回参数
        				} else {
        					log.setRtnParam("请求失败");//返回参数
        				}
        				log.setOrgId(Integer.parseInt(user_map.get("orgId")));//所属机构
        				String enumid = ObjectUtils.toString(user_map.get("areaCode"), "0");
        				if (!"0".equals(enumid)) {
        					String httpurl = "http://localhost:9022/Enum/findByEnum?id="+Integer.parseInt(enumid);
        					String strResult = doGet(httpurl);
        					if (!"".equals(strResult)) {
        						JSONObject enum_obj = JSONObject.parseObject(strResult);
        						log.setUserAddress(ObjectUtils.toString(enum_obj.get("gbcode"), ""));//行政区划
        					}
        				}

        				//添加保存日志
        				systemLogMapper.insert(log);

        				//中断本次循环
        				break;
        			}
        		}
        	}
    	}
    }

	/**
     * afterCompletion是视图渲染完成之后才执行,同样需要preHandle返回true，
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        //该方法通常用于清理资源等工作
    }

    /**
     * 获取客户端IP
     * 
     * @param request
     * @return
     */
    private String getClientIpAddress(HttpServletRequest request) {  
        String clientIp = request.getHeader("x-forwarded-for");  
        if(clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {  
            clientIp = request.getHeader("Proxy-Client-IP");  
        }  
        if(clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {  
            clientIp = request.getHeader("WL-Proxy-Client-IP");  
        }  
        if(clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {  
            clientIp = request.getRemoteAddr();  
        }  
        return "0:0:0:0:0:0:0:1".equals(clientIp) ? "127.0.0.1" : clientIp;  
    }

}
