package com.storlead.framework.core.context;

import com.alibaba.ttl.TransmittableThreadLocal;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @Author Created by chenkq on 2020/4/30
 */
public class Context implements IContext {

    // Tread 线程的一个本地化对象
    private static final TransmittableThreadLocal<IContext> contextTreadLocal = new TransmittableThreadLocal<>();

    private Map<String, Object> attributes = new Hashtable<>();
    private HttpServletRequest request;
    private HttpServletResponse response;

    private boolean validate = true;

    // 支持的三种语言
    public static final Set<Locale> LOCAL_LIST = new HashSet<Locale>(
            Arrays.asList(new Locale[] { Locale.TAIWAN, Locale.US, Locale.CHINA }));

    public Context() {

    }

    /**
     * 获取本线程的TreadLocal
     *
     * 例：  获取线程里的变量需要先获取这个
     * IContext context = Context.getContext();
     * **/
    public static final IContext getContext() {
        return ((IContext) contextTreadLocal.get());
    }

    /**
     * 获取本线程的 TreadLocal
     * @param context 为己初使化的本类
     *
     * 例：
     * 	Context context = new Context();
     *  context.init(request,response);
     *  Context.setContext(context);// 放在线程变量
     * **/
    public static final void setContext(Context context) {
        contextTreadLocal.set(context);
    }

    /**
     * 销毁上下文   (注意， 设置了上下文，线程销毁时一定要销毁这个)
     *
     * **/
    public static final void destroy() {
        Context context = (Context) contextTreadLocal.get();
        if (context != null) {
            contextTreadLocal.set(null);
            context.request = null;
            context.response = null;
            context.attributes.clear();
        }
    }

    /**
     * 移除属性（从会话上下文删除会话属性）
     **/
    @Override
    public void removeAttribute(String attr) {
        attributes.remove(attr);

    }

    /**
     * 获取属性（从上下文获取会话属性）
     * @see
     **/
    @SuppressWarnings("unchecked")
    @Override
    public <T> T getAttribute(String attr, Class<T> attrType) {
        Object value = attributes.get(attr);
        if (value == null) {
            return null;
        }

        // 判断获取的class，是否是指定的class
        if (attrType != null && !attrType.isAssignableFrom(value.getClass())) {
            throw new ClassCastException("类型转换错误 : attr:"+attr+" class:" + value.getClass() + " cannot cast to " + attrType);
        }

        return (T) value;
    }

    /**
     * 设置会话属性。   name在整个Context里唯一，应避免不同属性重复。
     * @see
     * @param name   名称
     * @param value  值
     *
     * 如 setAttribute("user_data", user);
     **/
    @Override
    public void setAttribute(String name, Object value) {
        if (validate && value!=null) {
            attributes.put(name, value);
        }

    }

    /**
     * 使得这个Context失效、与Session失效 ，   （销毁本上下文）
     *
     * @see
     **/
    @Override
    public void invalidate() {
        validate = false;
        attributes.clear();

        Context.destroy(); // 销毁本线程上下文
    }

    /**
     * 初始化请求上下文（设置请求与返回类）
     * @see
     **/
    @Override
    public void init(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;

    }

    /**
     * 获取request里的请求头
     * @see
     * @param attr 属性key
     * @param
     *
     *
     **/
    @SuppressWarnings("unchecked")
    @Override
    public <T> T getRequestHeader(String attr, Class<T> requiredType) {
        if (request == null) {
            return null;
        }
        Object value = request.getHeader(attr);
        if (value == null) {
            return null;
        }
        if (requiredType != null && !requiredType.isAssignableFrom(value.getClass())) {
            throw new ClassCastException("类型转换错误 :" + value.getClass() + " cannot cast to " + requiredType);
        }
        return (T) value;
    }

    /**
     * 获取客户端发请求的 get或post值
     **/
    @Override
    public String getRequestParameter(String attr) {
        if (request == null) {
            return null;
        }
        String value = request.getParameter(attr);
        if (value == null) {
            return null;
        }

        return value;
    }

    /**
     * 获取请求头类
     **/
    @Override
    public HttpServletRequest getRequest() {
        if (request == null) {
            return null;
        }
        return request;
    }

    /**
     * 获取返回头类
     **/
    @Override
    public HttpServletResponse getResponse() {

        return response;
    }

    /**
     * 获取请求的Web站点的域名
     * 没有设置 request ，则返回空
     * https://ww.baidu.com
     **/
    @Override
    public String getHostAddress() {
        if (request == null) {
            return null;
        }
        if (request.getServerPort() == 80) { // 80 的不用加端口号
            return request.getScheme() + "://" + request.getServerName() + request.getContextPath();
        } else {
            return request.getScheme() + "://" + request.getServerName() + " :" + request.getServerPort()
                    + request.getContextPath();
        }
    }

    /**
     * 获取客户端IP地址
     **/
    @Override
    public String getIpAddress() {
        if (request == null) {
            return "127.0.0.1";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 获取当前Locale  默认中国
     **/
    @Override
    public Locale getLocale() {
        if (request != null && request.getHeader("Accept-Language") != null) {
            Locale locale = request.getLocale();
            if (locale.getLanguage().equals(Locale.US.getLanguage())) {
                return Locale.US;
            } else {
                return locale;
            }
        } else {
            return Locale.CHINA;
        }
    }
}
