package com.rackspacecloud.android;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.TreeMap;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.rackspace.cloud.android.R;
import com.rackspace.cloud.loadbalancer.api.client.Algorithm;
import com.rackspace.cloud.loadbalancer.api.client.AlgorithmManager;
import com.rackspace.cloud.loadbalancer.api.client.Protocol;
import com.rackspace.cloud.loadbalancer.api.client.ProtocolManager;
import com.rackspace.cloud.servers.api.client.Account;
import com.rackspace.cloud.servers.api.client.CloudServersException;
import com.rackspace.cloud.servers.api.client.Flavor;
import com.rackspace.cloud.servers.api.client.FlavorManager;
import com.rackspace.cloud.servers.api.client.Image;
import com.rackspace.cloud.servers.api.client.ImageManager;
import com.rackspace.cloud.servers.api.client.http.Authentication;
//
public class ListAccountsActivity extends CloudListActivity{
private final String FILENAME = "accounts.data";
private static final String PAGE_ROOT = "/Root";
private boolean authenticating;
private ArrayList<Account> accounts;
private Intent tabViewIntent;
private ProgressDialog dialog;
private Context context;
//used to track the current asynctask
@SuppressWarnings("rawtypes")
private AsyncTask task;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
trackPageView(PAGE_ROOT);
onRestoreInstanceState(savedInstanceState);
registerForContextMenu(getListView());
context = getApplicationContext();
tabViewIntent = new Intent(this, TabViewActivity.class);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("authenticating", authenticating);
outState.putSerializable("accounts", accounts);
//need to set authenticating back to true because it is set to false
//in hideAccountDialog()
if(authenticating){
hideAccountDialog();
authenticating = true;
}
writeAccounts();
}
@SuppressWarnings("unchecked")
@Override
protected void onRestoreInstanceState(Bundle state) {
/*
* need reference to the app so you can access
* isLoggingIn
*/
if (state != null && state.containsKey("authenticating") && state.getBoolean("authenticating")) {
showAccountDialog();
} else {
hideAccountDialog();
}
if (state != null && state.containsKey("accounts")) {
accounts = (ArrayList<Account>)state.getSerializable("accounts");
if (accounts.size() == 0) {
displayNoAccountsCell();
} else {
getListView().setDividerHeight(1); // restore divider lines
setListAdapter(new AccountAdapter());
}
} else {
loadAccounts();
}
}
@Override
protected void onStart(){
super.onStart();
if(authenticating){
showAccountDialog();
}
}
@Override
protected void onStop(){
super.onStop();
if(authenticating){
hideAccountDialog();
authenticating = true;
}
}
private void loadAccounts() {
//check and see if there are any in memory
if(accounts == null){
accounts = readAccounts();
}
//if nothing was written before accounts will still be null
if(accounts == null){
accounts = new ArrayList<Account>();
}
setAccountList();
}
private void setAccountList() {
if (accounts.size() == 0) {
displayNoAccountsCell();
} else {
getListView().setDividerHeight(1); // restore divider lines
this.setListAdapter(new AccountAdapter());
}
}
private void writeAccounts(){
FileOutputStream fos;
ObjectOutputStream out = null;
try{
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
out = new ObjectOutputStream(fos);
out.writeObject(accounts);
out.flush();
out.close();
} catch (FileNotFoundException e) {
showAlert("Error", "Could not save accounts.");
e.printStackTrace();
} catch (IOException e) {
showAlert("Error", "Could not save accounts.");
e.printStackTrace();
}
}
private ArrayList<Account> readAccounts(){
FileInputStream fis;
ObjectInputStream in;
try {
fis = openFileInput(FILENAME);
in = new ObjectInputStream(fis);
@SuppressWarnings("unchecked")
ArrayList<Account> file = (ArrayList<Account>)in.readObject();
in.close();
return file;
} catch (FileNotFoundException e) {
//showAlert("Error", "Could not load accounts.");
e.printStackTrace();
return null;
} catch (StreamCorruptedException e) {
showAlert("Error", "Could not load accounts.");
e.printStackTrace();
} catch (IOException e) {
showAlert("Error", "Could not load accounts.");
e.printStackTrace();
} catch (ClassNotFoundException e) {
showAlert("Error", "Could not load accounts.");
e.printStackTrace();
}
return null;
}
private void displayNoAccountsCell() {
String a[] = new String[1];
a[0] = "No Accounts";
setListAdapter(new ArrayAdapter<String>(getApplicationContext(), R.layout.noaccountscell, R.id.no_accounts_label, a));
getListView().setTextFilterEnabled(true);
getListView().setDividerHeight(0); // hide the dividers so it won't look like a list row
getListView().setItemsCanFocus(false);
}
protected void onListItemClick(ListView l, View v, int position, long id) {
if (accounts != null && accounts.size() > 0) {
//setActivityIndicatorsVisibility(View.VISIBLE, v);
Account.setAccount(accounts.get(position));
Log.d("info", "the server is " + Account.getAccount().getAuthServerV2());
login();
}
}
public void login() {
//showActivityIndicators();
//setLoginPreferences();
new AuthenticateTask().execute((Void[]) null);
}
//setup menu for when menu button is pressed
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.accounts_list_menu, menu);
return true;
}
@Override
//in options menu, when add account is selected go to add account activity
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_account:
startActivityForResult(new Intent(this, AddAccountActivity.class), 78); // arbitrary number; never used again
return true;
case R.id.contact_rackspace:
startActivity(new Intent(this, ContactActivity.class));
return true;
case R.id.add_password:
startActivity(new Intent(this, CreatePasswordActivity.class));
return true;
}
return false;
}
//the context menu for a long press on an account
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.account_context_menu, menu);
}
//removes the selected account from account list if remove is clicked
public boolean onContextItemSelected(MenuItem item) {
if (accounts.size() == 0) {
displayNoAccountsCell();
return true;
} else {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
accounts.remove(info.position);
writeAccounts();
loadAccounts();
return true;
}
}
class AccountAdapter extends ArrayAdapter<Account> {
AccountAdapter() {
super(ListAccountsActivity.this, R.layout.listaccountcell, accounts);
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View row = inflater.inflate(R.layout.listaccountcell, parent, false);
TextView label = (TextView) row.findViewById(R.id.label);
label.setText(accounts.get(position).getUsername());
TextView sublabel = (TextView) row.findViewById(R.id.sublabel);
sublabel.setText(getAccountServer(accounts.get(position)));
ImageView icon = (ImageView) row.findViewById(R.id.account_type_icon);
icon.setImageResource(setAccountIcon(accounts.get(position)));
return row;
}
}
public String getAccountServer(Account account){
String authServer = account.getAuthServer();
if(authServer == null){
authServer = account.getAuthServerV2();
}
String result;
if(authServer.equals(Preferences.COUNTRY_UK_AUTH_SERVER) || authServer.equals(Preferences.COUNTRY_UK_AUTH_SERVER_V2)){
result = "Rackspace Cloud (UK)";
}
else if(authServer.equals(Preferences.COUNTRY_US_AUTH_SERVER) || authServer.equals(Preferences.COUNTRY_US_AUTH_SERVER_V2)){
result = "Rackspace Cloud (US)";
}
else{
result = "Custom";
//setCustomIcon();
}
return result;
}
//display rackspace logo for cloud accounts and openstack logo for others
private int setAccountIcon(Account account){
String authServer = account.getAuthServer();
if(authServer == null){
authServer = account.getAuthServerV2();
}
if(authServer.equals(Preferences.COUNTRY_UK_AUTH_SERVER)
|| authServer.equals(Preferences.COUNTRY_US_AUTH_SERVER)
|| authServer.equals(Preferences.COUNTRY_US_AUTH_SERVER_V2)
|| authServer.equals(Preferences.COUNTRY_UK_AUTH_SERVER_V2)){
return R.drawable.rackspacecloud_icon;
}
else{
return R.drawable.openstack_icon;
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 187){
hideAccountDialog();
}
if (resultCode == RESULT_OK && requestCode == 78) {
Account acc = new Account();
Bundle b = data.getBundleExtra("accountInfo");
acc.setPassword(b.getString("apiKey"));
acc.setUsername(b.getString("username"));
acc.setAuthServerV2(b.getString("server"));
Log.d("info", "the set server was " + b.getString("server"));
Log.d("info", "the server is " + acc.getAuthServerV2());
accounts.add(acc);
writeAccounts();
loadAccounts();
}
}
private void showAccountDialog() {
app.setIsLoggingIn(true);
authenticating = true;
if(dialog == null || !dialog.isShowing()){
dialog = new ProgressDialog(this);
dialog.setProgressStyle(R.style.NewDialog);
dialog.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
app.setIsLoggingIn(false);
//need to cancel the old task or we may get a double login
task.cancel(true);
hideAccountDialog();
}
});
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
dialog.show();
dialog.setContentView(new ProgressBar(this), new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
}
private void hideAccountDialog() {
if(dialog != null){
dialog.dismiss();
}
authenticating = false;
}
private class AuthenticateTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected void onPreExecute(){
Log.d("info", "Starting authenticate");
task = this;
showAccountDialog();
}
@Override
protected Boolean doInBackground(Void... arg0) {
try {
return new Boolean(Authentication.authenticate(context));
} catch (CloudServersException e) {
e.printStackTrace();
return false;
}
}
@Override
protected void onPostExecute(Boolean result) {
if (result.booleanValue()) {
//startActivity(tabViewIntent);
if(app.isLoggingIn()){
new LoadImagesTask().execute((Void[]) null);
} else {
hideAccountDialog();
}
} else {
hideAccountDialog();
if(app.isLoggingIn()){
showAlert("Login Failure", "Authentication failed. Please check your User Name and Password.");
}
}
}
}
private class LoadImagesTask extends AsyncTask<Void, Void, ArrayList<Image>> {
@Override
protected void onPreExecute(){
Log.d("info", "Starting Images");
task = this;
}
@Override
protected ArrayList<Image> doInBackground(Void... arg0) {
return (new ImageManager()).createList(true, context);
}
@Override
protected void onPostExecute(ArrayList<Image> result) {
if (result != null && result.size() > 0) {
TreeMap<String, Image> imageMap = new TreeMap<String, Image>();
for (int i = 0; i < result.size(); i++) {
Image image = result.get(i);
imageMap.put(image.getId(), image);
}
Image.setImages(imageMap);
if(app.isLoggingIn()){
new LoadProtocolsTask().execute((Void[]) null);
} else {
hideAccountDialog();
}
} else {
hideAccountDialog();
if(app.isLoggingIn()){
showAlert("Login Failure", "There was a problem loading server images. Please try again.");
}
}
}
}
private class LoadProtocolsTask extends AsyncTask<Void, Void, ArrayList<Protocol>> {
@Override
protected void onPreExecute(){
Log.d("info", "Starting protcols");
task = this;
}
@Override
protected ArrayList<Protocol> doInBackground(Void... arg0) {
return (new ProtocolManager()).createList(context);
}
@Override
protected void onPostExecute(ArrayList<Protocol> result) {
if (result != null && result.size() > 0) {
Protocol.setProtocols(result);
if(app.isLoggingIn()){
new LoadAlgorithmsTask().execute((Void[]) null);
} else {
hideAccountDialog();
}
} else {
hideAccountDialog();
if(app.isLoggingIn()){
showAlert("Login Failure", "There was a problem loading load balancer protocols. Please try again.");
}
}
}
}
private class LoadAlgorithmsTask extends AsyncTask<Void, Void, ArrayList<Algorithm>> {
protected void onPreExecute(){
Log.d("info", "Starting algorithms");
task = this;
}
@Override
protected ArrayList<Algorithm> doInBackground(Void... arg0) {
return (new AlgorithmManager()).createList(context);
}
@Override
protected void onPostExecute(ArrayList<Algorithm> result) {
if (result != null && result.size() > 0) {
Algorithm.setAlgorithms(result);
if(app.isLoggingIn()){
new LoadFlavorsTask().execute((Void[]) null);
} else {
hideAccountDialog();
}
} else {
hideAccountDialog();
if(app.isLoggingIn()){
showAlert("Login Failure", "There was a problem loading load balancer algorithms. Please try again.");
}
}
}
}
private class LoadFlavorsTask extends AsyncTask<Void, Void, ArrayList<Flavor>> {
protected void onPreExecute(){
Log.d("info", "Starting flavors");
task = this;
}
@Override
protected ArrayList<Flavor> doInBackground(Void... arg0) {
return (new FlavorManager()).createList(true, context);
}
@Override
protected void onPostExecute(ArrayList<Flavor> result) {
if (result != null && result.size() > 0) {
TreeMap<String, Flavor> flavorMap = new TreeMap<String, Flavor>();
for (int i = 0; i < result.size(); i++) {
Flavor flavor = result.get(i);
flavorMap.put(flavor.getId(), flavor);
}
Flavor.setFlavors(flavorMap);
hideAccountDialog();
if(app.isLoggingIn()){
startActivityForResult(tabViewIntent, 187);
}
} else {
hideAccountDialog();
if(app.isLoggingIn()){
showAlert("Login Failure", "There was a problem loading server flavors. Please try again.");
}
}
}
}
}