package oasis.services.authn;

import static com.google.common.base.Preconditions.*;

import java.util.Set;

import javax.inject.Inject;

import org.joda.time.Duration;
import org.joda.time.Instant;

import com.google.common.base.Strings;

import oasis.model.accounts.AccessToken;
import oasis.model.accounts.AccessTokenGenerator;
import oasis.model.accounts.AuthorizationCode;
import oasis.model.accounts.RefreshToken;
import oasis.model.accounts.Token;
import oasis.model.authn.TokenRepository;

public class TokenHandler {
  private final TokenRepository tokenRepository;

  @Inject TokenHandler(TokenRepository tokenRepository) {
    this.tokenRepository = tokenRepository;
  }

  public boolean checkTokenValidity(Token token) {
    // A null token is not valid !
    if (token == null) {
      return false;
    }

    // Compute the token Expiration Date
    Instant tokenExpirationDate = token.getCreationTime().plus(token.getTimeToLive());
    if (tokenExpirationDate.isBefore(Instant.now())) {
      // Token is expired
      return false;
    }

    // The token is valid
    return true;
  }

  public AccessToken createAccessToken(String accountId, AccessTokenGenerator oauthToken) {
    return this.createAccessToken(accountId, Duration.standardHours(1), oauthToken, null);
  }

  public AccessToken createAccessToken(String accountId, AccessTokenGenerator oauthToken, Set<String> scopeIds) {
    return this.createAccessToken(accountId, Duration.standardHours(1), oauthToken, scopeIds);
  }

  private AccessToken createAccessToken(String accountId, Duration ttl, AccessTokenGenerator token, Set<String> scopeIds) {
    checkArgument(!Strings.isNullOrEmpty(accountId));

    if (scopeIds == null || scopeIds.isEmpty()) {
      scopeIds = checkNotNull(token).getScopeIds();
    }

    String serviceProviderId;

    AccessToken newAccessToken = new AccessToken();

    newAccessToken.setCreationTime(Instant.now());
    newAccessToken.setTimeToLive(ttl);
    newAccessToken.setScopeIds(scopeIds);
    if (token != null) {
      serviceProviderId = token.getServiceProviderId();

      if (token instanceof AuthorizationCode) {
        if (!tokenRepository.revokeToken(token.getId())) {
          return null;
        }
      } else if (token instanceof RefreshToken) {
        newAccessToken.setRefreshTokenId(token.getId());
      }
    } else {
      // TODO : Get the ServiceProviderId
      serviceProviderId = null;
    }
    newAccessToken.setServiceProviderId(serviceProviderId);

    if (!registerToken(accountId, newAccessToken)) {
      return null;
    }

    // Return the new access token
    return newAccessToken;
  }

  public AuthorizationCode createAuthorizationCode(String accountId, Set<String> scopeIds, String serviceProviderId, String nonce) {
    checkArgument(!Strings.isNullOrEmpty(accountId));

    AuthorizationCode newAuthorizationCode = new AuthorizationCode();

    newAuthorizationCode.setCreationTime(Instant.now());
    // A AuthorizationCode is available only for 1 minute
    newAuthorizationCode.setTimeToLive(Duration.standardMinutes(1));
    newAuthorizationCode.setScopeIds(scopeIds);
    newAuthorizationCode.setServiceProviderId(serviceProviderId);
    newAuthorizationCode.setNonce(nonce);

    // Register the new token
    if (!registerToken(accountId, newAuthorizationCode)) {
      return null;
    }

    // Return the new token
    return newAuthorizationCode;
  }

  public RefreshToken createRefreshToken(String accountId, AuthorizationCode authorizationCode) {
    checkArgument(!Strings.isNullOrEmpty(accountId));

    RefreshToken refreshToken = new RefreshToken();

    refreshToken.setCreationTime(Instant.now());
    // A RefreshToken is valid 50 years
    refreshToken.setTimeToLive(Duration.standardDays(50 * 365));
    refreshToken.setScopeIds(authorizationCode.getScopeIds());
    refreshToken.setServiceProviderId(authorizationCode.getServiceProviderId());

    // Register the new token
    if (!registerToken(accountId, refreshToken)) {
      return null;
    }

    return refreshToken;
  }

  public boolean registerToken(String accountId, Token token) {
    checkArgument(!Strings.isNullOrEmpty(accountId));
    checkNotNull(token);

    return tokenRepository.registerToken(accountId, token);
  }
}

@@ -1792,39 +1792,8 @@
  %7D%0A%0A
-    String serviceProviderId;%0A%0A
     
@@ -1977,92 +1977,9 @@
 s);%0A
-    if (token != null) %7B%0A      serviceProviderId = token.getServiceProviderId();%0A%0A  
+%0A
     
@@ -2026,18 +2026,16 @@
 %7B%0A      
-  
 if (!tok
@@ -2081,26 +2081,24 @@
 ) %7B%0A        
-  
 return null;
@@ -2098,18 +2098,16 @@
 n null;%0A
-  
       %7D%0A
@@ -2110,18 +2110,16 @@
   %7D%0A    
-  
 %7D else i
@@ -2150,26 +2150,24 @@
 eshToken) %7B%0A
-  
       newAcc
@@ -2213,103 +2213,8 @@
 ));%0A
-      %7D%0A    %7D else %7B%0A      // TODO : Get the ServiceProviderId%0A      serviceProviderId = null;%0A
     
@@ -2247,33 +2247,42 @@
 rviceProviderId(
-s
+token.getS
 erviceProviderId
@@ -2281,16 +2281,18 @@
 oviderId
+()
 );%0A%0A    

Access Tokens must be created from a RefreshToken