package com.vaguehope.onosendai.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONException;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
import com.vaguehope.onosendai.util.ArrayHelper;
import com.vaguehope.onosendai.util.LogWrapper;
import com.vaguehope.onosendai.util.StringHelper;
public class Prefs {
private static final String ID_SEP = ":";
private static final String KEY_ACCOUNT_IDS = "account_ids";
private static final String KEY_ACCOUNT_PREFIX = "account_";
private static final String KEY_COLUMN_IDS = "column_ids";
private static final String KEY_COLUMN_PREFIX = "column_";
private static final String KEY_FILTER_IDS = "filter_ids";
private static final String KEY_FILTER_PREFIX = "filter_";
private static final LogWrapper LOG = new LogWrapper("PRF");
private final SharedPreferences sharedPreferences;
public Prefs (final Context context) {
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}
public Prefs (final PreferenceManager preferenceManager) {
this.sharedPreferences = preferenceManager.getSharedPreferences();
}
public SharedPreferences getSharedPreferences () {
return this.sharedPreferences;
}
public boolean isConfigured () {
return readAccountIds().size() > 0;
}
public void writeOver (final Collection<Account> accounts, final Collection<Column> columns) throws JSONException {
for (final String id : readColumnIdsStr()) {
deleteColumn(id);
}
for (final String id : readAccountIds()) {
deleteAccount(id);
}
for (final Account account : accounts) {
writeNewAccount(account);
}
for (final Column column : columns) {
writeNewColumn(column);
}
}
public Config asConfig () throws JSONException {
return new Config(readAccounts(), readColumns());
}
public String getNextAccountId () {
return nextId(readAccountIds(), KEY_ACCOUNT_PREFIX);
}
public List<String> readAccountIds () {
return readIds(KEY_ACCOUNT_IDS);
}
public Collection<Account> readAccounts () throws JSONException {
final Collection<Account> ret = new ArrayList<Account>();
for (final String id : readAccountIds()) {
ret.add(readAccount(id));
}
return ret;
}
public Account readAccount (final String id) throws JSONException {
if (StringHelper.isEmpty(id)) return null;
final String raw = this.sharedPreferences.getString(id, null);
if (raw == null) return null;
return Account.parseJson(raw);
}
public void writeNewAccount (final Account account) throws JSONException {
final String id = account.getId();
if (id == null || id.isEmpty()) throw new IllegalArgumentException("Account has no ID.");
final String json = account.toJson().toString();
final String idsS = appendId(readAccountIds(), id);
final Editor e = this.sharedPreferences.edit();
e.putString(id, json);
e.putString(KEY_ACCOUNT_IDS, idsS);
e.commit();
LOG.i("Wrote new account %s.", id);
}
public void updateExistingAccount (final Account account) throws JSONException {
final String id = account.getId();
if (id == null || id.isEmpty()) throw new IllegalArgumentException("Account has no ID.");
final String json = account.toJson().toString();
final Editor e = this.sharedPreferences.edit();
e.putString(id, json);
e.commit();
LOG.i("Updated account %s.", id);
}
public void deleteAccount (final Account account) {
deleteAccount(account.getId());
}
public void deleteAccount (final String id) {
if (id == null || id.isEmpty()) throw new IllegalArgumentException("Account has no ID.");
final List<String> ids = new ArrayList<String>(readAccountIds());
if (!ids.remove(id)) throw new IllegalStateException("Tried to delete account '" + id + "' that does not exist in '" + ids + "'.");
final String idsS = ArrayHelper.join(ids, ID_SEP);
final Editor e = this.sharedPreferences.edit();
e.putString(KEY_ACCOUNT_IDS, idsS);
e.remove(id);
e.commit();
}
public static String makeColumnId (final int id) {
return KEY_COLUMN_PREFIX + id;
}
private static int parseColumnId (final String id) {
if (!id.startsWith(KEY_COLUMN_PREFIX)) throw new IllegalArgumentException("Column id '" + id + "' does not start with '" + KEY_COLUMN_PREFIX + "'.");
return Integer.parseInt(id.substring(KEY_COLUMN_PREFIX.length()));
}
public int getNextColumnId () {
return parseColumnId(nextId(readColumnIdsStr(), KEY_COLUMN_PREFIX));
}
public List<Integer> readColumnIds () {
final List<Integer> ret = new ArrayList<Integer>();
for (final String id : readColumnIdsStr()) {
ret.add(parseColumnId(id));
}
return ret;
}
private List<String> readColumnIdsStr () {
return readIds(KEY_COLUMN_IDS);
}
/**
* 0 based.
*/
public int readColumnPosition (final int id) {
return readColumnPosition(makeColumnId(id));
}
private int readColumnPosition (final String id) {
return readColumnIdsStr().indexOf(id);
}
public List<Column> readColumns () throws JSONException {
final List<Column> ret = new ArrayList<Column>();
for (final String id : readColumnIdsStr()) {
ret.add(readColumn(id));
}
return ret;
}
public Map<Integer, Column> readColumnsAsMap () throws JSONException {
final Map<Integer, Column> map = new LinkedHashMap<Integer, Column>();
for (final Column col : readColumns()) {
map.put(Integer.valueOf(col.getId()), col);
}
return map;
}
public Column readColumn (final int id) throws JSONException {
return readColumn(makeColumnId(id));
}
private Column readColumn (final String id) throws JSONException {
final String raw = this.sharedPreferences.getString(id, null);
if (raw == null) return null;
return Column.parseJson(raw);
}
public void writeNewColumn (final Column column) throws JSONException {
final String id = makeColumnId(column.getId());
final String json = column.toJson().toString();
final String idsS = appendId(readColumnIdsStr(), id);
final Editor e = this.sharedPreferences.edit();
e.putString(id, json);
e.putString(KEY_COLUMN_IDS, idsS);
e.commit();
}
public void writeUpdatedColumn (final Column column) throws JSONException {
final String id = makeColumnId(column.getId());
final String json = column.toJson().toString();
final Editor e = this.sharedPreferences.edit();
e.putString(id, json);
e.commit();
}
public void moveColumnToPosition (final int id, final int position) {
moveColumnToPosition(makeColumnId(id), position);
}
private void moveColumnToPosition (final String id, final int position) {
final List<String> ids = readColumnIdsStr();
if (ids.indexOf(id) == position) return; // Already in that position.
if (position < 0 || position >= ids.size()) throw new IllegalArgumentException("Position '" + position + "' is out of bounds.");
final List<String> newIds = new ArrayList<String>(ids);
if (!newIds.remove(id)) throw new IllegalArgumentException("ID '" + id + "' not found.");
newIds.add(position, id);
final String idsS = ArrayHelper.join(newIds, ID_SEP);
final Editor e = this.sharedPreferences.edit();
e.putString(KEY_COLUMN_IDS, idsS);
e.commit();
}
public void deleteColumn (final Column column) {
deleteColumn(makeColumnId(column.getId()));
}
private void deleteColumn (final String id) {
final List<String> ids = new ArrayList<String>(readColumnIdsStr());
if (!ids.remove(id)) throw new IllegalStateException("Tried to delete column '" + id + "' that does not exist in '" + ids + "'.");
final String idsS = ArrayHelper.join(ids, ID_SEP);
final Editor e = this.sharedPreferences.edit();
e.putString(KEY_COLUMN_IDS, idsS);
e.remove(id);
e.commit();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public String getNextFilterId () {
return nextIdHighest(readFilterIds(), KEY_FILTER_PREFIX);
}
public List<String> readFilterIds () {
return readIds(KEY_FILTER_IDS);
}
public Collection<String> readFilters () {
final Collection<String> ret = new ArrayList<String>();
for (final String id : readFilterIds()) {
ret.add(readFilter(id));
}
return ret;
}
public String readFilter (final String id) {
if (StringHelper.isEmpty(id)) return null;
return this.sharedPreferences.getString(id, null);
}
public void writeFilter (final String id, final String filter) {
if (id == null || id.isEmpty()) throw new IllegalArgumentException("Filter ID missing.");
final String idsS = appendId(readFilterIds(), id);
final Editor e = this.sharedPreferences.edit();
e.putString(id, filter);
e.putString(KEY_FILTER_IDS, idsS);
e.commit();
LOG.i("Wrote new filter %s: %s.", id, filter);
}
public void deleteFilter (final String id) {
if (id == null || id.isEmpty()) throw new IllegalArgumentException("Filter ID missing.");
final List<String> ids = new ArrayList<String>(readFilterIds());
if (!ids.remove(id)) throw new IllegalStateException("Tried to delete filter '" + id + "' that does not exist in '" + ids + "'.");
final String idsS = ArrayHelper.join(ids, ID_SEP);
final Editor e = this.sharedPreferences.edit();
e.putString(KEY_FILTER_IDS, idsS);
e.remove(id);
e.commit();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
private static String nextId (final List<String> existingIds, final String prefix) {
int x = 1;
while (true) {
final String id = prefix + x;
if (!existingIds.contains(id)) return id;
x += 1;
}
}
private static String nextIdHighest (final List<String> existingIds, final String prefix) {
int x = 1;
for (String exId : existingIds) {
x = Math.max(x, Integer.parseInt(exId.substring(prefix.length())));
}
return prefix + (x + 1);
}
private List<String> readIds (final String key) {
final String ids = this.sharedPreferences.getString(key, null);
if (ids == null || ids.length() < 1) return Collections.emptyList();
return Arrays.asList(ids.split(ID_SEP));
}
private static String appendId (final List<String> existingIds, final String id) {
final List<String> ids = new ArrayList<String>(existingIds);
ids.add(id);
return ArrayHelper.join(ids, ID_SEP);
}
}