package com.house365.rest.log;

import com.house365.commons.system.TCPIPUtils;

import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.springframework.web.util.UrlPathHelper;

/**
 * rest log bean
 * 
 * @author hqc
 * @version 1.0
 */
public class HttpRequestLogger implements Serializable {

    private static final long serialVersionUID = 1L;

    private Integer id;

    /**
     * 日志标题
     */
    private String title;

    /**
     * 请求URI
     */
    private String uri;

    /**
     * 请求方法(GET/POST/PUT/DELETE/INPUT)
     */
    private String method;

    /**
     * 请求参数列表(字符串形式)
     */
    private Map<String, String> params;

    private String serviceCode;

    private String serviceName;

    /**
     * 访问者ip地址
     */
    private String clientIpAddr;

    /**
     * 被访问的服务器地址+端口号
     */
    private String serverIpAddr;

    /**
     * 访问开始系统毫秒数
     */
    private Long optBeginMillis;

    /**
     * 访问结束系统毫秒数
     */
    private Long optEndMillis;

    /**
     * 处理时间
     */
    private Long processTime;

    /**
     * 请求返回的http status
     */
    private Integer httpStatus;

    /**
     * 业务返回码 1 成功 0 失败
     */
    private String code;

    /**
     * 信息
     */
    private String msg;

    public static HttpRequestLogger beginLog(HttpServletRequest request, String title) {
        HttpRequestLogger log = new HttpRequestLogger();
        log.setOptBeginMillis(System.currentTimeMillis());
        log.setTitle(title);
        log.setUri(new UrlPathHelper().getRequestUri(request));
        log.setMethod(request.getMethod());
        Map<String, String> paramMap = new HashMap<String, String>();
        @SuppressWarnings("unchecked")
        Map<String, String[]> originalParamMap = request.getParameterMap();
        if (originalParamMap != null && !originalParamMap.isEmpty()) {
            for (Map.Entry<String, String[]> entry : originalParamMap.entrySet()) {
                paramMap.put(entry.getKey(), getStringParameterValue(entry.getValue()));
                if ("serviceCode".equals(entry.getKey())) {
                    log.setServiceCode(getStringParameterValue(entry.getValue()));
                }
                if ("serviceName".equals(entry.getKey())) {
                    log.setServiceName(getStringParameterValue(entry.getValue()));
                }
            }
            log.setParams(paramMap);
        }
        log.setServerIpAddr(TCPIPUtils.getLocalIpAddr(request));
        log.setClientIpAddr(TCPIPUtils.getRemoteIpAddr(request));
        return log;
    }

    public void endLog(String code, String msg, int httpStatus) {
        this.setOptEndMillis(System.currentTimeMillis());
        this.setProcessTime(this.getOptEndMillis() - this.getOptBeginMillis());
        this.setMsg((msg != null && msg.length() < 399) ? msg : msg.substring(0, 399));
        this.setCode(code);
        this.setHttpStatus(httpStatus);
    }

    private static String getStringParameterValue(String[] values) {
        if (values == null) {
            return null;
        } else {
            return values.length == 1 ? values[0] : Arrays.toString(values);
        }
    }

    /**
     * @return the httpStatus
     */
    public Integer getHttpStatus() {
        return httpStatus;
    }

    /**
     * @param httpStatus
     *            the httpStatus to set
     */
    public void setHttpStatus(Integer httpStatus) {
        this.httpStatus = httpStatus;
    }

    /**
     * @return the code
     */
    public String getCode() {
        return code;
    }

    /**
     * @param code
     *            the code to set
     */
    public void setCode(String code) {
        this.code = code;
    }

    /**
     * @return the msg
     */
    public String getMsg() {
        return msg;
    }

    /**
     * @param msg
     *            the msg to set
     */
    public void setMsg(String msg) {
        this.msg = msg;
    }

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param title
     *            the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * @return the uri
     */
    public String getUri() {
        return uri;
    }

    /**
     * @param uri
     *            the uri to set
     */
    public void setUri(String uri) {
        this.uri = uri;
    }

    /**
     * @return the method
     */
    public String getMethod() {
        return method;
    }

    /**
     * @param method
     *            the method to set
     */
    public void setMethod(String method) {
        this.method = method;
    }

    /**
     * @return the params
     */
    public Map<String, String> getParams() {
        return params;
    }

    /**
     * @param params
     *            the params to set
     */
    public void setParams(Map<String, String> params) {
        this.params = params;
    }

    /**
     * @return the clientIpAddr
     */
    public String getClientIpAddr() {
        return clientIpAddr;
    }

    /**
     * @param clientIpAddr
     *            the clientIpAddr to set
     */
    public void setClientIpAddr(String clientIpAddr) {
        this.clientIpAddr = clientIpAddr;
    }

    /**
     * @return the serverIpAddr
     */
    public String getServerIpAddr() {
        return serverIpAddr;
    }

    /**
     * @param serverIpAddr
     *            the serverIpAddr to set
     */
    public void setServerIpAddr(String serverIpAddr) {
        this.serverIpAddr = serverIpAddr;
    }

    /**
     * @return the optBeginMillis
     */
    public Long getOptBeginMillis() {
        return optBeginMillis;
    }

    /**
     * @param optBeginMillis
     *            the optBeginMillis to set
     */
    public void setOptBeginMillis(Long optBeginMillis) {
        this.optBeginMillis = optBeginMillis;
    }

    /**
     * @return the optEndMillis
     */
    public Long getOptEndMillis() {
        return optEndMillis;
    }

    /**
     * @param optEndMillis
     *            the optEndMillis to set
     */
    public void setOptEndMillis(Long optEndMillis) {
        this.optEndMillis = optEndMillis;
    }

    /**
     * @return the processTime
     */
    public Long getProcessTime() {
        return processTime;
    }

    /**
     * @return the serviceCode
     */
    public String getServiceCode() {
        return serviceCode;
    }

    /**
     * @param serviceCode
     *            the serviceCode to set
     */
    public void setServiceCode(String serviceCode) {
        this.serviceCode = serviceCode;
    }

    /**
     * @return the serviceName
     */
    public String getServiceName() {
        return serviceName;
    }

    /**
     * @param serviceName
     *            the serviceName to set
     */
    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    /**
     * @param processTime
     *            the processTime to set
     */
    public void setProcessTime(Long processTime) {
        this.processTime = processTime;
    }

    /**
     * @return the id
     */
    public Integer getId() {
        return id;
    }

    /**
     * @param id
     *            the id to set
     */
    public void setId(Integer id) {
        this.id = id;
    }

    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}