package fsenablers.android.login;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

/**
 * Provides utility methods for communicating with the server.
 */
final public class NetworkUtilities {

    /** The tag used to log to adb console. **/
    private static final String TAG = "NetworkUtilities";

    /** The Intent extra to store password. **/
    public static final String PARAM_PASSWORD = "password";

    /** The Intent extra to store username. **/
    public static final String PARAM_USERNAME = "username";

    public static final String PARAM_UPDATED = "timestamp";

    public static final String USER_AGENT = "AuthenticationService/1.0";

    public static final int REGISTRATION_TIMEOUT_MS = 30 * 1000; // ms

    public static final String BASE_URL = "http://godzilla-7:8500/testing";

    public static final String AUTH_URI = BASE_URL + "/act_authenticate.cfm";

    
    private static HttpClient mHttpClient;

    private NetworkUtilities() {
    }

    /**
     * Configures the httpClient to connect to the URL provided.
     */
    public static void maybeCreateHttpClient() {
        if (mHttpClient == null) {
            mHttpClient = new DefaultHttpClient();
            final HttpParams params = mHttpClient.getParams();
            HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT_MS);
            HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT_MS);
            ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT_MS);
        }
    }

    /**
     * Executes the network requests on a separate thread.
     * 
     * @param runnable The runnable instance containing network mOperations to
     *        be executed.
     */
    public static Thread performOnBackgroundThread(final Runnable runnable) {
        final Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    runnable.run();
                } finally {
                }
            }
        };
        t.start();
        return t;
    }
    
    public static UserAccount performAuthentication( String userName, String password ) {

    	UserAccount userAccount = new UserAccount();
    	
    	final HttpResponse resp;
        final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(PARAM_USERNAME, userName));
        params.add(new BasicNameValuePair(PARAM_PASSWORD, password));
        HttpEntity entity = null;
        try {
            entity = new UrlEncodedFormEntity(params);
        } catch (final UnsupportedEncodingException e) {
            // this should never happen.
            throw new AssertionError(e);
        }
        final HttpPost post = new HttpPost(AUTH_URI);
        post.addHeader(entity.getContentType());
        post.setEntity(entity);
        maybeCreateHttpClient();
        try {
            resp = mHttpClient.execute(post);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Successful authentication");
                }
                
                Log.d( TAG, "ContentType = " + resp.getEntity().getContentType().toString() );
                
                BufferedReader br = new BufferedReader( new InputStreamReader( resp.getEntity().getContent()));
                String lineOfText = br.readLine();
                StringBuffer jsonBuffer = new StringBuffer();
                while( lineOfText != null ) {
                	jsonBuffer.append( lineOfText );
                	lineOfText = br.readLine();
                	
                }
                br.close();
                
                try {
                	JSONObject json = new JSONObject( jsonBuffer.toString() );
                	Log.d( TAG, "JSON = " + json.toString() );
                	
                	userAccount = new UserAccount( 
                		json.getString( "cfid" ),
                		json.getString( "firstName" ),
                		json.getString( "lastName" )
                	);
                	Log.d( TAG, "UserAccount = " + userAccount );
                } catch( JSONException jsx ) {
                	Log.e( TAG, jsx.getMessage() );
                }
                
            } else {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Error authenticating" + resp.getStatusLine());
                }
            }
        } catch (final IOException e) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "IOException when getting authtoken", e);
            }
        } finally {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "getAuthtoken completing");
            }
        }
        
        return userAccount;
    	
    }

    
    public static boolean authenticate(String username, String password, Handler handler,
        final Context context) {

    	
    	UserAccount userAccount = performAuthentication( username, password );
    	sendResult( userAccount, handler, context );
    	
    	return userAccount.isValid();
    	
    	/*
        final HttpResponse resp;
        final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(PARAM_USERNAME, username));
        params.add(new BasicNameValuePair(PARAM_PASSWORD, password));
        HttpEntity entity = null;
        try {
            entity = new UrlEncodedFormEntity(params);
        } catch (final UnsupportedEncodingException e) {
            // this should never happen.
            throw new AssertionError(e);
        }
        final HttpPost post = new HttpPost(AUTH_URI);
        post.addHeader(entity.getContentType());
        post.setEntity(entity);
        maybeCreateHttpClient();
        try {
            resp = mHttpClient.execute(post);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Successful authentication");
                }
                
                Log.d( TAG, "ContentType = " + resp.getEntity().getContentType().toString() );
                
                BufferedReader br = new BufferedReader( new InputStreamReader( resp.getEntity().getContent()));
                String lineOfText = br.readLine();
                StringBuffer jsonBuffer = new StringBuffer();
                while( lineOfText != null ) {
                	jsonBuffer.append( lineOfText );
                	lineOfText = br.readLine();
                	
                }
                br.close();
                
                try {
                	JSONObject json = new JSONObject( jsonBuffer.toString() );
                	Log.d( TAG, "JSON = " + json.toString() );
                	Log.d( TAG, "CFID = " + json.getString( "cfid" ));
                	sendResult(true, handler, context, json);
                } catch( JSONException jsx ) {
                	sendResult(false, handler, context, null);
                }
                
                
                
                
                return true;
            } else {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Error authenticating" + resp.getStatusLine());
                }
                sendResult(false, handler, context, null);
                return false;
            }
        } catch (final IOException e) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "IOException when getting authtoken", e);
            }
            sendResult(false, handler, context, null );
            return false;
        } finally {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "getAuthtoken completing");
            }
        }
        */
    }

    /**
     * Sends the authentication response from server back to the caller main UI
     * thread through its handler.
     * 
     * @param result The boolean holding authentication result
     * @param handler The main UI thread's handler instance.
     * @param context The caller Activity's context.
     */
    private static void sendResult(final UserAccount userAccount, final Handler handler,
        final Context context ) {
        if (handler == null || context == null) {
            return;
        }
        handler.post(new Runnable() {
            public void run() {
            	
            	/*
            	UserAccount userAccount = new UserAccount( null, null, null );;
            	JSONObject _json = json;
            	if( json != null ) {
            		try { 
            			userAccount = new UserAccount( json.getString( "cfid" ), json.getString( "firstName"), json.getString( "lastName"));
            		} catch( JSONException jsx ) {
            		}
            	} 
            	*/
            	
                ((AuthenticatorActivity) context).onAuthenticationResult( userAccount );
            }
        });
    }

    /**
     * Attempts to authenticate the user credentials on the server.
     * 
     * @param username The user's username
     * @param password The user's password to be authenticated
     * @param handler The main UI thread's handler instance.
     * @param context The caller Activity's context
     * @return Thread The thread on which the network mOperations are executed.
     */
    public static Thread attemptAuth(final String username, final String password,
        final Handler handler, final Context context) {

        final Runnable runnable = new Runnable() {
            public void run() {
                authenticate(username, password, handler, context);
            }
        };
        // run on background thread.
        return NetworkUtilities.performOnBackgroundThread(runnable);
    }

 
}
