ingo@617: package de.intevation.gnv.histogram;
ingo@617: 
ingo@1081: import de.intevation.artifacts.CallContext;
ingo@1081: 
ingo@1081: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
ingo@1081: 
ingo@1081: import de.intevation.gnv.chart.ChartLabels;
ingo@1081: 
ingo@617: import de.intevation.gnv.geobackend.base.Result;
ingo@617: import de.intevation.gnv.geobackend.base.ResultDescriptor;
ingo@617: 
ingo@617: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
ingo@617: 
ingo@617: import java.util.ArrayList;
ingo@617: import java.util.Collection;
ingo@617: import java.util.Iterator;
ingo@617: import java.util.List;
ingo@1081: import java.util.Locale;
ingo@617: 
ingo@617: import org.apache.log4j.Logger;
ingo@617: 
ingo@617: /**
ingo@770:  * This class supports some helper methods for histogram charts.
ingo@770:  *
ingo@770:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
ingo@617:  */
ingo@617: public class HistogramHelper {
ingo@617: 
ingo@770:     /**
ingo@770:      * Logger used for logging with log4j.
ingo@770:      */
ingo@617:     private static Logger logger = Logger.getLogger(HistogramHelper.class);
ingo@617: 
ingo@617: 
ingo@770:     /**
ingo@770:      * Disabled HistogramHelper constructor. This is a helper class and no
ingo@770:      * instance should be instantiated from this class.
ingo@770:      */
ingo@617:     private HistogramHelper() {
ingo@617:     }
ingo@617: 
ingo@617: 
ingo@770:     /**
ingo@770:      * This function prepare some input data and turns it into an array which is
ingo@770:      * taken by {@link de.intevation.gnv.chart.DefaultHistogram}.
ingo@770:      *
ingo@770:      * @param input A collection with the data used to be displayed in a
ingo@770:      * histogram
ingo@770:      * @param parameters A collection with a bunch of parameters
ingo@770:      * @param measurements A collection with a bunch of measurements
ingo@770:      * @param dates A collection with a bunch of dates
ingo@770:      *
ingo@770:      * @return Object[][] containing raw data which can be used to create
ingo@770:      * histograms
ingo@770:      */
ingo@617:     public static Object[][] prepareHistogramData(
ingo@617:         Collection input,
ingo@617:         Collection parameters,
ingo@617:         Collection measurements,
ingo@617:         Collection dates
ingo@617:     ) {
ingo@617:         List names = new ArrayList<String>();
ingo@617:         List data  = new ArrayList<Double[]>();
ingo@617: 
ingo@617:         if (logger.isDebugEnabled()) {
ingo@617:             logger.debug("############ prepare histogram data ##########");
ingo@617:             logger.debug("Input data size: " + input.size());
ingo@617:         }
ingo@617: 
ingo@617:         if (input == null) {
ingo@617:             return new Object[0][0];
ingo@617:         }
ingo@617: 
ingo@617:         String break1, break2, break3;
ingo@617:         int b1Idx = -1;
ingo@617:         int b2Idx = -1;
ingo@617:         int b3Idx = -1;
ingo@617:         int yIdx  = -1;
ingo@617:         try {
ingo@617:             Iterator iter = input.iterator();
ingo@617: 
ingo@617:             if (iter.hasNext()) {
ingo@617:                 Result row = (Result) iter.next();
ingo@617:                 Result previousRow = row;
ingo@617: 
ingo@617:                 if (b1Idx == -1) {
ingo@617:                     ResultDescriptor rd = row.getResultDescriptor();
ingo@617:                     b1Idx = rd.getColumnIndex("GROUP1");
ingo@617:                     b2Idx = rd.getColumnIndex("GROUP2");
ingo@617:                     b3Idx = rd.getColumnIndex("GROUP3");
ingo@617:                     yIdx  = rd.getColumnIndex("YORDINATE");
ingo@617: 
ingo@617:                     if (b1Idx == -1 || b2Idx == -1 || b3Idx == -1 || yIdx == -1) {
ingo@617:                         return new Object[0][0];
ingo@617:                     }
ingo@617:                 }
ingo@617:                 break1 = row.getString(b1Idx);
ingo@617:                 break2 = row.getString(b2Idx);
ingo@617:                 break3 = row.getString(b3Idx);
ingo@617: 
ingo@617:                 List values = new ArrayList<Double>();
ingo@617:                 while (iter.hasNext()) {
ingo@617: 
ingo@617:                     // found new series
ingo@617:                     if (!break1.equals(row.getString(b1Idx))
ingo@617:                         || !break2.equals(row.getString(b2Idx))
ingo@617:                         || !break3.equals(row.getString(b3Idx))
ingo@617:                         ) {
ingo@617: 
ingo@617:                         // get parameter name
ingo@617:                         String name = generateName(
ingo@617:                             break1, break2, break3,
ingo@617:                             parameters, measurements, dates
ingo@617:                         );
ingo@617: 
ingo@617:                         // add values and parameter name
ingo@617:                         data.add((Double[]) values.toArray(new Double[values.size()]));
ingo@617:                         names.add(name);
ingo@617: 
ingo@617:                         if (logger.isDebugEnabled()) {
ingo@617:                             logger.debug(" --- series name: " + name);
ingo@617:                             logger.debug(" --- series items: " + values.size());
ingo@617:                         }
ingo@617: 
ingo@617:                         values.clear();
ingo@617: 
ingo@617:                         Double yValue = row.getDouble(yIdx);
ingo@617:                         if (yValue != null)
ingo@617:                             values.add(yValue);
ingo@617: 
ingo@617:                         // set new conditions to find new series
ingo@617:                         break1 = row.getString(b1Idx);
ingo@617:                         break2 = row.getString(b2Idx);
ingo@617:                         break3 = row.getString(b3Idx);
ingo@617: 
ingo@617:                         previousRow = row;
ingo@617:                         row         = (Result) iter.next();
ingo@617:                     } else {
ingo@617: 
ingo@617:                         Double value = row.getDouble(yIdx);
ingo@617:                         if (value != null)
ingo@617:                             values.add(value);
ingo@617: 
ingo@617:                         row = (Result) iter.next();
ingo@617:                     }
ingo@617:                 }
ingo@617: 
ingo@617:                 Double yValue = row.getDouble(yIdx);
ingo@617:                 if (yValue != null)
ingo@617:                     values.add(yValue);
ingo@617: 
ingo@617:                 String name = generateName(
ingo@617:                     break1, break2, break3, parameters, measurements, dates);
ingo@617: 
ingo@617:                 if (logger.isDebugEnabled()) {
ingo@617:                     logger.debug(" --- series name: " + name);
ingo@617:                     logger.debug(" --- series items: " + values.size());
ingo@617:                 }
ingo@617: 
ingo@617:                 data.add((Double[]) values.toArray(new Double[values.size()]));
ingo@617:                 names.add(name);
ingo@617:             }
ingo@617:         }
ingo@617:         catch (Exception e) {
ingo@617:             logger.error(e.getMessage(), e);
ingo@617:         }
ingo@617: 
ingo@617:         int series = data.size();
ingo@617:         logger.debug(" === Found total: " + series);
ingo@617:         Object[][] obj = new Object[series][2];
ingo@617:         for (int i = 0; i < series; i++) {
ingo@617:             obj[i][0] = names.get(i);
ingo@617:             obj[i][1] = (Double[]) data.get(i);
ingo@617:         }
ingo@617: 
ingo@617:         return obj;
ingo@617:     }
ingo@617: 
ingo@617: 
ingo@770:     /**
ingo@770:      * This method generates a string made up of parameter name and a
ingo@770:      * measurement.
ingo@770:      *
ingo@770:      * @param break1 Id of a parameter.
ingo@770:      * @param break2 Id of a measurement.
ingo@770:      * @param break3 Id of a date.
ingo@770:      * @param parameters A collection with a bunch of parameters.
ingo@770:      * @param measurements A collection with a bunch of measurements.
ingo@770:      * @param dates A collection with a bunch of dates.
ingo@770:      *
ingo@770:      * @return Concatenated string (${parametername} + ${measurement} + m).
ingo@770:      */
ingo@617:     protected static String generateName(
ingo@617:         String break1, String break2, String break3,
ingo@617:         Collection parameters, Collection measurements, Collection dates)
ingo@617:     {
ingo@617:         return findValueTitle(parameters,break1) + " " +
ingo@617:                findValueTitle(measurements,break2) + "m";
ingo@617:     }
ingo@617: 
ingo@617: 
ingo@770:     /**
ingo@770:      * Find a value with the given <code>id</code> and return its description.
ingo@770:      *
ingo@770:      * @param values A collection which contains the value we are searching for
ingo@770:      * @param id Id of the value
ingo@770:      *
ingo@770:      * @return String representation of the value. An empty string is returned
ingo@770:      * if no value have been found with the given id.
ingo@770:      */
ingo@617:     protected static String findValueTitle(Collection values, String id) {
ingo@617:         if (values != null) {
ingo@617:             Iterator it = values.iterator();
ingo@617: 
ingo@617:             while (it.hasNext()) {
ingo@617:                 KeyValueDescibeData data = (KeyValueDescibeData) it.next();
ingo@617: 
ingo@617:                 if (id.equals(data.getKey())) {
ingo@617:                     return data.getValue();
ingo@617:                 }
ingo@617:             }
ingo@617:         }
ingo@617:         return "";
ingo@617:     }
ingo@1080: 
ingo@1080: 
ingo@1080:     /**
ingo@1080:      * Creates and returns labels to decorate histograms.
ingo@1080:      *
ingo@1080:      * @param uuid The UUID of the current artifact.
ingo@1080:      * @param context The CallContext object.
ingo@1080:      * @param data An array storing strings.
ingo@1080:      * @return A ChartLabels object with the 1st string in <i>data</i> as title.
ingo@1080:      */
ingo@1080:     public static ChartLabels createHistogramLabels(
ingo@1080:         String uuid, CallContext context, Locale locale, Object[] data)
ingo@1080:     {
ingo@1080:         RessourceFactory fac = RessourceFactory.getInstance();
ingo@1080: 
ingo@1080:         return new ChartLabels(
ingo@1080:             (String) data[0],
ingo@1080:             "",
ingo@1080:             "",
ingo@1080:             fac.getRessource(locale, "histogram.axis.range.title", ""));
ingo@1080:     }
ingo@1081: 
ingo@1081: 
ingo@1081:     public static Object[][] prepareVectorialHistogramData(Collection input) {
ingo@1081:         List names = new ArrayList<String>();
ingo@1081:         List data  = new ArrayList<Double[]>();
ingo@1081: 
ingo@1081:         if (logger.isDebugEnabled()) {
ingo@1081:             logger.debug("######### prepare vectorial histogram data #######");
ingo@1081:             logger.debug("Input data size: " + input.size());
ingo@1081:         }
ingo@1081: 
ingo@1081:         if (input == null) {
ingo@1081:             return new Object[0][0];
ingo@1081:         }
ingo@1081: 
ingo@1081:         int sIdx = -1;
ingo@1081:         int yIdx = -1;
ingo@1081: 
ingo@1081:         String series = null;
ingo@1081: 
ingo@1081:         try {
ingo@1081:             Iterator iter = input.iterator();
ingo@1081: 
ingo@1081:             if (iter.hasNext()) {
ingo@1081:                 Result row = (Result) iter.next();
ingo@1081:                 Result previousRow = row;
ingo@1081: 
ingo@1081:                 if (sIdx == -1 || yIdx == -1) {
ingo@1081:                     ResultDescriptor rd = row.getResultDescriptor();
ingo@1081:                     sIdx = rd.getColumnIndex("SERIES");
ingo@1081:                     yIdx = rd.getColumnIndex("YORDINATE");
ingo@1081: 
ingo@1081:                     if (sIdx == -1 || yIdx == -1) {
ingo@1081:                         return new Object[0][0];
ingo@1081:                     }
ingo@1081:                 }
ingo@1081: 
ingo@1081:                 List values = new ArrayList<Double>();
ingo@1081:                 while (iter.hasNext()) {
ingo@1081:                     row = (Result) iter.next();
ingo@1081: 
ingo@1081:                     // found new series
ingo@1081:                     if (series != null && !series.equals(row.getString(sIdx))) {
ingo@1081: 
ingo@1081:                         // add values and parameter name
ingo@1081:                         data.add((Double[])
ingo@1081:                             values.toArray(new Double[values.size()]));
ingo@1081:                         names.add(series);
ingo@1081: 
ingo@1081:                         if (logger.isDebugEnabled()) {
ingo@1081:                             logger.debug(" --- series name: " + series);
ingo@1081:                             logger.debug(" --- series items: " + values.size());
ingo@1081:                         }
ingo@1081: 
ingo@1081:                         values.clear();
ingo@1081:                     }
ingo@1081: 
ingo@1081:                     Double value = row.getDouble(yIdx);
ingo@1081:                     if (value != null)
ingo@1081:                         values.add(value);
ingo@1081: 
ingo@1081:                     series = row.getString(sIdx);
ingo@1081:                 }
ingo@1081: 
ingo@1081:                 if (logger.isDebugEnabled()) {
ingo@1081:                     logger.debug(" --- series name: " + series);
ingo@1081:                     logger.debug(" --- series items: " + values.size());
ingo@1081:                 }
ingo@1081: 
ingo@1081:                 data.add((Double[]) values.toArray(new Double[values.size()]));
ingo@1081:                 names.add(series);
ingo@1081:             }
ingo@1081:         }
ingo@1081:         catch (Exception e) {
ingo@1081:             logger.error(e.getMessage(), e);
ingo@1081:         }
ingo@1081: 
ingo@1081:         int count = data.size();
ingo@1081:         logger.debug(" === Found total: " + count);
ingo@1081:         Object[][] obj = new Object[count][2];
ingo@1081:         for (int i = 0; i < count; i++) {
ingo@1081:             obj[i][0] = names.get(i);
ingo@1081:             obj[i][1] = (Double[]) data.get(i);
ingo@1081:         }
ingo@1081: 
ingo@1081:         return obj;
ingo@1081:     }
ingo@617: }
ingo@617: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :