package com.identityforge.aad.adcl4j;

import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import org.apache.commons.lang3.StringUtils;

import java.net.MalformedURLException;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Created by nwoolls on 5/4/15.
 */
public class AuthClientImpl implements  AuthClient {

    private static final String GRAPH_API_URI = "https://graph.windows.net";
    private static final String AUTHORITY_URI = "https://login.windows.net/common";

    private AuthenticationResult authenticationResult = null;
    private final String clientId;
    private final String username;
    private final String password;

    public AuthClientImpl(String clientId, String username, String password) {

        this.clientId = clientId;
        this.username = username;
        this.password = password;
    }

    public AuthenticationResult getAuthenticationResult() {
        return authenticationResult;
    }

    public void ensureAuthenticated() throws AuthenticationException {

        // we do not have a valid token
        Boolean valid_token = false;

        // have we previously authenticated?
        if (authenticationResult != null) {
            Date expiresDate = authenticationResult.getExpiresOnDate();
            Date now = new Date();
            // has our token expired?
            if (expiresDate.before(now)) {

                // get a new token using the stored refresh token
                authenticationResult = getAccessTokenFromRefreshToken();
                valid_token = true;

            } else
                valid_token = true;
        }

        // we do not have a valid token - authenticate
        if (!valid_token) {
            authenticationResult = getAccessTokenFromUserCredentials(
                    this.clientId, this.username, this.password);
        }
    }

    public Boolean validateCredentials(String username, String password) {

        Boolean result = false;

        try {
            AuthenticationResult response = getAccessTokenFromUserCredentials(this.clientId, username, password);
            result = !StringUtils.isEmpty(response.getAccessToken());
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }

        return result;
    }

    private AuthenticationResult getAccessTokenFromRefreshToken() throws AuthenticationException {

        AuthenticationContext context = null;
        AuthenticationResult result = null;
        ExecutorService service = null;
        try {
            try {
                service = Executors.newFixedThreadPool(1);
                context = new AuthenticationContext(AUTHORITY_URI, false, service);
                Future<AuthenticationResult> future = context.acquireTokenByRefreshToken(authenticationResult.getRefreshToken(),
                        clientId, null);
                result = future.get();
            } catch (InterruptedException |
                    MalformedURLException |
                    ExecutionException e) {
                e.printStackTrace();
                throw new AuthenticationException(e.getLocalizedMessage());
            }
        } finally {
            service.shutdown();
        }

        if (result == null) {
            throw new AuthenticationException("authentication result was null");
        }
        return result;
    }

    private AuthenticationResult getAccessTokenFromUserCredentials(
            String clientId, String username, String password)
            throws AuthenticationException {
        AuthenticationContext context = null;
        AuthenticationResult result = null;
        ExecutorService service = null;
        try {
            try {
                service = Executors.newFixedThreadPool(1);
                context = new AuthenticationContext(AUTHORITY_URI, false, service);
                Future<AuthenticationResult> future = context.acquireToken(
                        GRAPH_API_URI, clientId, username, password, null);
                result = future.get();
            } catch (InterruptedException |
                    MalformedURLException |
                    ExecutionException e) {
                e.printStackTrace();
                throw new AuthenticationException(e.getLocalizedMessage());
            }
        } finally {
            service.shutdown();
        }

        if (result == null) {
            throw new AuthenticationException("authentication result was null");
        }
        return result;
    }
}

@@ -1982,23 +1982,8 @@
     
- this.clientId,
  thi
@@ -2232,23 +2232,8 @@
 als(
-this.clientId, 
 user
@@ -2538,25 +2538,24 @@
 ption %7B%0A
-%0A
         
 Authenti
@@ -2550,687 +2550,201 @@
     
-AuthenticationContext context = null;%0A        AuthenticationResult result = null;%0A        ExecutorService service = null;%0A        try %7B%0A            try %7B%0A                service = Executors.newFixedThreadPool(1);%0A                context = new AuthenticationContext(AUTHORITY_URI, false, service);%0A                Future%3CAuthenticationResult%3E future = context.acquireTokenByRefreshToken(authenticationResult.getRefreshToken(),%0A                        clientId, null);%0A                result = future.get();%0A            %7D catch (InterruptedException %7C%0A                    MalformedURLException %7C%0A                    ExecutionException e) %7B%0A                e.printStackTrace();%0A    
+return getAccessToken(clientId, null, null, authenticationResult.getRefreshToken());%0A    %7D%0A%0A    private AuthenticationResult getAccessTokenFromUserCredentials(String username, String password)%0A
     
@@ -2748,36 +2748,33 @@
            throw
- new
+s
  AuthenticationE
@@ -2785,256 +2785,78 @@
 tion
-(e.getLocalizedMessage());%0A            %7D%0A        %7D finally %7B%0A            service.shutdown();%0A        %7D%0A%0A        if (result == null) %7B%0A            throw new AuthenticationException(%22authentication result was
+ %7B%0A        return getAccessToken(clientId, username, password,
  null
-%22
 );%0A
-        %7D%0A        return result;%0A
     
@@ -2905,35 +2905,16 @@
 essToken
-FromUserCredentials
 (%0A      
@@ -2960,32 +2960,53 @@
  String password
+, String refreshToken
 )%0A            th
@@ -3028,32 +3028,33 @@
 tionException %7B%0A
+%0A
         Authenti
@@ -3074,23 +3074,16 @@
  context
- = null
 ;%0A      
@@ -3154,20 +3154,47 @@
 rvice = 
-null
+Executors.newFixedThreadPool(1)
 ;%0A      
@@ -3223,67 +3223,8 @@
 y %7B%0A
-                service = Executors.newFixedThreadPool(1);%0A
     
@@ -3358,108 +3358,293 @@
 ture
- = context.acquireToken(%0A                        GRAPH_API_URI, clientId, username, password, null);
+;%0A                if (refreshToken == null) %7B%0A                    future = context.acquireToken(GRAPH_API_URI, clientId, username, password, null);%0A                %7D else %7B%0A                    future = context.acquireTokenByRefreshToken(refreshToken, clientId, null);%0A                %7D
 %0A   

Refactor authentication code to eliminate duplicated logic