package cri.sanity;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
// tool class of application preferences
public final class P
{
//---- public api
public static final Map<String,Object> getDefaults() {
if(defs != null) return defs;
defs = new HashMap<String,Object>();
final Object[] list = K.getDefaults();
final int n = list.length;
for(int i=0; i<n; i+=2)
defs.put((String)list[i], list[i+1]);
return defs;
}
public static final void setDefaults() {
final Map<String,?> bakMap = bakMap();
A.edit().clear();
A.putAll(getDefaults()).putAll(bakMap);
setVer();
}
public static final void setDef(String ... keys) { for(String k : keys) setDef(k); }
public static final void setDef(String key) {
final Object val = defs.get(key);
if(val != null) A.put(key, val);
}
public static final void setDefIfNew(String ... keys) { for(String k : keys) setDefIfNew(k); }
public static final void setDefIfNew(String key) { if(!A.has(key)) setDef(key); }
public static final void renameBool(String dst, String old) {
if(A.has(old)) A.put(dst, A.is(old)).del(old);
else setDefIfNew(dst);
}
public static final boolean backupExists() {
final String dir = A.sdcardDir();
if(dir == null) return false;
return new File(dir, Conf.BACKUP_FN).exists();
}
public static final String[] filterSections() {
final Object[] shortcuts = PrefGroups.filterShortcuts();
final int row = PrefGroups.SHORTCUT_FILTER_ROW;
final int n = shortcuts.length / row;
final String[] filters = new String[n];
for(int i=0; i<n; i+=row)
filters[i] = (String)shortcuts[i*row + 2];
return filters;
}
public static final String[] intLabels() {
Set<String> set = PrefGroups.intLabVals().keySet();
String[] vol = PrefGroups.volumes();
String[] all = new String[set.size() + vol.length];
int i = 0;
for(String k : set) all[i++] = k;
for(String k : vol) all[i++] = k;
return all;
}
public static final Map<String,Object> skipKeysMap() {
Map<String,Object> map = new HashMap<String,Object>();
for(String k : PrefGroups.skipKeys()) map.put(k, null);
return map;
}
// backup all preferences to file, using one text line for each preference (key/value pair): key=(ClassName)value
public static final boolean backup() {
final String dir = A.sdcardDir();
if(dir == null) return false;
return backup(dir+'/'+Conf.BACKUP_FN);
}
public static final boolean backup(String fn) {
try {
BufferedWriter out = new BufferedWriter(new FileWriter(fn, false));
final Map<String,?> skipMap = skipKeysMap();
final Map<String,?> map = A.prefs().getAll();
final String[] keys = new String[map.size()];
map.keySet().toArray(keys);
Arrays.sort(keys);
for(String k : keys) {
if(skipMap.containsKey(k)) continue;
final Object v = map.get(k);
final String c = v.getClass().getName();
out.write(k+"=("+c.substring(c.lastIndexOf('.')+1)+')'+v+'\n');
}
out.close();
return true;
} catch(IOException e) {
return false;
}
}
// restore all preferences from file, using one text line for each preference (key/value pair): key=(ClassName)value
public static final boolean restore() {
final String dir = A.sdcardDir();
if(dir == null) return false;
return restore(dir+'/'+Conf.BACKUP_FN);
}
public static final boolean restore(String fn) {
final Map<String,?> loadMap = load(fn);
if(loadMap == null) return false;
final Map<String,?> bakMap = bakMap();
A.edit().clear();
A.putAll(loadMap).putAll(bakMap).commit();
upgrade();
return true;
}
public static final Map<String,?> load(String fn) {
Map<String,Object> m = new HashMap<String,Object>();
boolean read = false;
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(fn), 8192);
for(;;) {
final String line = in.readLine();
if(line.length() <= 0) continue;
int q, p = line.indexOf('=');
if(p <= 0) continue;
final String key = line.substring(0,p).trim();
final String elm = line.substring(p+1).trim();
if(key.length()<=0 || elm.length()<=0) continue;
p = elm.indexOf('(') + 1;
q = elm.indexOf(')', p+1) + 1;
final String cls = elm.substring(p, q-p);
final String val = elm.substring(q).trim();
if( cls.equals("String" )) m.put(key, val);
else if(cls.equals("Boolean")) m.put(key, Boolean.parseBoolean(val));
else if(cls.equals("Integer")) m.put(key, Integer.parseInt(val));
else if(cls.equals("Float" )) m.put(key, Float.parseFloat(val));
else if(cls.equals("Long" )) m.put(key, Long.parseLong(val));
else continue;
read = true;
}
} catch(Exception e) {
try { if(in != null) in.close(); } catch(Exception e2) {}
return read? m : null;
}
}
public static final void removeFilters() {
for(String k : A.prefs().getAll().keySet()) {
if(!k.startsWith("filter_")) continue;
if(k.startsWith("filter_enable_")) continue;
if(k.contains("_count_")) A.put(k, 0);
else A.del(k);
}
A.commit();
}
public static final boolean upgrade() {
final int ver = verSaved();
if(A.verCode() == ver) return false;
upgrade(ver);
return true;
}
//---- private api
private static Map<String,Object> bakMap() {
final String[] skipKeys = PrefGroups.skipKeys();
final Map<String,Object> bakMap = new HashMap<String,Object>(skipKeys.length);
for(String k : skipKeys) {
final Object v = A.get(k);
if(v != null) bakMap.put(k, v);
}
return bakMap;
}
private static void upgrade(int oldVer) {
if(oldVer < 17000)
setDefaults();
else {
final Map<String,Object> def = getDefaults();
K.upgrade(oldVer);
A.commit();
for(String k : def.keySet())
if(!A.has(k)) A.put(k, def.get(k));
//A.commit();
//setWrapKeys();
setVer();
}
}
private static int verSaved() {
try {
return A.geti(K.VER);
} catch(Exception e) { try {
final int ver = (int)(Float.parseFloat(A.gets(K.VER)) * 10000f);
final int b = A.geti("beta");
return b<1? ver : ver-100+b;
} catch(Exception e2) {
return 0;
}}
}
private static void setVer() { A.putc(K.VER, A.verCode()); }
private static Map<String,Object> defs;
}