/**
 * Firebase Java Simple Login Library
 *
 * Copyright 2013 Firebase - All Rights Reserved https://www.firebase.com
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binaryform must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Firebase
 *
 */
package com.firebase.simplelogin;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import com.firebase.client.DataSnapshot;
import com.firebase.client.Firebase;
import com.firebase.client.Firebase.AuthListener;
import com.firebase.client.FirebaseError;
import com.firebase.client.ValueEventListener;
import com.firebase.simplelogin.enums.FirebaseSimpleLoginErrorCode;
import com.firebase.simplelogin.enums.Provider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


/**
 * Firebase Java Simple Login Library.
 *
 * Entry point for the Firebase simple login library.
 *
 * Attach an event listener to the .info/authenticated location to get notifications on changes in authentication state.
 *
 * <pre><code>
 * Firebase f = new Firebase("https://example.firebaseio.com/");
 * f.child(".info/authenticated").addValueEventListener(new ValueEventListener() {
 *  &#064;Override
 *  public void onDataChange(DataSnapshot arg0) {
 *    System.out.println("auth!: " + arg0.getValue());
 *  }
 *
 *  &#064;Override
 *  public void onCancelled() {
 *  }
 * });
 * </code></pre>
 *
 * Use the checkAuthStatus() method to retrieve the FirebaseSimpleLoginUser object of the logged in user.
 *
 * <pre><code>
 * SimpleLogin simpleLogin = new SimpleLogin(f, this);
 * final SimpleLoginAuthenticatedHandler simpleLoginAuthenticatedHandler = new SimpleLoginAuthenticatedHandler() {
 *  &#064;Override
 *  public void authenticated(FirebaseSimpleLoginError error, FirebaseSimpleLoginUser user) {
 *    System.out.println("Error: " + error);
 *    System.out.println("User: " + user);
 *    System.out.println("3rdP: " + user.getThirdPartyUserData());
 *  }
 * };
 * simpleLogin.checkAuthStatus(simpleLoginAuthenticatedHandler);
 * </code></pre>
 *
 * @author Firebase
 *
 */
public class SimpleLogin {

  private final Firebase ref;
  private final String namespace;
  private final String apiHost;
  private final Context androidContext;
  private final SimpleLoginOptions options;

  /**
   * Simple Login constructor.
   *
   * @param ref Firebase reference against which to login.
   */
  public SimpleLogin(Firebase ref) {
    this(ref, null);
  }

  /**
   * Simple Login constructor; pass an Activity, Context, or Service to enable saving of user tokens between app launches.
   *
   * @param ref Firebase reference against which to login.
   * @param context Android context used to save tokens.
   */
  public SimpleLogin(Firebase ref, Context context) {
    this(ref, Constants.FIREBASE_AUTH_DEFAULT_API_HOST, context, new SimpleLoginOptions());
  }

  /**
   * Simple Login constructor; pass an Activity, Context, or Service to enable saving of user tokens between app launches.
   * Also, include
   *
   * @param ref Firebase reference against which to login.
   * @param context Android context used to save tokens.
   * @param options SimpleLoginOptions instance for advanced configuration.
   */
  public SimpleLogin(Firebase ref, Context context, SimpleLoginOptions options) {
   this(ref, Constants.FIREBASE_AUTH_DEFAULT_API_HOST, context, options);
  }

  private SimpleLogin(Firebase ref, String apiHost, Context context, SimpleLoginOptions options) {
    super();
    this.ref = ref;
    this.apiHost = apiHost;
    this.namespace = FirebaseUtils.namespaceFromRef(ref);
    this.androidContext = context;
    this.options = options;
  }

  /**
   * Logout the user.
   */
  public void logout() {
    this.ref.unauth();
    clearCredentials();
  }

  /**
   * The semver version for this build of the Firebase simple login client.
   *
   * @return Returns the semver
   */
  public static String getSdkVersion() {
    return Constants.FIREBASE_AUTH_SEMVER;
  }

  /**
   * Check the authentication status. If there is a previously signed in user, it will reauthenticate that user.
   *
   * @param handler Handler for asynchronous events.
   */
  public void checkAuthStatus(SimpleLoginAuthenticatedHandler handler) {
    if(androidContext != null) {
      SharedPreferences sharedPreferences = androidContext.getSharedPreferences(Constants.FIREBASE_ANDROID_SHARED_PREFERENCE, Context.MODE_PRIVATE);
      String jsonTokenData = sharedPreferences.getString("jsonTokenData", null);
      if(jsonTokenData != null) {
        try {
          JSONObject jsonObject = new JSONObject(jsonTokenData);
          attemptAuthWithData(jsonObject, handler);
        }
        catch (JSONException e) {
          handler.authenticated(null, null);
        }
      }
      else {
        handler.authenticated(null, null);
      }
    }
    else {
      handler.authenticated(null, null);
    }
  }

  private void attemptAuthWithData(JSONObject data, final SimpleLoginAuthenticatedHandler handler) {
    try {
      String token = data.has("token") ? data.getString("token") : null;
      JSONObject userData = data.has("userData") ? data.getJSONObject("userData") : null;
      if(token != null && userData != null) {
        Provider provider = FirebaseUtils.providerForString(userData.getString("provider"));
        if(provider != Provider.INVALID) {
          // XXX send account for provider in objc
          attemptAuthWithToken(token, provider, userData, handler);
        }
        else {
          clearCredentials();
          handler.authenticated(null, null);
        }
      }
      else {
        handler.authenticated(FirebaseSimpleLoginError.errorFromResponse(null), null);
      }
    }
    catch (JSONException e) {
      e.printStackTrace();
      handler.authenticated(FirebaseSimpleLoginError.errorFromResponse(null), null);
    }
  }

  private void clearCredentials() {
    if(androidContext != null) {
      SharedPreferences sharedPreferences = androidContext.getSharedPreferences(Constants.FIREBASE_ANDROID_SHARED_PREFERENCE, Context.MODE_PRIVATE);
      Editor editor = sharedPreferences.edit();
      editor.clear();
      editor.commit();
    }
  }

    /**
     * Login anonymously.
     *
     * @param completionHandler Handler for asynchronous events.
     */
    public void loginAnonymously(final SimpleLoginAuthenticatedHandler completionHandler) {
      HashMap<String, String> data = new HashMap<String, String>();
      makeRequest(Constants.FIREBASE_AUTH_ANONYMOUS_PATH, data, new RequestHandler() {

        public void handle(FirebaseSimpleLoginError error, JSONObject data) {
          if (error != null) {
            completionHandler.authenticated(error, null);
          }
          else {
            try {
              String token = data.has("token") ? data.getString("token") : null;
              if (token == null) {
                JSONObject errorDetails = data.has("error") ? data.getJSONObject("error") : null;
                FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(errorDetails);
                completionHandler.authenticated(theError, null);
              }
              else {
                JSONObject userData = data.has("user") ? data.getJSONObject("user") : null;
                if (userData == null) {
                  FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
                  completionHandler.authenticated(theError, null);
                }
                else {
                  attemptAuthWithToken(token, Provider.ANONYMOUS, userData, completionHandler);
                }
              }
            }
            catch (JSONException e) {
              e.printStackTrace();
              FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
              completionHandler.authenticated(theError, null);
            }
          }
        }

      });
    }

  /**
   * Login an existing Firebase "email/password" user.
   *
   * @param email Email address of user.
   * @param password Password for user.
   * @param completionHandler Handler for asynchronous events.
   */
  public void loginWithEmail(String email, String password, final SimpleLoginAuthenticatedHandler completionHandler) {
    if (!Validation.isValidEmail(email)) {
      handleInvalidEmail(completionHandler);
    }
    else if (!Validation.isValidPassword(password)) {
      handleInvalidPassword(completionHandler);
    }
    else {
      HashMap<String, String> data = new HashMap<String, String>();
      data.put("email", email);
      data.put("password", password);

      makeRequest(Constants.FIREBASE_AUTH_PASSWORD_PATH, data, new RequestHandler() {
        public void handle(FirebaseSimpleLoginError error, JSONObject data) {
          if (error != null) {
            completionHandler.authenticated(error, null);
          }
          else {
            try {
              String token = data.has("token") ? data.getString("token") : null;
              if (token == null) {
                JSONObject errorDetails = data.has("error") ? data.getJSONObject("error") : null;
                FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(errorDetails);
                completionHandler.authenticated(theError, null);
              }
              else {
                JSONObject userData = data.has("user") ? data.getJSONObject("user") : null;
                if (userData == null) {
                  FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
                  completionHandler.authenticated(theError, null);
                }
                else {
                  attemptAuthWithToken(token, Provider.PASSWORD, userData, completionHandler);
                }
              }
            }
            catch (JSONException e) {
              e.printStackTrace();
              FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
              completionHandler.authenticated(theError, null);
            }
          }
        }

      });
    }
  }

  private void attemptAuthWithToken(final String token, final Provider provider, final JSONObject userData, final SimpleLoginAuthenticatedHandler completionHandler) {
    this.ref.auth(token, new AuthListener() {

      public void onAuthSuccess(Object authData) {
        FirebaseSimpleLoginUser user = saveSession(token, provider, userData);
        if (user != null) {
          final Firebase authRef = ref.getRoot().child(".info/authenticated");
          final ValueEventListener authValueEventListener = new ValueEventListener() {
            public void onDataChange(DataSnapshot snapshot) {
              Object value = snapshot.getValue();
              if (value instanceof Boolean) {
                Boolean boolVal = (Boolean) value;
                if (!boolVal.booleanValue()) {
                  clearCredentials();
                  authRef.removeEventListener(this); // can't refer to authValueEventListener here
                }
              }
            }
            public void onCancelled(FirebaseError error) {}
          };
          authRef.addValueEventListener(authValueEventListener);
          completionHandler.authenticated(null, user);
        }
        else {
          completionHandler.authenticated(FirebaseSimpleLoginError.errorFromResponse(null), null);
        }

      }

      public void onAuthRevoked(FirebaseError error) {
        clearCredentials();
        completionHandler.authenticated(FirebaseSimpleLoginError.errorFromFirebaseError(error), null);
      }

      public void onAuthError(FirebaseError error) {
        completionHandler.authenticated(FirebaseSimpleLoginError.errorFromFirebaseError(error), null);
      }
    });
  }

  private FirebaseSimpleLoginUser saveSession(String token, Provider provider, JSONObject userData) {
    clearCredentials();
    FirebaseSimpleLoginUser user = null;
    try {
      String userId = userData.has("id") ? userData.getString("id") : null;
      if (userId != null) {
        if(provider == Provider.PASSWORD) {
          String email = userData.has("email") ? userData.getString("email") : null;
          boolean isTemporaryPassword = userData.has("isTemporaryPassword") ? userData.getBoolean("isTemporaryPassword") : false;
          if(email != null) {
            user = new FirebaseSimpleLoginUser(userId, userData.getString("uid"), token, email, isTemporaryPassword);
          }
        }
        else {
          user = new FirebaseSimpleLoginUser(userId, userData.getString("uid"), provider, token, FirebaseUtils.toMap(userData));
        }
      }
    }
    catch (JSONException e) {}

    // Save to shared prefs
    if(androidContext != null) {
      SharedPreferences sharedPreferences = androidContext.getSharedPreferences(Constants.FIREBASE_ANDROID_SHARED_PREFERENCE, Context.MODE_PRIVATE);
      Editor editor = sharedPreferences.edit();
      try {
        JSONObject jsonTokenData = new JSONObject();
        jsonTokenData.put("token", token);
        jsonTokenData.put("userData", userData);
        editor.putString("jsonTokenData", jsonTokenData.toString());
      }
      catch (JSONException e) {
        // TODO: log an error?
      }
      finally {
        editor.commit();
      }
    }
    return user;
  }

  /**
   * Create a Firebase "email/password" user.
   *
   * @param email Email address for user.
   * @param password Password for user.
   * @param completionHandler Handler for asynchronous events.
   */
  public void createUser(String email, String password, final SimpleLoginAuthenticatedHandler completionHandler) {
    if (!Validation.isValidEmail(email)) {
      handleInvalidEmail(completionHandler);
    }
    else if (!Validation.isValidPassword(password)) {
      handleInvalidPassword(completionHandler);
    }
    else {
      HashMap<String, String> data = new HashMap<String, String>();
      data.put("email", email);
      data.put("password", password);

      makeRequest(Constants.FIREBASE_AUTH_CREATEUSER_PATH, data, new RequestHandler() {
        public void handle(FirebaseSimpleLoginError error, JSONObject data) {
          if (error != null) {
            completionHandler.authenticated(error, null);
          }
          else {
            try {
              JSONObject errorDetails = data.has("error") ? data.getJSONObject("error") : null;
              JSONObject userData = data.has("user") ? data.getJSONObject("user") : null;
              if (errorDetails != null) {
                FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(errorDetails);
                completionHandler.authenticated(theError, null);
              }
              else if (userData == null) {
                FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
                completionHandler.authenticated(theError, null);
              }
              else {
                String userId = userData.getString("id");
                                String uid = userData.getString("uid");
                                String email = userData.getString("email");
                FirebaseSimpleLoginUser user = new FirebaseSimpleLoginUser(userId, uid, null, email, false);
                completionHandler.authenticated(null, user);
              }
            }
            catch (JSONException e) {
              e.printStackTrace();
              FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
              completionHandler.authenticated(theError, null);
            }
          }
        }
      });
    }
  }

  /**
   * Remove a Firebase "email/password" user.
   *
   * @param email Email address for user.
   * @param password Password for user.
   * @param handler Handler for asynchronous events.
   */
  public void removeUser(String email, String password, final SimpleLoginCompletionHandler handler) {
    final SimpleLoginAuthenticatedHandler authHandler = new SimpleLoginAuthenticatedHandler() {
      public void authenticated(FirebaseSimpleLoginError error, FirebaseSimpleLoginUser user) {
        handler.completed(error, false);
      }
    };

    if (!Validation.isValidEmail(email)) {
      handleInvalidEmail(authHandler);
    }
    else if (!Validation.isValidPassword(password)) {
      handleInvalidPassword(authHandler);
    }
    else {
      HashMap<String, String> data = new HashMap<String, String>();
      data.put("email", email);
      data.put("password", password);

      makeRequest(Constants.FIREBASE_AUTH_REMOVEUSER_PATH, data, new RequestHandler() {
        public void handle(FirebaseSimpleLoginError error, JSONObject data) {
          if(error != null) {
            handler.completed(error, false);
          }
          else {
            try {
              JSONObject errorDetails = data.has("error") ? data.getJSONObject("error") : null;
              if(errorDetails != null) {
                handler.completed(FirebaseSimpleLoginError.errorFromResponse(errorDetails), false);
              }
              else {
                handler.completed(null, true);
              }
            }
            catch (JSONException e) {
              e.printStackTrace();
              FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
              handler.completed(theError, false);
            }
          }
        }
      });
    }
  }

  /**
   * Change the password for a Firebase "email/password" user.
   *
   * @param email Email address for user.
   * @param oldPassword User's old password.
   * @param newPassword User's new password.
   * @param handler Handler for asynchronous events.
   */
  public void changePassword(final String email, final String oldPassword, final String newPassword, final SimpleLoginCompletionHandler handler) {
    final SimpleLoginAuthenticatedHandler authHandler = new SimpleLoginAuthenticatedHandler() {
      public void authenticated(FirebaseSimpleLoginError error, FirebaseSimpleLoginUser user) {
        handler.completed(error, false);
      }
    };

    if (!Validation.isValidEmail(email)) {
      handleInvalidEmail(authHandler);
    }
    else if (!Validation.isValidPassword(newPassword)) {
      handleInvalidPassword(authHandler);
    }
    else {
      HashMap<String, String> data = new HashMap<String, String>();
      data.put("email", email);
      data.put("oldPassword", oldPassword);
      data.put("newPassword", newPassword);

      makeRequest(Constants.FIREBASE_AUTH_CHANGEPASSWORD_PATH, data, new RequestHandler() {
        public void handle(FirebaseSimpleLoginError error, JSONObject data) {
          if(error != null) {
            handler.completed(error, false);
          }
          else {
            try {
              JSONObject errorDetails = data.has("error") ? data.getJSONObject("error") : null;
              if(errorDetails != null) {
                handler.completed(FirebaseSimpleLoginError.errorFromResponse(errorDetails), false);
              }
              else {
                handler.completed(null, true);
              }
            }
            catch (JSONException e) {
              e.printStackTrace();
              FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
              handler.completed(theError, false);
            }
          }
        }
      });
    }
  }

    /**
     * Send a password reset email for a Firebase "email/password" user.
     *
     * @param email Email address for user.
     * @param handler Handler for asynchronous events.
     */
    public void sendPasswordResetEmail(String email, final SimpleLoginCompletionHandler handler) {
      final SimpleLoginAuthenticatedHandler authHandler = new SimpleLoginAuthenticatedHandler() {
        public void authenticated(FirebaseSimpleLoginError error, FirebaseSimpleLoginUser user) {
        handler.completed(error, false);
        }
      };

      if (!Validation.isValidEmail(email)) {
        handleInvalidEmail(authHandler);
      }
      else {
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("email", email);

        makeRequest(Constants.FIREBASE_AUTH_RESETPASSWORD_PATH, data, new RequestHandler() {
          public void handle(FirebaseSimpleLoginError error, JSONObject data) {
            if(error != null) {
              handler.completed(error, false);
            }
            else {
              try {
                JSONObject errorDetails = data.has("error") ? data.getJSONObject("error") : null;
                if(errorDetails != null) {
                  handler.completed(FirebaseSimpleLoginError.errorFromResponse(errorDetails), false);
                }
                else {
                  handler.completed(null, true);
                }
              }
              catch (JSONException e) {
                e.printStackTrace();
                FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
                handler.completed(theError, false);
              }
            }
          }
        });
      }
    }

  private void handleInvalidEmail(final SimpleLoginAuthenticatedHandler userHandler) {
    new Handler().post(new Runnable() {
      public void run() {
        if(userHandler != null) {
          userHandler.authenticated(FirebaseSimpleLoginError.errorFromCode(FirebaseSimpleLoginErrorCode.InvalidEmail), null);
        }
      }
    });
  }

  private void handleInvalidPassword(final SimpleLoginAuthenticatedHandler userHandler) {
    new Handler().post(new Runnable() {
      public void run() {
        if(userHandler != null) {
          userHandler.authenticated(FirebaseSimpleLoginError.errorFromCode(FirebaseSimpleLoginErrorCode.InvalidPassword), null);
        }
      }
    });
  }

  private void handleInvalidInvalidToken(final SimpleLoginAuthenticatedHandler userHandler) {
    new Handler().post(new Runnable() {
      public void run() {
        if(userHandler != null) {
          userHandler.authenticated(FirebaseSimpleLoginError.errorFromCode(FirebaseSimpleLoginErrorCode.BadProviderToken), null);
        }
      }
    });
  }

  private void makeRequest(String urlPath, HashMap<String, String> data, final RequestHandler handler) {
    Uri.Builder b = Uri.parse(this.apiHost).buildUpon();
    b.path(urlPath);
    b.appendQueryParameter("firebase", this.namespace);
    b.appendQueryParameter("mobile", "android");
               b.appendQueryParameter("transport", "json");


    if (data != null) {
      for (Map.Entry<String, String> entry : data.entrySet()) {
        if (entry != null) {
          b.appendQueryParameter(entry.getKey(), entry.getValue());
        }
      }
    }
    new FetchTask(handler).execute(b.build().toString());
  }

  /**
   * Login to Firebase using a Facebook token. The returned FirebaseSimpleLoginUser object will contain pertinent
   * Facebook data accessible with getThirdPartyUserData().
   *
   * @param appId Facebook app id.
   * @param accessToken Access token returned by Facebook SDK.
   * @param completionHandler Handler for asynchronous events.
   */
  public void loginWithFacebook(final String appId, final String accessToken, final SimpleLoginAuthenticatedHandler completionHandler) {
    if(appId == null || accessToken == null) {
      handleInvalidInvalidToken(completionHandler);
    }
    else {
      HashMap<String, String> data = new HashMap<String, String>();
      data.put("access_token", accessToken);

            loginWithToken(Constants.FIREBASE_AUTH_FACEBOOK_PATH, Provider.FACEBOOK, data, completionHandler);
        }
  }

    /**
     * Login to Firebase using a Google access token. The returned FirebaseSimpleLoginUser object will contain pertinent
     * Google data accessible with getThirdPartyUserData().
     *
     * @param accessToken Access token returned by Facebook SDK.
     * @param completionHandler Handler for asynchronous events.
     */
    public void loginWithGoogle(final String accessToken, final SimpleLoginAuthenticatedHandler completionHandler) {
        if(accessToken == null) {
            handleInvalidInvalidToken(completionHandler);
        }
        else {
            HashMap<String, String> data = new HashMap<String, String>();
            data.put("access_token", accessToken);

            loginWithToken(Constants.FIREBASE_AUTH_GOOGLE_PATH, Provider.GOOGLE, data, completionHandler);
        }
    }

    /**
   * Login to Firebase using a Twitter token. The returned FirebaseSimpleLoginUser object will contain pertinent
   * Twitter data accessible with getThirdPartyUserData().
   *
   * @param oauth_token Twitter oauth token.
   * @param oauth_token_secret Twitter token secret.
   * @param user_id Twitter numeric user id.
   * @param completionHandler Handler for asynchronous events.
   */
  public void loginWithTwitter(final String oauth_token, final String oauth_token_secret, final Long user_id, final SimpleLoginAuthenticatedHandler completionHandler) {
    if(oauth_token == null || oauth_token_secret == null || user_id == null) {
      handleInvalidInvalidToken(completionHandler);
    }
    else {
      HashMap<String, String> data = new HashMap<String, String>();
      data.put("oauth_token", oauth_token);
      data.put("oauth_token_secret", oauth_token_secret);
      data.put("user_id", user_id.toString());

      loginWithToken(Constants.FIREBASE_AUTH_TWITTERTOKEN_PATH, Provider.TWITTER, data, completionHandler);
    }
  }

    private void loginWithToken(final String urlPath, final Provider provider, final HashMap<String, String> data, final SimpleLoginAuthenticatedHandler completionHandler) {
      makeRequest(urlPath, data, new RequestHandler() {
        public void handle(FirebaseSimpleLoginError error, JSONObject data) {
          if (error != null) {
            completionHandler.authenticated(error, null);
          }
          else {
            try {
              String token = data.has("token") ? data.getString("token") : null;
              if (token == null) {
                JSONObject errorDetails = data.has("error") ? data.getJSONObject("error") : null;
                FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(errorDetails);
                completionHandler.authenticated(theError, null);
              }
              else {
                JSONObject userData = data.has("user") ? data.getJSONObject("user") : null;
                if (userData == null) {
                  FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
                  completionHandler.authenticated(theError, null);
                }
                else {
                  attemptAuthWithToken(token, provider, userData, completionHandler);
                }
              }
            }
            catch (JSONException e) {
              e.printStackTrace();
              FirebaseSimpleLoginError theError = FirebaseSimpleLoginError.errorFromResponse(null);
              completionHandler.authenticated(theError, null);
            }
          }
        }
      });
    }

  /**
   * FetchTask class.
   */
  class FetchTask extends AsyncTask<String, Void, JSONObject> {

    private RequestHandler handler;

    public FetchTask(RequestHandler handler) {
      super();
      this.handler = handler;
    }

    @Override
    protected JSONObject doInBackground(String... arg) {
      DefaultHttpClient httpClient = new DefaultHttpClient();
      HttpGet httpGet = new HttpGet(arg[0]);
      JSONObject result = null;
      try {
        result = httpClient.execute(httpGet, new JsonBasicResponseHandler());
      }
      catch (IOException e) {
        e.printStackTrace();
      }
      return result;
    }

    @Override
    protected void onPostExecute(JSONObject result) {
      // Method is automatically called on main thread
      super.onPostExecute(result);
      if (result == null) {
        handler.handle(FirebaseSimpleLoginError.errorFromCode(FirebaseSimpleLoginErrorCode.Unknown), null);
      }
      else {
        handler.handle(null, result);
      }
    }
  }
}