package com.framsticks.params; import java.io.IOException; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Collection; import java.util.List; import com.framsticks.params.types.*; import org.apache.log4j.Logger; import java.util.Locale; /** * The Class SimpleAbstractAccess implements all the methods of AccessInterface * which actions can be implemented with usage of {@link AccessInterface} methods * or concern schema, which is stored in {@link #framsClass} * * Based on c++ class SimpleAbstractParam located in: cpp/gdk/param.* * * @author Jarek Szymczak , Mateusz Jarus (please * replace name and surname with my personal data) * * @author Piotr Sniegowski */ public abstract class SimpleAbstractAccess implements AccessInterface { private final static Logger LOGGER = Logger.getLogger(SimpleAbstractAccess.class.getName()); @Override public final FramsClass getFramsClass() { return framsClass; } public void setFramsClass(FramsClass framsClass) { this.framsClass = framsClass; } /** * Simple String key, value class. */ public static class Entry { public final String key; public final String value; public Entry(String key, String value) { this.key = key; this.value = value; } @Override public String toString() { return key + " = " + value; } } protected FramsClass framsClass; @Override public String getId() { return framsClass.getId(); } @Override public int getParamCount() { return framsClass.getParamCount(); } @Override public Param getParam(int i) { return framsClass.getParamEntry(i); } @Override public Param getParam(String id) { return framsClass.getParamEntry(id); } @Override public Param getGroupMember(int gi, int n) { return framsClass.getGroupMember(gi, n); } @Override public T get(int i, Class type) { return get(getParam(i), type); } @Override public T get(String id, Class type) { return get(getParam(id), type); } @Override public int set(String id, T value) { return set(getParam(id), value); } @Override public int set(int i, T value) { return set(getParam(i), value); } @SuppressWarnings("unchecked") @Override public int set(Param param, T value) { int flags = 0; //String id = param.getEffectiveId(); try { Object oldValue = get(param, param.getStorageType()); Object casted = param.reassign(value, oldValue); if (casted != oldValue) { internalSet(param, casted); } } catch (CastFailure e) { LOGGER.error("casting failure while set: ", e); } return flags; } @Override public void setDefault(boolean numericOnly) { for (int i = 0; i < framsClass.getParamCount(); i++) setDefault(i, numericOnly); } @Override public void setDefault(int i, boolean numericOnly) { Param entry = framsClass.getParamEntry(i); if ((entry != null) && (!numericOnly || entry.isNumeric())) { set(i, entry.getDef(entry.getStorageType())); } } @Override public void setMin() { for (int i = 0; i < framsClass.getParamCount(); i++) { setMin(i); } } @SuppressWarnings("unchecked") @Override public void setMin(int i) { Param entry = framsClass.getParamEntry(i); Object min = entry.getMin(entry.getStorageType()); if (min != null) { set(i, min); } } @Override public void setMax() { for (int i = 0; i < framsClass.getParamCount(); i++) { setMax(i); } } @SuppressWarnings("unchecked") @Override public void setMax(int i) { Param entry = framsClass.getParamEntry(i); Object max = entry.getMax(entry.getStorageType()); if (max != null) { set(i, max); } } @Override public void copyFrom(AccessInterface src) { clearValues(); //TODO: iterate over self, and pull from src /* for (int i = 0; i < src.getFramsClass().size(); i++) { this.set(i, src.get(i, Object.class)); } */ } @Override public void save(SinkInterface sink) { assert framsClass != null; sink.print(framsClass.getId()).print(":").breakLine(); for (Param p : framsClass.getParamEntries()) { if (p instanceof ValueParam) { Object value = get(p, Object.class); if (value == null) { continue; } sink.print(p.getId()).print(":"); ((ValueParam)p).save(sink, value); sink.breakLine(); //continue; } /* if (p instanceof CompositeParam) { if (!(p instanceof ListParam)) { continue; } Collection c = get(p, Collection.class); if (c != null) { save(stream, p, c.size()); } } */ } sink.breakLine(); } @Override public String save2(boolean omitDefaultValues) { StringBuilder stringBuilder = new StringBuilder(); DecimalFormat df = new DecimalFormat("#.###", new DecimalFormatSymbols( Locale.ENGLISH)); boolean canOmitName = false; int n = 0; for (int i = 0; i < framsClass.getParamCount(); i++) { Object value = this.get(i, Object.class); Object def = framsClass.getParamEntry(i).getDef(Object.class); if (value != null && (!omitDefaultValues || !value.equals(def))) { if ((n != i && !canOmitName) || (getParam(i).getFlags() & Flags.CANOMITNAME) == 0) { stringBuilder.append(getParam(i).getId()); stringBuilder.append("="); } n++; canOmitName = true; if (this.get(i, Object.class) instanceof String) { String valueString = this.get(i, String.class); valueString = valueString.replaceAll("\\\"", "\\\\\""); valueString = valueString.contains(",") ? "\"" + valueString + "\"" : valueString; // if ("".equals(valueString.trim())) // value = "\"\""; stringBuilder.append(valueString); } else if (this.get(i, Object.class) instanceof Double) { stringBuilder.append(df.format(this.get(i, Double.class))); } else stringBuilder.append(this.get(i, Object.class)); stringBuilder.append(", "); } else { canOmitName = false; } } String params = ""; if (stringBuilder.length() > 1) params = stringBuilder.substring(0, stringBuilder.length() - 2); return getId() + ":" + params; } /* private static void appendToValue(StringBuilder value, String line) { if (value.length() != 0) { value.append(System.getProperty("line.separator")); } value.append(line); } */ private Entry readEntry(SourceInterface source) throws IOException { String line; String key = null; StringBuilder value = null; while ((line = source.readLine()) != null) { if (key == null) { int colonIndex = line.indexOf(':'); if (colonIndex == -1) { return null; } key = line.substring(0, colonIndex); String inlineValue = line.substring(colonIndex + 1); if (!inlineValue.startsWith("~")) { return new Entry(key, inlineValue); } value = new StringBuilder(); value.append(inlineValue.substring(1)); continue; } if (value.length() != 0) { value.append(System.getProperty("line.separator")); } if (line.contains("~")) { value.append(line.substring(0, line.indexOf("~"))); return new Entry(key, value.toString()); } value.append(line); /* if (line.contains("~")) { String lastLine = line.substring(0, line.indexOf("~")); if (lastLine.length() > 0) { appendToValue(value, lastLine); } return new Entry(key, value.toString()); } appendToValue(value, line); */ } return null; } @Override public void load(SourceInterface source) throws Exception { //TODO not clearing values, because get from manager gives only fields, not children //this.clearValues(); Entry entry; while ((entry = readEntry(source)) != null) { Param param = getParam(entry.key); if (param == null) { continue; } if ((param.getFlags() & Flags.DONTLOAD) != 0) { LOGGER.debug("DontLoad flag was set - not loading..."); } else { int retFlags = this.set(param, entry.value); if ((retFlags & (Flags.PSET_HITMIN | Flags.PSET_HITMAX)) != 0) { String which = ((retFlags & Flags.PSET_HITMIN) != 0) ? "small" : "big"; LOGGER.warn("value of key '" + entry.key + "' was too " + which + ", adjusted"); } } } } protected abstract void internalSet(Param param, T value); @Override public Collection getParams() { return framsClass.getParamEntries(); } /* protected > int setAndCut(Param param, Object value, Class type) { int flags = 0; T val = type.cast(value); T min = param.getMin(type); T max = param.getMax(type); if (min != null && val.compareTo(min) < 0) { val = min; flags |= Flags.PSET_HITMIN; } if (max != null && val.compareTo(max) > 0) { val = max; flags |= Flags.PSET_HITMAX; } internalSet(param, val); return flags; }*/ }