sascha@2382: package de.intevation.flys.model;
sascha@2382: 
sascha@2382: import java.util.Comparator;
sascha@2382: import java.util.ArrayList;
sascha@2382: import java.util.List;
sascha@2382: import java.util.Arrays;
sascha@2382: import java.util.HashMap;
sascha@2382: import java.util.Iterator;
sascha@2382: import java.util.NoSuchElementException;
sascha@2382: 
sascha@2382: import java.io.Serializable;
sascha@2382: 
sascha@2382: import org.hibernate.Session;
sascha@2382: import org.hibernate.SQLQuery;
sascha@2382: 
sascha@2382: import org.hibernate.type.StandardBasicTypes;
sascha@2382: 
sascha@2382: import de.intevation.flys.backend.SessionHolder;
sascha@2382: 
sascha@2382: public class FastAnnotations
sascha@2382: implements   Serializable
sascha@2382: {
sascha@2382:     public static final String SQL_BY_RIVER_NAME =
sascha@2382:         "SELECT r.a AS a, r.b AS b, p.value AS position, " +
sascha@2382:                 "at.value AS attribute, ant.name AS name, " +
sascha@2382:                 "e.top AS top, e.bottom AS bottom " +
sascha@2382:         "FROM annotations an " +
sascha@2382:             "JOIN ranges r " +
sascha@2382:                 "ON an.range_id = r.id " +
sascha@2382:             "JOIN attributes at " +
sascha@2382:                 "ON an.attribute_id = at.id " +
sascha@2382:             "JOIN positions p " +
sascha@2382:                 "ON an.position_id = p.id " +
sascha@2382:             "JOIN rivers riv " +
sascha@2382:                 "ON r.river_id = riv.id " +
sascha@2382:             "LEFT JOIN annotation_types ant " +
sascha@2382:                 "ON an.type_id = ant.id " +
sascha@2382:             "LEFT JOIN edges e " +
sascha@2382:                 "ON an.edge_id = e.id " +
sascha@2382:             "WHERE riv.name = :river_name " +
sascha@2382:                 "ORDER BY r.a";
sascha@2382: 
sascha@2382:     public static final String SQL_BY_RIVER_ID =
sascha@2382:         "SELECT r.a AS a, r.b AS b, p.value AS position, " +
sascha@2382:                 "at.value AS attribute, ant.name AS name, " +
sascha@2382:                 "e.top AS top, e.bottom AS bottom " +
sascha@2382:         "FROM annotations an " +
sascha@2382:             "JOIN ranges r " +
sascha@2382:                 "ON an.range_id = r.id " +
sascha@2382:             "JOIN attributes at " +
sascha@2382:                 "ON an.attribute_id = at.id " +
sascha@2382:             "JOIN positions p " +
sascha@2382:                 "ON an.position_id = p.id " +
sascha@2382:             "LEFT JOIN annotation_types ant " +
sascha@2382:                 "ON an.type_id = ant.id " +
sascha@2382:             "LEFT JOIN edges e " +
sascha@2382:                 "ON an.edge_id = e.id " +
sascha@2382:             "WHERE r.id = :river_id " +
sascha@2382:                 "ORDER BY r.a";
sascha@2382: 
sascha@2382:     public static final double EPSILON = 1e-5;
sascha@2382: 
sascha@2382:     public static final Comparator<Annotation> KM_CMP =
sascha@2382:         new Comparator<Annotation>() {
sascha@2382:             @Override
sascha@2382:             public int compare(Annotation a, Annotation b) {
sascha@2382:                 double diff = a.a - b.a;
sascha@2382:                 if (diff < -EPSILON) return -1;
sascha@2382:                 if (diff > +EPSILON) return +1;
sascha@2382:                 return 0;
sascha@2382:             }
sascha@2382:         };
sascha@2382: 
sascha@2382:     public static final class Annotation
sascha@2382:     implements                Serializable
sascha@2382:     {
sascha@2382:         private double a;
sascha@2382:         private double b;
sascha@2382:         private String position;
sascha@2382:         private String attribute;
sascha@2382:         private String name;
sascha@2382:         private double top;
sascha@2382:         private double bottom;
sascha@2382: 
sascha@2382:         public Annotation() {
sascha@2382:         }
sascha@2382: 
sascha@2382:         public Annotation(double a) {
sascha@2382:             this.a = a;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public Annotation(
sascha@2382:             double a,
sascha@2382:             double b,
sascha@2382:             String position,
sascha@2382:             String attribute,
sascha@2382:             String name,
sascha@2382:             double top,
sascha@2382:             double bottom
sascha@2382:         ) {
sascha@2382:             this.a         = a;
sascha@2382:             this.b         = b;
sascha@2382:             this.position  = position;
sascha@2382:             this.attribute = attribute;
sascha@2382:             this.name      = name;
sascha@2382:             this.top       = top;
sascha@2382:             this.bottom    = bottom;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public double getA() {
sascha@2382:             return a;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public double getB() {
sascha@2382:             return b;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public String getPosition() {
sascha@2382:             return position;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public String getAttribute() {
sascha@2382:             return attribute;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public String getName() {
sascha@2382:             return name;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public double getTop() {
sascha@2382:             return top;
sascha@2382:         }
sascha@2382: 
sascha@2382:         public double getBottom() {
sascha@2382:             return bottom;
sascha@2382:         }
sascha@3653: 
sascha@3653:         @Override
sascha@3653:         public String toString() {
sascha@3653:             return "[a=" + a + ";b=" + b +
sascha@3653:                 ";pos=" + position + ";attr=" + attribute +
sascha@3653:                 ";name=" + name + ";top=" + top +
sascha@3653:                 ";bot=" + bottom + "]";
sascha@3653:         }
felix@3323:     } // class Annotation
sascha@2382: 
sascha@2382:     public interface Filter {
sascha@2382: 
sascha@2382:         boolean accept(Annotation annotation);
sascha@2382: 
sascha@2382:     } // interface Filter
sascha@2382: 
sascha@3325:     public static class NameFilter implements Filter {
raimund@3324: 
raimund@3324:         private String name;
raimund@3324: 
sascha@3325:         public NameFilter(String name) {
raimund@3324:             this.name = name;
raimund@3324:         }
raimund@3324: 
sascha@3325:         @Override
sascha@3325:         public boolean accept(Annotation annotation) {
raimund@3324:             return annotation.getName().contains(name);
raimund@3324:         }
sascha@3325:     } // class NameFilter
raimund@3324: 
sascha@2382:     public static final Filter ALL = new Filter() {
sascha@2382:         @Override
sascha@2382:         public boolean accept(Annotation annotation) {
sascha@2382:             return true;
sascha@2382:         }
sascha@2382:     };
sascha@2382: 
sascha@2382:     public static final Filter IS_POINT = new Filter() {
sascha@2382:         @Override
sascha@2382:         public boolean accept(Annotation annotation) {
sascha@2382:             return Double.isNaN(annotation.getB());
sascha@2382:         }
sascha@2382:     };
sascha@2382: 
sascha@2382:     public static final Filter IS_RANGE = new Filter() {
sascha@2382:         @Override
sascha@2382:         public boolean accept(Annotation annotation) {
sascha@2382:             return !Double.isNaN(annotation.getB());
sascha@2382:         }
sascha@2382:     };
sascha@2382: 
sascha@2382:     private Annotation [] annotations;
sascha@2382: 
sascha@2382:     public FastAnnotations() {
sascha@2382:     }
sascha@2382: 
sascha@2382:     public FastAnnotations(Annotation [] annotations) {
sascha@2382:         this.annotations = annotations;
sascha@2382:     }
sascha@2382: 
sascha@2382:     public FastAnnotations(String riverName) {
sascha@2382:         this(loadByRiverName(riverName));
sascha@2382:     }
sascha@2382: 
sascha@2382:     public FastAnnotations(int riverId) {
sascha@2382:         this(loadByRiverId(riverId));
sascha@2382:     }
sascha@2382: 
sascha@2382:     public FastAnnotations(Iterator<Annotation> iter) {
sascha@2382:         this(toArray(iter));
sascha@2382:     }
sascha@2382: 
sascha@2382:     public int size() {
sascha@2382:         return annotations.length;
sascha@2382:     }
sascha@2382: 
sascha@2382:     public Iterator<Annotation> filter(final Filter filter) {
sascha@2382:         return new Iterator<Annotation>() {
sascha@2382: 
sascha@2382:             private int idx;
sascha@2382:             private Annotation current = findNext();
sascha@2382: 
sascha@3334:             @Override
sascha@2382:             public boolean hasNext() {
sascha@2382:                 return current != null;
sascha@2382:             }
sascha@2382: 
sascha@2382:             @Override
sascha@2382:             public Annotation next() {
sascha@2382:                 if (current == null) {
sascha@2382:                     throw new NoSuchElementException();
sascha@2382:                 }
sascha@2382:                 Annotation result = current;
sascha@2382:                 current = findNext();
sascha@2382:                 return result;
sascha@2382:             }
sascha@2382: 
sascha@2382:             private Annotation findNext() {
sascha@2382: 
sascha@2382:                 while (idx < annotations.length) {
sascha@2382:                     Annotation annotation = annotations[idx++];
sascha@2382:                     if (filter.accept(annotation)) {
sascha@2382:                         return annotation;
sascha@2382:                     }
sascha@2382:                 }
sascha@2382: 
sascha@2382:                 return null;
sascha@2382:             }
sascha@2382: 
sascha@2382:             @Override
sascha@2382:             public void remove() {
sascha@2382:                 throw new UnsupportedOperationException();
sascha@2382:             }
sascha@2382:         };
sascha@2382:     }
sascha@2382: 
sascha@2382:     public static Annotation [] toArray(Iterator<Annotation> iter) {
sascha@2382: 
sascha@2382:         ArrayList<Annotation> list = new ArrayList<Annotation>();
sascha@2382: 
sascha@2382:         while (iter.hasNext()) {
sascha@2382:             list.add(iter.next());
sascha@2382:         }
sascha@2382: 
sascha@2382:         return list.toArray(new Annotation[list.size()]);
sascha@2382:     }
sascha@2382: 
sascha@2382:     public Annotation findByKm(double km) {
sascha@2382:         Annotation key = new Annotation(km);
sascha@2382:         int idx = Arrays.binarySearch(annotations, key, KM_CMP);
sascha@2382:         return idx < 0 ? null : annotations[idx];
sascha@2382:     }
sascha@2382: 
sascha@2382:     private static SQLQuery createQuery(String query) {
sascha@2382:         Session session = SessionHolder.HOLDER.get();
sascha@2382: 
sascha@2382:         return session.createSQLQuery(query)
sascha@2382:             .addScalar("a",         StandardBasicTypes.DOUBLE)
sascha@2382:             .addScalar("b",         StandardBasicTypes.DOUBLE)
sascha@2382:             .addScalar("position",  StandardBasicTypes.STRING)
sascha@2382:             .addScalar("attribute", StandardBasicTypes.STRING)
sascha@2382:             .addScalar("name",      StandardBasicTypes.STRING)
sascha@2382:             .addScalar("top",       StandardBasicTypes.DOUBLE)
sascha@2382:             .addScalar("bottom",    StandardBasicTypes.DOUBLE);
sascha@2382:     }
sascha@2382: 
sascha@2382:     private static Annotation [] buildAnnotations(List<Object []> list) {
sascha@2382:         Annotation [] anns = new Annotation[list.size()];
sascha@2382: 
sascha@2382:         // Names are likely the same because they are a type
sascha@2382:         // like 'Pegel' or 'Hafen'.
sascha@2382:         HashMap<String, String> names = new HashMap<String, String>();
sascha@2382: 
sascha@2382:         for (int i = 0; i < anns.length; ++i) {
sascha@2382:             Object [] data   = list.get(i);
sascha@2382:             double a         = ((Double)data[0]);
sascha@2382:             double b         = data[1] != null ? (Double)data[1] : Double.NaN;
sascha@2382:             String position  = (String)data[2];
sascha@2382:             String attribute = (String)data[3];
sascha@2382:             String name      = (String)data[4];
sascha@2382:             double top       = data[5] != null ? (Double)data[5] : Double.NaN;
sascha@2382:             double bottom    = data[6] != null ? (Double)data[6] : Double.NaN;
sascha@2382: 
sascha@2382:             if (name != null) {
sascha@2382:                 String old = names.get(name);
sascha@2382:                 if (old != null) {
sascha@2382:                     name = old;
sascha@2382:                 }
sascha@2382:                 else {
sascha@2382:                     names.put(name, name);
sascha@2382:                 }
sascha@2382:             }
sascha@2382: 
sascha@2382:             anns[i] = new Annotation(
sascha@2382:                 a, b, position, attribute, name, top, bottom);
sascha@2382:         }
sascha@2382: 
sascha@2382:         return anns;
sascha@2382:     }
sascha@2382: 
sascha@2382:     public static Annotation [] loadByRiverName(String riverName) {
sascha@2382: 
sascha@2382:         SQLQuery query = createQuery(SQL_BY_RIVER_NAME);
sascha@2382: 
sascha@2382:         query.setString("river_name", riverName);
sascha@2382: 
sascha@2382:         return buildAnnotations(query.list());
sascha@2382:     }
sascha@2382: 
sascha@2382:     public static Annotation [] loadByRiverId(int riverId) {
sascha@2382: 
sascha@2382:         SQLQuery query = createQuery(SQL_BY_RIVER_ID);
sascha@2382: 
sascha@2382:         query.setInteger("river_id", riverId);
sascha@2382: 
sascha@2382:         return buildAnnotations(query.list());
sascha@2382:     }
sascha@2382: }
sascha@2382: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :