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 <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
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<Double, WstLine> lines;
ingo@446: 
ingo@447:     /** The column names.*/
ingo@447:     protected List<String> 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<String>(cols);
ingo@447:         this.lines       = new HashMap<Double, WstLine>();
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<WstLine> 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 :