package me.chyxion.tigon.shiro;

import java.util.Map;
import java.util.HashMap;
import org.apache.shiro.ShiroException;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.core.annotation.Order;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import me.chyxion.tigon.webmvc.exception.DefaultExceptionResolver;

/**
 * @version 0.0.1
 * @since 0.0.1
 * @author Shaun Chyxion <br>
 * chyxion@163.com <br>
 * Jul 21, 2015 1:22:28 PM
 */
@Order(8)
public class AuthExceptionResolver extends DefaultExceptionResolver {
    
    private static final Map<Class<? extends ShiroException>, Pair<Integer, String>> 
        EXCEPTIONS_MAP = 
            new HashMap<Class<? extends ShiroException>, Pair<Integer, String>>() {
                private static final long serialVersionUID = 1L;
                {
                    put(AuthenticationException.class, 
                        pair(4010, "Authentication Exception"));
                    put(AuthorizationException.class, 
                        pair(4010, "Authorization Exception"));
                    put(UnauthenticatedException.class, 
                        pair(4011, "Unauthenticated"));
                    put(UnknownAccountException.class, 
                        pair(4012, "Unknown Account"));
                    put(IncorrectCredentialsException.class, 
                        pair(4013, "Incorrect Credentials"));
                    put(ExpiredCredentialsException.class, 
                        pair(4014, "Expired Credentials"));
                    put(LockedAccountException.class, 
                        pair(4015, "Locked Account"));
                    put(UnauthorizedException.class,
                        pair(4016, "Unauthorized"));
                }

                /**
                 * new code msg pair
                 * @param code
                 * @param msg
                 * @return
                 */
                private Pair<Integer, String> pair(Integer code, String msg) {
                    return ImmutablePair.<Integer, String>of(code, msg);
                }
        };

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean accept(Throwable ex) {
        return EXCEPTIONS_MAP.containsKey(ex.getClass());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Object getErrorCode(Throwable ex) {
        return EXCEPTIONS_MAP.get(ex.getClass()).getKey();
    }

    /**
     * {@inheritDoc} 
     */
    @Override
    protected Object getErrorMessage(Throwable ex, Object code) {
        return EXCEPTIONS_MAP.get(ex.getClass()).getValue();
    }
}
