package uk.org.smithfamily.mslogger.dashboards; import java.io.*; import java.util.*; import org.json.*; import uk.org.smithfamily.mslogger.ApplicationSettings; import uk.org.smithfamily.mslogger.log.DebugLogManager; import uk.org.smithfamily.mslogger.widgets.*; import uk.org.smithfamily.mslogger.widgets.Indicator.DisplayType; import uk.org.smithfamily.mslogger.widgets.Indicator.Orientation; import android.content.res.AssetManager; /** * This is used to load and save dashboard files */ public enum DashboardIO { INSTANCE; private static final String TOP = "top"; private static final String LEFT = "left"; private static final String BOTTOM = "bottom"; private static final String RIGHT = "right"; private static final String DEFAULT = "default"; private static final String LABEL_DIGITS = "labelDigits"; private static final String VALUE_DIGITS = "valueDigits"; private static final String HI_D = "hiD"; private static final String HI_W = "hiW"; private static final String LOW_W = "lowW"; private static final String LOW_D = "lowD"; private static final String MAX = "max"; private static final String MIN = "min"; private static final String UNITS = "units"; private static final String GAUGE = "gauge"; private static final String RPM = "rpm"; private static final String DASHBOARDS = "dashboards"; private static final String INDICATORS = "indicators"; private static final String INDICATORS_LANDSCAPE = "indicators_landscape"; private static final String LOCATION = "location"; private static final String ORIENTATION = "orientation"; private static final String HORIZONTAL = "horizontal"; private static final String TYPE = "type"; private static final String CHANNEL = "channel"; private static final String TITLE = "title"; private List<Dashboard> activeDashboardDefinitions = new ArrayList<Dashboard>(); private final Map<String, List<Dashboard>> dashCache = new HashMap<String, List<Dashboard>>(); /** * Save the default dashboard to a file */ public void saveDash() { saveDash(DEFAULT); } /** * Build the JSON string that can be saved to a JSON formatted file * * @param dashName The dashboard name to save */ public synchronized void saveDash(final String dashName) { final JSONObject root = new JSONObject(); final JSONArray jDashes = new JSONArray(); try { for (final Dashboard d : activeDashboardDefinitions) { final JSONObject jDash = generateJDash(d); jDashes.put(jDash); } root.put(DASHBOARDS, jDashes); final String definition = root.toString(2); writeDefinition(dashName, definition); } catch (final Exception e) { DebugLogManager.INSTANCE.logException(e); } dashCache.put(dashName, activeDashboardDefinitions); } /** * Generate a JSON object from a Dashboard object * * @param d The dashboard object * @return A JSON object * @throws JSONException */ private JSONObject generateJDash(final Dashboard d) throws JSONException { final JSONObject jDash = new JSONObject(); JSONArray jIndicators = new JSONArray(); for (final Indicator i : d.getPortrait()) { final JSONObject jIndicator = generateJIndicator(i); jIndicators.put(jIndicator); } jDash.put(INDICATORS, jIndicators); jIndicators = new JSONArray(); for (final Indicator i : d.getLandscape()) { final JSONObject jIndicator = generateJIndicator(i); jIndicators.put(jIndicator); } jDash.put(INDICATORS_LANDSCAPE, jIndicators); return jDash; } /** * Generate a JSON object of an indicator * * @param i The indicator to generate the JSON object for * @return The JSON object representing an indicator * @throws JSONException */ private JSONObject generateJIndicator(final Indicator i) throws JSONException { final JSONObject j = new JSONObject(); j.put(TITLE, i.getTitle()); j.put(CHANNEL, i.getChannel()); j.put(TYPE, i.getDisplayType().name()); j.put(UNITS, i.getUnits()); j.put(MIN, i.getMin()); j.put(MAX, i.getMax()); j.put(LOW_D, i.getLowD()); j.put(LOW_W, i.getLowW()); j.put(HI_D, i.getHiD()); j.put(HI_W, i.getHiW()); j.put(VALUE_DIGITS, i.getVd()); j.put(LABEL_DIGITS, i.getLd()); j.put(LOCATION, getJLocation(i.getLocation())); j.put(ORIENTATION, i.getOrientation().name()); return j; } /** * Get the JSON object of a location object of an indicator * * @param l The Location object * @return A JSON object representing a location * @throws JSONException */ private JSONObject getJLocation(final Location l) throws JSONException { final JSONObject jLocation = new JSONObject(); jLocation.put(TOP, l.getTop()).put(LEFT, l.getLeft()).put(BOTTOM, l.getBottom()).put(RIGHT, l.getRight()); return jLocation; } /** * Load a dashboard by its name * * @param dashName Name of the dashboard * @return A list of Dashboard object */ public synchronized List<Dashboard> loadDash(String dashName) { activeDashboardDefinitions = dashCache.get(dashName); if (activeDashboardDefinitions == null) { activeDashboardDefinitions = new ArrayList<Dashboard>(); try { dashName += ".json"; final String dashDefinition = readDefinition(dashName); final JSONObject jsonObject = new JSONObject(dashDefinition); final JSONArray dashes = jsonObject.getJSONArray(DASHBOARDS); for (int dashIndex = 0; dashIndex < dashes.length(); dashIndex++) { final JSONObject jDash = dashes.getJSONObject(dashIndex); activeDashboardDefinitions.add(createDash(jDash)); } } catch (final JSONException e) { DebugLogManager.INSTANCE.logException(e); } if (activeDashboardDefinitions.size() == 1) { activeDashboardDefinitions.add(new Dashboard()); } dashCache.put(dashName, activeDashboardDefinitions); } return activeDashboardDefinitions; } /** * Create a Dashboard object from a JSON dashboard object * * @param jDash The JSONObject of the dashboard * @return The Dashboard object * @throws JSONException */ private Dashboard createDash(final JSONObject jDash) throws JSONException { final Dashboard d = new Dashboard(); JSONArray indicators = jDash.getJSONArray(INDICATORS); for (int indIndex = 0; indIndex < indicators.length(); indIndex++) { final JSONObject jIndicator = indicators.getJSONObject(indIndex); final Indicator i = createIndicator(jIndicator); d.add(i, false); } indicators = jDash.optJSONArray(INDICATORS_LANDSCAPE); if (indicators != null) { for (int indIndex = 0; indIndex < indicators.length(); indIndex++) { final JSONObject jIndicator = indicators.getJSONObject(indIndex); final Indicator i = createIndicator(jIndicator); d.add(i, true); } } return d; } /** * Create an Indicator object from a JSON indicator object * * @param jIndicator The JSONObject of the indicator * @return An instance of Indicator * @throws JSONException */ private Indicator createIndicator(final JSONObject jIndicator) throws JSONException { final Indicator i = new Indicator(); final String channel = jIndicator.optString(CHANNEL, RPM); final IndicatorDefault id = IndicatorDefaults.defaults.get(channel); final String title = jIndicator.optString(TITLE, id != null ? id.getTitle() : ""); final String type = jIndicator.optString(TYPE, GAUGE).toUpperCase(); final JSONObject jLocation = jIndicator.getJSONObject(LOCATION); final Location loc = createLocation(jLocation); final String units = jIndicator.optString(UNITS, id != null ? id.getUnits() : ""); final double min = jIndicator.optDouble(MIN, id != null ? id.getMin() : 0.0); final double max = jIndicator.optDouble(MAX, id != null ? id.getMax() : 7000); final double lowD = jIndicator.optDouble(LOW_D, id != null ? id.getLoD() : 0); final double lowW = jIndicator.optDouble(LOW_W, id != null ? id.getLoW() : 0); final double hiW = jIndicator.optDouble(HI_W, id != null ? id.getHiW() : 5000); final double hiD = jIndicator.optDouble(HI_D, id != null ? id.getHiD() : 7000); final int vd = jIndicator.optInt(VALUE_DIGITS, id != null ? id.getVd() : 0); final int ld = jIndicator.optInt(LABEL_DIGITS, id != null ? id.getLd() : 0); final String orientation = jIndicator.optString(ORIENTATION, HORIZONTAL).toUpperCase(); i.setTitle(title); i.setChannel(channel); i.setDisplayType(DisplayType.valueOf(type)); i.setLocation(loc); i.setUnits(units); i.setMin(min); i.setMax(max); i.setLowD(lowD); i.setLowW(lowW); i.setHiW(hiW); i.setHiD(hiD); i.setVd(vd); i.setLd(ld); i.setOrientation(Orientation.valueOf(orientation)); if (id == null) { IndicatorDefaults.defaults.put(channel, new IndicatorDefault(channel, "", units, min, max, lowD, lowW, hiW, hiD, vd, ld)); } return i; } /** * Create a Location object from a JSON location object * * @param jLocation The JSONObject of the location * @return An instance of Location * @throws JSONException */ private Location createLocation(final JSONObject jLocation) throws JSONException { return new Location(jLocation.optDouble(LEFT, 0.0), jLocation.optDouble(TOP, 0.0), jLocation.optDouble(RIGHT, 0.5), jLocation.optDouble(BOTTOM, 0.5)); } /** * Write a dashboard to a file * * @param fileName The dashboard file name * @param definition The JSON string of the dashboard * @throws FileNotFoundException */ private void writeDefinition(String fileName, final String definition) throws FileNotFoundException { fileName += ".json"; final File output = new File(ApplicationSettings.INSTANCE.getDashDir(), fileName); final PrintWriter p = new PrintWriter(output); p.println(definition); p.close(); } /** * Read a dashboard from a file * * @param fileName The dashboard file name * @return A JSON string of the dashboard */ private String readDefinition(final String fileName) { final StringBuilder sb = new StringBuilder(); final String assetFileName = DASHBOARDS + File.separator + fileName; final File override = new File(ApplicationSettings.INSTANCE.getDashDir(), fileName); final AssetManager assetManager = ApplicationSettings.INSTANCE.getContext().getResources().getAssets(); BufferedReader input = null; InputStream data = null; try { try { if (override.canRead()) { data = new FileInputStream(override); } else { data = assetManager.open(assetFileName); } input = new BufferedReader(new InputStreamReader(data)); String line; while ((line = input.readLine()) != null) { sb.append(line); } data.close(); } finally { if (input != null) { input.close(); } if (data != null) { data.close(); } } } catch (final IOException e) { DebugLogManager.INSTANCE.logException(e); } return sb.toString(); } /** * Load a dashboard * * @return A dashboard list */ public List<Dashboard> loadDash() { return loadDash(DEFAULT); } }