package me.chyxion.tigon.shiro.model;

import lombok.Getter;
import lombok.Setter;
import java.util.Map;
import lombok.ToString;
import java.util.HashMap;
import java.io.Serializable;
import org.apache.shiro.SecurityUtils;
import org.springframework.util.Assert;
import org.apache.shiro.session.Session;

/**
 * @version 0.0.1
 * @since 0.0.1
 * @author Shaun Chyxion <br>
 * chyxion@163.com <br>
 * May 12, 2016 10:42:39 AM
 */
@Getter
@Setter
@ToString
public class AuthUser<U> implements Serializable {
    private static final long serialVersionUID = 1L;

    public static final String SESSION_AUTH_USER_KEY = "__AUTH_USER__";
    public static final String OFFLINE = "__OFFLINE__";
    public static final String OFFLINE_MSG = "__OFFLINE_MSG__";

    protected Serializable userId;
    protected U user;
    protected Map<String, Serializable> attrs;
    
    /**
     * save this to session
     * @param session
     */
    public void save(Session session) {
        save(session, this);
    }

    /**
     * put this to session
     */
    public void save() {
        save(SecurityUtils.getSubject().getSession(false));
    }

    /**
     * get auth user from session
     * @param session session
     * @param <U> auth user data type
     * @return auth user
     */
    @SuppressWarnings("unchecked")
    public static <U> AuthUser<U> get(Session session) {
        return (AuthUser<U>) session.getAttribute(SESSION_AUTH_USER_KEY);
    }

    /**
     * get auth user from current session
     * @param <U> auth user data type
     * @return auth user
     */
    public static <U> AuthUser<U> get() {
        return get(SecurityUtils.getSubject().getSession(false));
    }

    /**
     * put auth user to session
     * @param session session
     * @param authUser auth user
     */
    public static void save(Session session, AuthUser<?> authUser) {
        Assert.notNull(session, "Session could not be null");
        Assert.notNull(authUser, "Auth user could not be null");
        Assert.state(authUser.getUserId() != null, "Auth user id could not be null");
        session.setAttribute(SESSION_AUTH_USER_KEY, authUser);
        session.touch();
    }

    /**
     * @param name attr name
     * @param value attr value
     * @return auth user
     */
    public AuthUser<U> setAttr(String name, Serializable value) {
        if (attrs == null) {
            attrs = new HashMap<>();
        }
        attrs.put(name, value);
        return this;
    }

    /**
     * @param name attr name
     * @param <T> attr type
     * @return attr value
     */
    @SuppressWarnings("unchecked")
    public <T> T removeAttr(String name) {
        return attrs != null ? (T) attrs.remove(name) : null;
    }
    
    /**
     * @param name attr name
     * @param <T> attr type
     * @return attr value
     */
    @SuppressWarnings("unchecked")
    public <T> T getAttr(String name) {
        T value = null;
        if (attrs != null) {
            value = (T) attrs.get(name);
        }
        return value;
    }
}
