/*
 * AuthUser.java
 * Copyright (C)  1999-2011 EMC Corporation. All Rights Reserved.
 */
package sample;

import com.rsa.authagent.authapi.HidePasswordFromCommandLine;
import com.rsa.authagent.authapi.AuthAgentException;
import com.rsa.authagent.authapi.AuthSession;
import com.rsa.authagent.authapi.AuthSessionFactory;
import sample.io.ConsoleIO;

/**
 * This sample performs a SecurID authentication.
 */
public class AuthUser
{
    private static final String ACCESS_DENIED = "Access Denied";
    private static final String PASSCODE_ACCEPTED = "Passcode Accepted";
    private static final String PIN_REJECTED = "New Pin rejected";
    private static final String PIN_ACCEPTED = "New Pin accepted; please login again with the new Pin.";
    private static final String GOOD_AUTH = "Authentication successful";
    private static final String BAD_AUTH = "Authentication incomplete";
    
    private AuthSessionFactory api = null;
    private ConsoleIO io;
    
    private AuthUser(String path) throws Exception
    {
        io = new ConsoleIO();
        try
        {
            api = AuthSessionFactory.getInstance(path);
//            io.outputLn(api.getAceServerStatus().toString());
        }
        catch (AuthAgentException e)
        {
            io.outputLn("Can't create api: " + e.getMessage());
            throw e;
        }
    }
    
    /**
     * main function entry for the sample application.
     * @param args The first element is an optional path to 
     * a custom properties file.
     */
    public static void main(String[] args)
    {
        String path;
        
        if (args == null || args.length == 0)
        {
            path = null;
        }
        else
        {
            path = args[0];
        }
        AuthUser test;
        try
        {
            test = new AuthUser(path);
            test.run();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    
    private void run() throws Exception
    {
        try
        {
	        while (true)
	        {
	            auth();
	            String yesOrNo = io.input("Continue? [y/n] ");
	            if (!yesOrNo.trim().toLowerCase().startsWith("y"))
	            {
	                break;
	            }
	        }
        }
        catch (Exception e)
        {
			io.outputLn(e.getMessage());
            io.outputLn("Aborting application");
        }
        finally
        {
            if (api != null)
            {
//                io.outputLn(api.getAceServerStatus().toString());
                api.shutdown();
            }
        }
    }
    
    private void auth() throws Exception
    {
        String userName;
        String passCode;
        AuthSession session;

        session = api.createUserSession();
        userName = io.input("Username: ");
        
        int authStatus = AuthSession.ACCESS_DENIED;
        for (int i = 0; i < 3 && authStatus != AuthSession.ACCESS_OK; i++)
        {            
        	//HidePasswordFromCommandLine hideThread = new HidePasswordFromCommandLine();
            //hideThread.start();
            //hideThread.hideInput = true;
        	passCode = io.input("Passcode: ");
        	//hideThread.stopThread = true;
        
            authStatus = session.lock(userName);
            authStatus = session.check(userName, passCode);
            authStatus = finalizeAuth(authStatus, session);
            switch (authStatus)
            {
            case AuthSession.ACCESS_OK :
                io.outputLn(PASSCODE_ACCEPTED);
                break;
            
            case AuthSession.PIN_ACCEPTED :
                io.outputLn(PIN_ACCEPTED);
                i--;
            	continue;
            	
            case AuthSession.PIN_REJECTED :
                io.outputLn(PIN_REJECTED);
                break;
            
            case AuthSession.ACCESS_DENIED :
            default :
                io.outputLn(ACCESS_DENIED);
                continue;
            }
        }
        session.close();
        if (authStatus == AuthSession.ACCESS_OK)
        {
            io.outputLn(GOOD_AUTH);
        }
        else
        {
            io.outputLn(BAD_AUTH);
        }
    }

    /**
     * @param authStatus the initial status
     * @return the final status
     */
    private int finalizeAuth(int authStatus, AuthSession session)
            throws Exception
    {
        int finalStatus;
        switch(authStatus)
        {
        case AuthSession.NEW_PIN_REQUIRED :
            NewPinSession newPin = new NewPinSession(io, session);
        	finalStatus = newPin.process();
        	break;
        
        case AuthSession.NEXT_CODE_REQUIRED :
            NextCodeSession nextCode = new NextCodeSession(io, session);
            finalStatus = nextCode.process();
            break;
            
        case AuthSession.ACCESS_OK :
            finalStatus = authStatus;
        	break;
        
        default:
            finalStatus = AuthSession.ACCESS_DENIED;
            break;
        }
        return finalStatus;
    }

}
