view artifacts/src/main/java/org/dive4elements/river/artifacts/model/OfficialLineFinder.java @ 6395:d2803cc7a338

Artifacts: Official lines: Only apply in Q-Calculations and filter against the ranges of the gauges.
author Sascha L. Teichmann <teichmann@intevation.de>
date Fri, 21 Jun 2013 16:28:47 +0200
parents ef08c4f57ede
children f579e4a80b84
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.artifacts.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.dive4elements.river.artifacts.D4EArtifact;
import org.dive4elements.river.artifacts.cache.CacheFactory;
import org.dive4elements.river.model.Gauge;
import org.dive4elements.river.model.MainValue;
import org.dive4elements.river.model.NamedMainValue;
import org.dive4elements.river.model.OfficialLine;
import org.dive4elements.river.model.River;
import org.dive4elements.river.model.Wst;
import org.dive4elements.river.model.WstColumn;

public class OfficialLineFinder
{
    public static final String CACHE_NAME = "official-lines";

    // We will only have one entry in this cache.
    public static final String CACHE_KEY = CACHE_NAME;

    public static final double EPSILON = 1e-4;


    public static class ValueRange extends Range {

        private double value;
        private int    wstId;
        private int    columnPos;

        public ValueRange(
            double start,
            double end, 
            double value,
            int    wstId,
            int    columnPos
        ) {
            super(start, end);
            this.value     = value;
            this.wstId     = wstId;
            this.columnPos = columnPos;
        }

        public boolean sameValue(double value) {
            return Math.abs(value - this.value) < EPSILON;
        }

        public int getWstId() {
            return wstId;
        }

        public int getColumnPos() {
            return columnPos;
        }
    }

    public OfficialLineFinder() {
    }

    public static Map<String, List<ValueRange>> getAll() {
        Cache cache = CacheFactory.getCache(CACHE_NAME);

        if (cache == null) {
            return getAllUncached();
        }

        Element element  = cache.get(CACHE_KEY);

        if (element != null) {
            return (Map<String, List<ValueRange>>)element.getValue();
        }

        Map<String, List<ValueRange>> result = getAllUncached();
        if (result != null) {
            cache.put(new Element(CACHE_KEY, result));
        }
        return result;

    }

    public static Map<String, List<ValueRange>> getAllUncached() {

        Map<String, List<ValueRange>> rivers2officialLines =
            new HashMap<String, List<ValueRange>>();


        for (OfficialLine line: OfficialLine.fetchAllOfficalLines()) {
            String   name = line.getNamedMainValue().getName();
            WstColumn wc  = line.getWstColumn();
            Wst       wst = wc.getWst();

            List<ValueRange> ranges = new ArrayList<ValueRange>();

            River river = wst.getRiver();
            List<Gauge> gauges = river.getGauges();
            for (Gauge gauge: gauges) {
                List<MainValue> mainValues = gauge.getMainValues();
                for (MainValue mainValue: mainValues) {
                    NamedMainValue nmv = mainValue.getMainValue();
                    if (nmv.getName().equalsIgnoreCase(name)) {
                        // found gauge with this main value

                        double from = gauge.getRange().getA().doubleValue();
                        double to   = gauge.getRange().getA().doubleValue();
                        double value = mainValue.getValue().doubleValue();
                        int    wstId = wst.getId();
                        int    pos   = wc.getPosition();
                        ValueRange range =
                            new ValueRange(from, to, value, wstId, pos);
                        ranges.add(range);
                        break;
                    }
                }
            }

            if (!ranges.isEmpty()) {
                rivers2officialLines.put(river.getName(), ranges);
            }
        }

        return rivers2officialLines;
    }

    public static final Range MAX_RANGE = new Range(-Double.MAX_VALUE, +Double.MAX_VALUE);

    private static final String nn(String s) {
        return s != null ? s : "";
    }

    public static Range extractRange(D4EArtifact artifact) {
        String mode      = nn(artifact.getDataAsString("ld_mode"));
        String locations = nn(artifact.getDataAsString("ld_locations"));
        String from      = nn(artifact.getDataAsString("ld_from"));
        String to        = nn(artifact.getDataAsString("ld_to"));

        if (mode.equals("location")) {
            try {
                String loc = locations.replace(" ", "");
                String[] split = loc.split(",");
                if (split.length < 1) {
                    return MAX_RANGE;
                }
                double min = Double.parseDouble(split[0]);
                double max = min;
                for (int i = 1; i < split.length; ++i) {
                    double v = Double.parseDouble(split[i]);
                    if (v > max) max = v;
                    if (v < min) min = v;
                }
                return new Range(min, max);
            }
            catch (NumberFormatException nfe) {
                return MAX_RANGE;
            }
        }
        try {
            return new Range(Double.parseDouble(from), Double.parseDouble(to));
        }
        catch (NumberFormatException nfe) {
            return MAX_RANGE;
        }
    }

    private static List<ValueRange> filterByRange(Range range, List<ValueRange> ranges) {
        List<ValueRange> list = new ArrayList<ValueRange>(ranges.size());
        for (ValueRange r: ranges) {
            if (r.intersects(range)) {
                list.add(r);
            }
        }
        return list;
    }

    private static boolean isQ(D4EArtifact artifact) {
        Boolean b = artifact.getDataAsBoolean("wq_isq");
        return b != null && b;
    }

    public static List<OfficialLine> findOfficialLines(D4EArtifact artifact) {

        if (!isQ(artifact)) { // Only handle Q calculations
            return Collections.<OfficialLine>emptyList();
        }

        Map<String, List<ValueRange>> rivers2officialLines = getAll();

        String riverName = nn(artifact.getDataAsString("river"));

        List<ValueRange> ranges = rivers2officialLines.get(riverName);

        if (ranges == null) {
            return Collections.<OfficialLine>emptyList();
        }

        ranges = filterByRange(extractRange(artifact), ranges);

        if (ranges.isEmpty()) {
            return Collections.<OfficialLine>emptyList();
        }


        // TODO: Figure out all the cases here.

        return Collections.<OfficialLine>emptyList();
    }
}

http://dive4elements.wald.intevation.org