/*
 * Copyright 2017 Robert Li.
 * Released under the MIT license
 * https://opensource.org/licenses/MIT
 */
package robertli.zero.core.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.stereotype.Component;
import robertli.zero.core.AppConfiguration;
import robertli.zero.core.ClientAccessTokenManager;
import robertli.zero.tool.MD5;

/**
 *
 * @see ClientAccessTokenManager
 * @version 2017-01-26 1.0.1
 * @author Robert Li
 */
@Component("clientAccessTokenManager")
public class ClientAccessTokenManagerImpl implements ClientAccessTokenManager {

    @Resource
    private AppConfiguration appConfiguration;

    private static final String COOKIE_ACCESS_TOKEN_O = "access_token_o";
    private static final String COOKIE_ACCESS_TOKEN_P = "access_token_p";
    private static final int ACCESS_KEY_MAX_AGE = 5 * 365 * 24 * 3600;

    private Map<String, String> getCookieMap(HttpServletRequest request) {
        Map<String, String> cookieMap = new HashMap<>();
        Cookie[] cookieArray = request.getCookies();
        if (cookieArray == null) {
            return cookieMap;
        }
        for (Cookie cookie : cookieArray) {
            String key = cookie.getName();
            String val = cookie.getValue();
            cookieMap.put(key, val);
        }
        return cookieMap;
    }

    private Map<String, String> getCookieMap(ServerHttpRequest request) {
        Map<String, String> cookieMap = new HashMap<>();
        List<String> cookieValues = request.getHeaders().get("Cookie");
        if (cookieValues == null || cookieValues.isEmpty()) {
            return cookieMap;
        }
        if (cookieMap.size() > 1) {
            Logger logger = Logger.getLogger("ClientAccessTokenManager");
            logger.log(Level.WARNING, "The 'Cookie' lines within Headers are more than one.");
        }
        String cookies[] = cookieValues.get(0).split(";");
        for (String cookie : cookies) {
            cookie = cookie.trim();
            String parts[] = cookie.split("=");
            cookieMap.put(parts[0], parts[1]);
        }
        return cookieMap;
    }

    @Override
    public String countAccessToken(String accessTokenO) {
        String salt = appConfiguration.getMd5Salt();
        return MD5.count(accessTokenO + salt);
    }

    @Override
    public String countAccessTokenP(String accessToken) {
        String salt = appConfiguration.getMd5Salt();
        return MD5.count(accessToken + salt);
    }

    private boolean isValidAccessToken(String accessTokenO, String accessTokenP) {
        if (accessTokenO == null || accessTokenP == null) {
            return false;
        }
        String accessToken = countAccessToken(accessTokenO);
        String salt = appConfiguration.getMd5Salt();
        String p = MD5.count(accessToken + salt);
        return p.equals(accessTokenP);
    }

    private String getAccessToken(Map<String, String> cookieMap) {
        //get access_token directly, so just use it.
        String accessToken = cookieMap.get("access_token");
        if (accessToken != null) {
            return accessToken;
        }

        String accessTokenO = cookieMap.get("access_token_o");
        String accessTokenP = cookieMap.get("access_token_p");
        if (isValidAccessToken(accessTokenO, accessTokenP)) {
            return countAccessToken(accessTokenO);
        }
        return null;
    }

    @Override
    public String getAccessToken(HttpServletRequest request) {
        Map<String, String> cookieMap = getCookieMap(request);
        return getAccessToken(cookieMap);
    }

    @Override
    public String getAccessToken(ServerHttpRequest request) {
        Map<String, String> cookieMap = getCookieMap(request);
        return getAccessToken(cookieMap);
    }

    private void putCookie(HttpServletResponse response, String name, String val, boolean httpOnly) {
        Cookie cookie = new Cookie(name, val);
        cookie.setHttpOnly(httpOnly);
        cookie.setMaxAge(ACCESS_KEY_MAX_AGE);
        cookie.setPath("/");
        response.addCookie(cookie);
    }

    @Override
    public void putAccessTokenO(HttpServletResponse response, String accessTokenO) {
        String accessToken = countAccessToken(accessTokenO);
        String accessTokenP = countAccessTokenP(accessToken);
        putCookie(response, COOKIE_ACCESS_TOKEN_O, accessTokenO, true);
        putCookie(response, COOKIE_ACCESS_TOKEN_P, accessTokenP, false);
    }

    private void deleteCookie(HttpServletResponse response, String name) {
        Cookie cookie = new Cookie(name, null);
        cookie.setMaxAge(0);
        cookie.setPath("/");
        response.addCookie(cookie);
    }

    @Override
    public void deleteAccessToken(HttpServletResponse response) {
        deleteCookie(response, COOKIE_ACCESS_TOKEN_O);
        deleteCookie(response, COOKIE_ACCESS_TOKEN_P);
    }

}

@@ -211,73 +211,8 @@
 ap;%0A
-import java.util.logging.Level;%0Aimport java.util.logging.Logger;%0A
 impo
@@ -665,18 +665,18 @@
 17-0
-1-26
+8-23
  1.0.
-1
+2
 %0A * 
@@ -1887,204 +1887,48 @@
     
-if (cookieMap.size() %3E 1) %7B%0A            Logger logger = Logger.getLogger(%22ClientAccessTokenManager%22);%0A            logger.log(Level.WARNING, %22The 'Cookie' lines within Headers are more than one.%22);
+for (String cookieLine : cookieValues) %7B
 %0A   
@@ -1928,33 +1928,33 @@
 ) %7B%0A        
-%7D%0A
     
-   
+final
  String cook
@@ -1971,21 +1971,12 @@
 okie
-Values.get(0)
+Line
 .spl
@@ -1984,32 +1984,36 @@
 t(%22;%22);%0A        
+    
 for (String cook
@@ -2024,24 +2024,28 @@
  cookies) %7B%0A
+    
             
@@ -2072,32 +2072,36 @@
 ();%0A            
+    
 String parts%5B%5D =
@@ -2124,32 +2124,36 @@
 %22);%0A            
+    
 cookieMap.put(pa
@@ -2171,16 +2171,30 @@
 ts%5B1%5D);%0A
+            %7D%0A
         

fix bugs for picking Cookies