
package com.fsck.k9;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import android.content.Context;
import timber.log.Timber;

import com.fsck.k9.mail.store.RemoteStore;
import com.fsck.k9.mailstore.LocalStore;
import com.fsck.k9.preferences.StorageEditor;
import com.fsck.k9.preferences.Storage;


public class Preferences {

    private static Preferences preferences;

    public static synchronized Preferences getPreferences(Context context) {
        Context appContext = context.getApplicationContext();
        if (preferences == null) {
            preferences = new Preferences(appContext);
        }
        return preferences;
    }


    private Storage mStorage;
    private Map<String, Account> accounts = null;
    private List<Account> accountsInOrder = null;
    private Account newAccount;
    private Context mContext;

    private Preferences(Context context) {
        mStorage = Storage.getStorage(context);
        mContext = context;
        if (mStorage.isEmpty()) {
            Timber.i("Preferences storage is zero-size, importing from Android-style preferences");
            StorageEditor editor = mStorage.edit();
            editor.copy(context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE));
            editor.commit();
        }
    }

    public synchronized void loadAccounts() {
        accounts = new HashMap<String, Account>();
        accountsInOrder = new LinkedList<Account>();
        String accountUuids = getStorage().getString("accountUuids", null);
        if ((accountUuids != null) && (accountUuids.length() != 0)) {
            String[] uuids = accountUuids.split(",");
            for (String uuid : uuids) {
                Account newAccount = new Account(this, uuid);
                accounts.put(uuid, newAccount);
                accountsInOrder.add(newAccount);
            }
        }
        if ((newAccount != null) && newAccount.getAccountNumber() != -1) {
            accounts.put(newAccount.getUuid(), newAccount);
            if (!accountsInOrder.contains(newAccount)) {
                accountsInOrder.add(newAccount);
            }
            newAccount = null;
        }
    }

    /**
     * Returns an array of the accounts on the system. If no accounts are
     * registered the method returns an empty array.
     *
     * @return all accounts
     */
    public synchronized List<Account> getAccounts() {
        if (accounts == null) {
            loadAccounts();
        }

        return Collections.unmodifiableList(new ArrayList<Account>(accountsInOrder));
    }

    /**
     * Returns an array of the accounts on the system. If no accounts are
     * registered the method returns an empty array.
     *
     * @return all accounts with {@link Account#isAvailable(Context)}
     */
    public synchronized Collection<Account> getAvailableAccounts() {
        List<Account> allAccounts = getAccounts();
        Collection<Account> retval = new ArrayList<Account>(accounts.size());
        for (Account account : allAccounts) {
            if (account.isEnabled() && account.isAvailable(mContext)) {
                retval.add(account);
            }
        }

        return retval;
    }

    public synchronized Account getAccount(String uuid) {
        if (accounts == null) {
            loadAccounts();
        }
        Account account = accounts.get(uuid);

        return account;
    }

    public synchronized Account newAccount() {
        newAccount = new Account(mContext);
        accounts.put(newAccount.getUuid(), newAccount);
        accountsInOrder.add(newAccount);

        return newAccount;
    }

    public synchronized void deleteAccount(Account account) {
        if (accounts != null) {
            accounts.remove(account.getUuid());
        }
        if (accountsInOrder != null) {
            accountsInOrder.remove(account);
        }

        try {
            RemoteStore.removeInstance(account);
        } catch (Exception e) {
            Timber.e(e, "Failed to reset remote store for account %s", account.getUuid());
        }
        LocalStore.removeAccount(account);

        account.delete(this);

        if (newAccount == account) {
            newAccount = null;
        }
    }

    /**
     * Returns the Account marked as default. If no account is marked as default
     * the first account in the list is marked as default and then returned. If
     * there are no accounts on the system the method returns null.
     */
    public Account getDefaultAccount() {
        String defaultAccountUuid = getStorage().getString("defaultAccountUuid", null);
        Account defaultAccount = getAccount(defaultAccountUuid);

        if (defaultAccount == null) {
            Collection<Account> accounts = getAvailableAccounts();
            if (!accounts.isEmpty()) {
                defaultAccount = accounts.iterator().next();
                setDefaultAccount(defaultAccount);
            }
        }

        return defaultAccount;
    }

    public void setDefaultAccount(Account account) {
        getStorage().edit().putString("defaultAccountUuid", account.getUuid()).commit();
    }

    public Storage getStorage() {
        return mStorage;
    }

    public static <T extends Enum<T>> T getEnumStringPref(Storage storage, String key, T defaultEnum) {
        String stringPref = storage.getString(key, null);

        if (stringPref == null) {
            return defaultEnum;
        } else {
            try {
                return Enum.valueOf(defaultEnum.getDeclaringClass(), stringPref);
            } catch (IllegalArgumentException ex) {
                Timber.w(ex, "Unable to convert preference key [%s] value [%s] to enum of type %s",
                        key, stringPref, defaultEnum.getDeclaringClass());

                return defaultEnum;
            }
        }
    }
}

@@ -803,18 +803,17 @@
 Storage 
-mS
+s
 torage;%0A
@@ -964,18 +964,17 @@
 Context 
-mC
+c
 ontext;%0A
@@ -1025,18 +1025,17 @@
         
-mS
+s
 torage =
@@ -1072,18 +1072,22 @@
         
-mC
+this.c
 ontext =
@@ -1108,18 +1108,17 @@
     if (
-mS
+s
 torage.i
@@ -1264,18 +1264,17 @@
 ditor = 
-mS
+s
 torage.e
@@ -1500,31 +1500,16 @@
 HashMap%3C
-String, Account
 %3E();%0A   
@@ -1546,23 +1546,16 @@
 kedList%3C
-Account
 %3E();%0A   
@@ -2630,39 +2630,32 @@
 t(new ArrayList%3C
-Account
 %3E(accountsInOrde
@@ -3057,23 +3057,16 @@
 rayList%3C
-Account
 %3E(accoun
@@ -3182,18 +3182,17 @@
 ailable(
-mC
+c
 ontext))
@@ -3417,54 +3417,8 @@
    %7D
-%0A        Account account = accounts.get(uuid);
 %0A%0A  
@@ -3433,24 +3433,35 @@
 turn account
+s.get(uuid)
 ;%0A    %7D%0A%0A   
@@ -3541,10 +3541,9 @@
 unt(
-mC
+c
 onte
@@ -5239,18 +5239,17 @@
  return 
-mS
+s
 torage;%0A
@@ -5255,31 +5255,24 @@
 %0A    %7D%0A%0A    
-public 
 static %3CT ex

clean up Preferences