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:
ingo@446: /** The logger used in this class.*/
ingo@446: private static Logger logger = Logger.getLogger(WstWriter.class);
ingo@446:
ingo@446:
ingo@446: /** 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:
ingo@446:
ingo@446: /** The lines that need to be included for the export.*/
ingo@446: protected Map lines;
ingo@446:
ingo@447: /** The column names.*/
ingo@447: protected List columnNames;
ingo@447:
ingo@446: /** The locale used to format the values.*/
ingo@446: protected Locale locale;
ingo@446:
ingo@446: /** The number of discharge columns.*/
ingo@446: protected int cols;
ingo@446:
ingo@446: /** The last Q values.*/
ingo@446: protected double[] qs;
ingo@446:
ingo@446:
ingo@446:
ingo@446: /**
ingo@446: * This constructor creates a new WstWriter with an OutputStream and a
ingo@446: * number of Q columns.
ingo@446: *
ingo@446: * @param out The output stream where the WST is written to.
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.
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 :