/*
* XCTrack - XContest Live Tracking client for J2ME devices
* Copyright (C) 2009 Petr Chromec <petr@xcontest.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.xcontest.xctrack.config;
import java.util.Vector;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreNotFoundException;
import javax.microedition.rms.RecordStoreNotOpenException;
import org.xcontest.live.UTF8;
import org.xcontest.xctrack.Util;
import org.xcontest.xctrack.gps.GpsDeviceInfo;
import org.xcontest.xctrack.gps.GpsDriver;
import org.xcontest.xctrack.settings.Profile;
final class Record {
int recordStoreId;
boolean isModified;
byte[] data;
}
public final class Config {
final static String VERSION = "0.2";
public static void init() {
readAll();
_lastRunVersion = getConfigVersion();
if (_lastRunVersion == null || !_lastRunVersion.equals(VERSION)) {
setConfigVersion(VERSION);
writeAll();
}
}
/**
* debug only method ... clears both cached settings and associated record store
*/
public static void clear() {
try {
RecordStore.deleteRecordStore("config");
}
catch (RecordStoreNotFoundException e) {
}
catch (RecordStoreException e) {
}
_records = new Record[KEY_MAX+1];
}
/**
*
* @return string with information of all the records in the config record store
*/
public static String inspectRecordStore() {
String out = "";
RecordStore rs = null;
try {
rs = RecordStore.openRecordStore("config",true);
RecordEnumeration re = rs.enumerateRecords(null, null, false);
while (re.hasNextElement()) {
int id = re.nextRecordId();
byte[] data = rs.getRecord(id);
out += "" + id + ": key=" + data[0] + " data=" + new String(data,1,data.length-1) + "\n";
}
rs.closeRecordStore();
}
catch (Exception e) {
out += "EXCEPTION: " + e.toString();
try {
out += " num=" + rs.getNumRecords();
}
catch (RecordStoreNotOpenException e1) {}
}
return out;
}
public static String getConfigVersion() {
return getString(KEY_CONFIG_VERSION);
}
private static void setConfigVersion(String version) {
setString(KEY_CONFIG_VERSION,version);
}
public static boolean isFirstRun() {
return _lastRunVersion == null;
}
public static boolean isDebugMode() {
return Config.getInt(KEY_DEBUG_MODE, 0) == 1;
}
public static void setDebugMode(boolean val) {
Config.setInt(KEY_DEBUG_MODE, val ? 1 : 0);
}
public static int getProtocol() {
return getInt(KEY_PROTOCOL,DEFAULT_PROTOCOL);
}
public static void setProtocol(int value) {
setInt(KEY_PROTOCOL, value);
}
public static int getHTTPPingMode() {
return getInt(KEY_HTTP_PING_MODE,DEFAULT_HTTP_PING_MODE);
}
public static void setHTTPPingMode(int value) {
setInt(KEY_HTTP_PING_MODE,value);
}
/*
public static int getHTTPPingInterval() {
return getInt(KEY_HTTP_PING_INTERVAL,DEFAULT_HTTP_PING_INTERVAL);
}
public static void setHTTPPingInterval(int value) {
setInt(KEY_HTTP_PING_INTERVAL,value);
}
*/
public static String getUDPServerHost() {
String s = getString(KEY_UDPSERVER_HOST);
if (s == null || s.equals(""))
return DEFAULT_UDP_HOST;
else
return s;
}
public static int getUDPServerPort() {
String s = getString(KEY_UDPSERVER_PORT);
if (s == null || s.equals(""))
return DEFAULT_UDP_PORT;
else
return Integer.parseInt(s);
}
public static String getWSServerUrl() {
return DEFAULT_WSSERVER_URL;
}
public static String getTCPServerHost() {
String s = getString(KEY_TCPSERVER_HOST);
if (s == null || s.equals(""))
return DEFAULT_TCP_HOST;
else
return s;
}
public static int getTCPServerPort() {
String s = getString(KEY_TCPSERVER_PORT);
if (s == null || s.equals(""))
return DEFAULT_TCP_PORT;
else
return Integer.parseInt(s);
}
public static boolean getUseZLib() {
return Config.getInt(KEY_ZLIB, 1) == 1;
}
public static void setUseZLib(boolean val) {
Config.setInt(KEY_ZLIB, val ? 1 : 0);
}
/*
public static int getMinTracklogInterval() {
return getInt(KEY_TRACKLOG_MIN_INTERVAL,DEFAULT_TRACKLOG_MIN_INTERVAL);
}
public static void setMinTracklogInterval(int val) {
setInt(KEY_TRACKLOG_MIN_INTERVAL,val);
}
*/
public static int getResendInterval() {
return getInt(KEY_RESEND_INTERVAL,DEFAULT_RESEND_INTERVAL);
}
public static void setResendInterval(int val) {
setInt(KEY_RESEND_INTERVAL,val);
}
public static int getReceiveReconnectInterval() {
return getInt(KEY_RECEIVE_RECONNECT_INTERVAL,DEFAULT_RECEIVE_RECONNECT_INTERVAL);
}
public static void setReceiveReconnectInterval(int val) {
setInt(KEY_RECEIVE_RECONNECT_INTERVAL,val);
}
/*
public static int getSegmentNPoints() {
return getInt(KEY_SEGMENT_NPOINTS,DEFAULT_SEGMENT_NPOINTS);
}
public static void setSegmentNPoints(int val) {
setInt(KEY_SEGMENT_NPOINTS,val);
}
*/
public static GpsDriver getGpsDriver() {
GpsDriver[] all = GpsDriver.getAllDrivers();
String ident = getString(KEY_GPS_DRIVER);
if (ident != null) {
for (int i = 0; i < all.length; i ++)
if (all[i].getDriverId().compareTo(ident) == 0)
return all[i];
}
return null;
}
public static void setGpsDriver(GpsDriver driver) {
GpsDriver old = getGpsDriver();
if (old != driver) {
setGpsDevice(null);
}
setString(KEY_GPS_DRIVER,driver.getDriverId());
}
/**
*
* @return GpsDeviceInfo struct containing selected Driver & Device. Returns null if no device is selected
*/
public static GpsDeviceInfo getGpsDevice() {
GpsDriver driver = getGpsDriver();
String name = getString(KEY_GPS_DEVNAME);
String address = getString(KEY_GPS_DEVADDRESS);
if (address == null || address == "")
return null;
else
return new GpsDeviceInfo(driver,name == null ? "" : name,address);
}
public static void setGpsDevice(GpsDeviceInfo dev) {
if (dev == null) {
setString(KEY_GPS_DEVADDRESS,"");
setString(KEY_GPS_DEVNAME,"");
}
else {
setGpsDriver(dev.getDriver());
setString(KEY_GPS_DEVADDRESS,dev.getAddress());
setString(KEY_GPS_DEVNAME,dev.getName());
}
}
public static Profile[] getProfiles() {
if (_cacheProfiles != null) {
return _cacheProfiles;
}
else {
String strall = getString(KEY_PROFILES);
if (strall == null)
return _cacheProfiles = new Profile[0];
String[] all = unpackStrings(strall);
if (all == null)
return _cacheProfiles = new Profile[0];
Profile[] out = new Profile[all.length];
int j = 0;
for (int i = 0; i < out.length; i ++) {
String[] arr = unpackStrings(all[i]);
if (arr != null) {
Profile p = Profile.fromStringArray(arr);
if (p != null) {
out[j++] = p;
}
}
}
if (j < out.length) {
Profile[] out2 = new Profile[j];
for (int i = 0; i < j; i ++)
out2[i] = out[i];
return _cacheProfiles = out2;
}
else {
return _cacheProfiles = out;
}
}
}
public static void setProfiles(Profile[] profiles) {
_cacheProfiles = profiles;
String[] arr = new String[profiles.length];
for (int i = 0; i < arr.length; i ++) {
arr[i] = packStrings(profiles[i].toStringArray());
}
setString(KEY_PROFILES,packStrings(arr));
}
public static Profile getLastTrackProfile() {
String str = getString(KEY_LASTTRACK_PROFILE);
if (str == null)
return null;
String[] arr = unpackStrings(str);
if (arr == null)
return null;
return Profile.fromStringArray(arr);
}
public static void setLastTrackProfile(Profile p) {
setString(KEY_LASTTRACK_PROFILE,packStrings(p.toStringArray()));
}
public static void setLastTrackKey(String key) {
setString(KEY_LASTTRACK_KEY,key);
}
public static String getLastTrackKey() {
String val = getString(KEY_LASTTRACK_KEY);
if (val == "")
return null;
else
return val;
}
public static double getWidgetPageRepaintInterval() {
return getDouble(KEY_WIDGETPAGE_REPAINT_INTERVAL,DEFAULT_WIDGETPAGE_REPAINT_INTERVAL);
}
public static void setWidgetPageRepaintInterval(double val) {
setDouble(KEY_WIDGETPAGE_REPAINT_INTERVAL,val);
}
public static WidgetPosition[] getWidgetLayout() {
String str = getString(KEY_WIDGET_LAYOUT);
if (str == null)
return null;
String[] arr = Config.unpackStrings(str);
if (arr == null)
return null;
Vector vect = new Vector();
for (int i = 0; i < arr.length; i ++) {
WidgetPosition wp = WidgetPosition.load(arr[i]);
if (wp != null)
vect.addElement(wp);
}
if (vect.size() == 0)
return null;
WidgetPosition[] wp = new WidgetPosition[vect.size()];
for (int i = 0; i < wp.length; i ++)
wp[i] = (WidgetPosition)vect.elementAt(i);
return wp;
}
public static void setWidgetLayout(WidgetPosition[] wp) {
String[] arr = new String[wp.length];
for (int i = 0; i < arr.length; i ++)
arr[i] = wp[i].save();
setString(KEY_WIDGET_LAYOUT,packStrings(arr));
}
public static boolean getKeepBacklight() {
return getBoolean(KEY_KEEP_BACKLIGHT,false);
}
public static void setKeepBacklight(boolean val) {
setBoolean(KEY_KEEP_BACKLIGHT,val);
}
public static int getBacklightLevel() {
return getInt(KEY_BACKLIGHT_LEVEL,DEFAULT_BACKLIGHT_LEVEL);
}
public static void setBacklightLevel(int level) {
setInt(KEY_BACKLIGHT_LEVEL,level);
}
public static final int PROTOCOL_UDP = 0;
public static final int PROTOCOL_TCP = 1;
// public static final int PROTOCOL_HTTP = 2;
public static final int HTTP_PING_NEVER = 0;
public static final int HTTP_PING_ONCE = 1;
private static final String DEFAULT_UDP_HOST = "81.0.213.99"; //"update.live-tracking.org";
private static final int DEFAULT_UDP_PORT = 5483;
private static final String DEFAULT_TCP_HOST = "81.0.213.99"; //"update.live-tracking.org";
private static final int DEFAULT_TCP_PORT = 5483;
private static final int DEFAULT_PROTOCOL = PROTOCOL_UDP;
private static final String DEFAULT_WSSERVER_URL = "ws://update.live-tracking.org:80/tracker";
private static final int DEFAULT_HTTP_PING_MODE = HTTP_PING_NEVER;
private static final int DEFAULT_RESEND_INTERVAL = 60*1000; // milliseconds
private static final int DEFAULT_RECEIVE_RECONNECT_INTERVAL = 30*1000; // milliseconds
private static final int DEFAULT_BACKLIGHT_LEVEL = 50;
private static final double DEFAULT_WIDGETPAGE_REPAINT_INTERVAL = 0.5;
private static final byte KEY_GPS_DRIVER = 0;
private static final byte KEY_GPS_DEVADDRESS = 1;
private static final byte KEY_GPS_DEVNAME = 2;
private static final byte KEY_UDPSERVER_HOST = 3;
private static final byte KEY_UDPSERVER_PORT = 4;
private static final byte KEY_WIDGETPAGE_REPAINT_INTERVAL = 5;
private static final byte KEY_PROFILES = 6;
private static final byte KEY_LASTTRACK_KEY = 7;
private static final byte KEY_PROTOCOL = 8;
private static final byte KEY_CONFIG_VERSION = 9;
private static final byte KEY_HTTP_PING_MODE = 10;
private static final byte KEY_TCPSERVER_HOST = 11;
private static final byte KEY_TCPSERVER_PORT = 12;
private static final byte KEY_BACKLIGHT_LEVEL = 13;
private static final byte KEY_DEBUG_MODE = 14;
private static final byte KEY_ZLIB = 15;
private static final byte KEY_RESEND_INTERVAL = 16;
private static final byte KEY_RECEIVE_RECONNECT_INTERVAL = 17;
private static final byte KEY_WIDGET_LAYOUT = 18;
private static final byte KEY_LASTTRACK_PROFILE = 19;
private static final byte KEY_KEEP_BACKLIGHT = 20;
private static final byte KEY_MAX = 20;
private static final byte BYTE_ENCODING_DEFAULT = 1;
private static final byte BYTE_ENCODING_UTF8 = 2;
private static Profile[] _cacheProfiles;
private static boolean getBoolean(int key, boolean defval) {
String s = getString(key);
if (s == null)
return defval;
else if (s.equals("0"))
return false;
else if (s.equals("1"))
return true;
else
return defval;
}
private static void setBoolean(int key, boolean val) {
setString(key,val ? "1" : "0");
}
private static void setInt(int key, int value) {
setString(key,""+value);
}
private static int getInt(int key, int defval) {
String s = getString(key);
if (s == null || s.equals("")) {
return defval;
}
else {
return Integer.parseInt(s);
}
}
private static void setDouble(int key, double value) {
setString(key,""+value);
}
private static double getDouble(int key, double defval) {
String s = getString(key);
if (s == null || s.equals("")) {
return defval;
}
else {
return Double.parseDouble(s);
}
}
private static String getString(int key) {
Record r = _records[key];
if (r != null && r.data.length >= 2) {
if (r.data.length >= 2 && r.data[1] == BYTE_ENCODING_UTF8)
return UTF8.decode(r.data,2,r.data.length-2);
else if (r.data.length >= 2 && r.data[1] == BYTE_ENCODING_DEFAULT)
return new String(r.data,2,r.data.length-2);
else
return new String(r.data,1,r.data.length-1); // fallback for prehistoric version
}
else
return null;
}
private static void setString(int key, String val) {
Record r;
if (_records[key] == null) {
r = new Record();
r.recordStoreId = -1;
_records[key] = r;
}
else {
r = _records[key];
}
if (val == null) val = "";
byte[] newdata;
newdata = UTF8.encode(val);
r.data = new byte[2+newdata.length];
r.data[0] = (byte)key;
r.data[1] = BYTE_ENCODING_UTF8;
for (int i = 0; i < newdata.length; i ++)
r.data[2+i] = newdata[i];
r.isModified = true;
}
public static String packStrings(String[] arr) {
StringBuffer sb = new StringBuffer();
sb.append(arr.length);
sb.append(',');
for (int i = 0; i < arr.length; i ++) {
sb.append(arr[i].length());
sb.append(',');
}
for (int i = 0; i < arr.length; i ++)
sb.append(arr[i]);
return sb.toString();
}
public static String[] unpackStrings(String str) {
String[] out;
int[] lens;
int startPos;
int lastPos;
int count;
if (str == null)
return null;
startPos = str.indexOf(',');
if (startPos < 0)
return null;
count = Integer.parseInt(str.substring(0, startPos));
lens = new int[count];
lastPos = startPos;
for (int i = 0; i < count; i ++) {
int pos = str.indexOf(',',lastPos+1);
if (pos < 0) return null;
lens[i] = Integer.parseInt(str.substring(lastPos+1, pos));
lastPos = pos;
}
lastPos ++;
out = new String[count];
for (int i = 0; i < count; i ++) {
if (lastPos+lens[i] > str.length())
return null;
out[i] = str.substring(lastPos, lastPos+lens[i]);
lastPos += lens[i];
}
if (lastPos != str.length())
return null;
return out;
}
private static void readAll() {
_records = new Record[KEY_MAX+1];
RecordStore rs;
try {
rs = RecordStore.openRecordStore("config",true);
RecordEnumeration re = rs.enumerateRecords(null, null, false);
while (re.hasNextElement()) {
Record r = new Record();
r.recordStoreId = re.nextRecordId();
r.data = rs.getRecord(r.recordStoreId);
r.isModified = false;
if (r.data.length >= 1 && r.data[0] <= KEY_MAX) {
_records[r.data[0]] = r;
}
}
rs.closeRecordStore();
}
catch (Exception e) {
Util.showError("Cannot read user settings!", e);
}
}
public static void writeAll() {
RecordStore rs;
try {
rs = RecordStore.openRecordStore("config", true);
for (int i = 0; i <= KEY_MAX; i ++) {
Record r = _records[i];
if (r != null && r.isModified) {
if (r.recordStoreId < 0) {
r.recordStoreId = rs.addRecord(r.data, 0, r.data.length);
}
else {
rs.setRecord(r.recordStoreId, r.data, 0, r.data.length);
}
r.isModified = false;
}
}
rs.closeRecordStore();
}
catch (Exception e) {
Util.showError("Cannot save user settings!", e);
}
}
private static Record[] _records;
private static String _lastRunVersion;
}