ingo@446: package de.intevation.flys.exports; ingo@446: ingo@446: import java.io.BufferedWriter; ingo@446: import java.io.OutputStream; ingo@446: import java.io.OutputStreamWriter; ingo@446: import java.io.PrintWriter; ingo@446: ingo@447: import java.util.ArrayList; ingo@446: import java.util.Collection; ingo@446: import java.util.HashMap; ingo@447: import java.util.List; ingo@446: import java.util.Locale; ingo@446: import java.util.Map; ingo@446: import java.util.TreeMap; ingo@446: ingo@446: import org.apache.log4j.Logger; ingo@446: ingo@446: import de.intevation.flys.artifacts.model.WstLine; ingo@446: ingo@446: ingo@446: /** ingo@446: * A writer that creates WSTs. ingo@446: * ingo@446: * @author Ingo Weinzierl ingo@446: */ ingo@446: public class WstWriter { ingo@446: felix@3147: /** The logger used in this class. */ ingo@446: private static Logger logger = Logger.getLogger(WstWriter.class); ingo@446: felix@3147: /** The default unit that is written into the header of the WST. */ ingo@446: public static final String DEFAULT_UNIT = "Wassserstand [NN + m]"; ingo@446: felix@3147: /** The lines that need to be included for the export. */ ingo@446: protected Map lines; ingo@446: felix@3147: /** The column names. */ ingo@447: protected List columnNames; ingo@447: felix@3147: /** The locale used to format the values. */ ingo@446: protected Locale locale; ingo@446: felix@3147: /** The number of discharge columns. */ ingo@446: protected int cols; ingo@446: felix@3147: /** The last Q values. */ ingo@446: protected double[] qs; ingo@446: ingo@446: ingo@446: ingo@446: /** felix@3284: * This constructor creates a new WstWriter with a number of Q columns. ingo@446: * ingo@446: * @param cols The number of columns of the resulting WST. ingo@446: */ ingo@446: public WstWriter(int cols) { ingo@447: this.columnNames = new ArrayList(cols); ingo@447: this.lines = new HashMap(); ingo@447: this.qs = new double[cols]; ingo@447: this.locale = Locale.US; ingo@446: } ingo@446: ingo@446: ingo@446: /** ingo@446: * This method is used to create the WST from the data that has been ingo@446: * inserted using add(double[]) before. felix@3284: * @param out Where to write to. ingo@446: */ ingo@446: public void write(OutputStream out) { ingo@446: logger.info("WstWriter.write"); ingo@446: ingo@446: PrintWriter writer = new PrintWriter( ingo@446: new BufferedWriter( ingo@446: new OutputStreamWriter(out))); ingo@446: ingo@749: this.qs = new double[cols]; ingo@749: ingo@446: writeHeader(writer); ingo@446: ingo@446: Collection collection = new TreeMap(lines).values(); ingo@446: ingo@446: for (WstLine line: collection) { ingo@446: writeWLine(writer, line); ingo@446: } ingo@446: ingo@446: writer.flush(); ingo@446: writer.close(); ingo@446: } ingo@446: ingo@446: ingo@446: /** ingo@446: * This method is used to add a new line to the WST. ingo@446: * ingo@446: * @param wqkms A 3dim double array with [W,Q, KM]. ingo@446: */ ingo@446: public void add(double[] wqkms) { ingo@446: Double km = wqkms[2]; ingo@446: ingo@446: WstLine line = lines.get(km); ingo@446: ingo@446: if (line == null) { ingo@446: line = new WstLine(km.doubleValue()); ingo@446: lines.put(km, line); ingo@446: } ingo@446: ingo@446: line.add(wqkms[0], wqkms[1]); ingo@446: } ingo@446: ingo@446: ingo@749: public void addCorrected(double[] wqckms) { ingo@749: Double km = wqckms[2]; ingo@749: ingo@749: WstLine line = lines.get(km); ingo@749: ingo@749: if (line == null) { ingo@749: line = new WstLine(km.doubleValue()); ingo@749: lines.put(km, line); ingo@749: } ingo@749: ingo@749: line.add(wqckms[3], wqckms[1]); ingo@749: } ingo@749: ingo@749: ingo@446: /** ingo@447: * Adds a further column name. ingo@447: * ingo@447: * @param name The name of the new column. ingo@447: */ ingo@447: public void addColumn(String name) { ingo@447: if (name != null) { ingo@749: cols++; ingo@749: ingo@749: String basename = name; ingo@749: ingo@749: int i = 0; ingo@749: while (columnNames.contains(name)) { ingo@749: name = basename + "_" + i++; ingo@749: ingo@749: if (name.length() > 9) { ingo@749: name = name.substring(name.length() - 9); ingo@749: } ingo@749: } ingo@749: ingo@447: columnNames.add(name); ingo@447: } ingo@447: } ingo@447: ingo@447: ingo@447: /** ingo@446: * This method writes the header of the WST. ingo@446: * ingo@446: * @param writer The PrintWriter that creates the output. ingo@446: */ ingo@446: protected void writeHeader(PrintWriter writer) { ingo@446: logger.debug("WstWriter.writeHeader"); ingo@446: ingo@446: writer.println(cols); ingo@447: writer.print(" "); ingo@446: ingo@447: for (String columnName: columnNames) { ingo@447: writer.printf(locale, "%9s", columnName); ingo@447: } ingo@447: ingo@447: writer.println(); ingo@446: ingo@446: writer.write("* KM "); ingo@446: writer.write(DEFAULT_UNIT); ingo@446: writer.println(); ingo@446: } ingo@446: ingo@446: ingo@446: /** ingo@446: * This method writes a line with W values and a certain kilometer. ingo@446: * ingo@446: * @param writer The PrintWriter that is used to create the output. ingo@446: * @param line The WstLine that should be written to the output. ingo@446: */ ingo@446: protected void writeWLine(PrintWriter writer, WstLine line) { ingo@446: double km = line.getKm(); ingo@446: double[] qs = line.getQs(); ingo@446: int num = line.getSize(); ingo@446: ingo@446: if (dischargesChanged(qs)) { ingo@446: writeQLine(writer, qs); ingo@446: } ingo@446: ingo@446: writer.printf(locale, "%8.3f", km); ingo@446: ingo@446: for (int i = 0; i < num; i++) { ingo@446: writer.printf(locale, "%9.2f", line.getW(i)); ingo@446: } ingo@446: ingo@446: writer.println(); ingo@446: } ingo@446: ingo@446: ingo@446: /** ingo@446: * Writes a discharge line (Q values) into a WST. ingo@446: * ingo@446: * @param qs the Q values for the next range. ingo@446: */ ingo@446: protected void writeQLine(PrintWriter writer, double[] qs) { ingo@446: writer.write("*\u001f "); ingo@446: ingo@749: for (int i = 0; i < qs.length; i++) { ingo@446: this.qs[i] = qs[i]; ingo@446: ingo@446: writer.printf(locale, "%9.2f", qs[i]); ingo@446: } ingo@446: ingo@446: writer.println(); ingo@446: } ingo@446: ingo@446: ingo@446: /** ingo@446: * This method determines if a Q has changed from the last line to the ingo@446: * current one. ingo@446: * ingo@446: * @param newQs The Q values of the next line. ingo@446: * ingo@446: * @return true, if a Q value have changed, otherwise false. ingo@446: */ ingo@446: protected boolean dischargesChanged(double[] newQs) { ingo@446: // XXX maybe there is a way to do this faster ingo@446: for (int i = 0; i < cols; i++) { ingo@446: if (Math.abs(newQs[i] - qs[i]) >= 0.001) { ingo@446: return true; ingo@446: } ingo@446: } ingo@446: ingo@446: return false; ingo@446: } ingo@446: } ingo@446: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :