Package com.vaadin.addon.timeline.gwt.client

Source Code of com.vaadin.addon.timeline.gwt.client.VClientCache$DataRange

package com.vaadin.addon.timeline.gwt.client;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Timer;

public class VClientCache implements VDataListener{

    /**
     * A data point in time
     */
    public static class DataPoint implements Comparable<DataPoint> {
        private final Float value;
        private final Long date;

        /**
         * Constructor
         * @param date
         *     The date of the point
         * @param value
         *     The value of the point
         */
        public DataPoint(Date date, Float value){
            this.value = value;
            this.date = date.getTime();
        }

        /**
         * The value of the point
         * @return
         *     The value
         */
        public Float getValue(){
            return value;
        }

        /**
         * The date of the point
         * @return
         *     The date
         */
        public Date getDate(){
            return new Date(date);
        }

        public Long getTime(){
            return date;
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Comparable#compareTo(java.lang.Object)
         */
        @Override
        public int compareTo(DataPoint o) {
            return date.compareTo(o.getTime());
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object o){
            if(o instanceof DataPoint){
                DataPoint dp = (DataPoint)o;
                return date.equals(dp.getTime());
            } else {
                return false;
            }
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode(){
            return date.hashCode();
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString(){
            return Long.toString(date);
        }
    }

    /**
     * A range of points sorted by time
     */
    public static class DataRange implements Comparable<DataRange> {
        private final Long from;
        private final Long to;
        private final List<DataPoint> points;
        private final Set<String> markers;
        private final Set<String> events;
        private DataPoint minimum;
        private DataPoint maximum;

        /**
         * Constructor
         * @param from
         *     Date that range starts
         * @param to
         *     Date the range ends
         * @param values
         *     The values in the range (must have the same size as the dates)
         * @param dates
         *     The dates in the range (must have the same size as the values)
         * @param markers
         *     The markers in the range
         * @param events
         *     The events in the range
         */
        public DataRange(Date from, Date to, List<Float> values, List<Date> dates, Set<String> markers, Set<String> events){
            this.from = from.getTime();
            this.to = to.getTime();

            points = new ArrayList<DataPoint>();
            for(int i=0;i<dates.size(); i++){

                // Create data point
                DataPoint dp = new DataPoint(dates.get(i), values.get(i));

                // Calculate minimum
                if(minimum == null || minimum.getValue() > dp.getValue()) {
                    minimum = dp;
                }

                // Calculate maximum
                if(maximum == null || maximum.getValue() < dp.getValue()) {
                    maximum = dp;
                }

                // Add the point
                points.add(dp);
            }

            // Add markers and events
            this.markers = markers;
            this.events = events;
        }

        /**
         * Constructor
         * @param from
         *     Date that range starts
         * @param to
         *     Date the range ends
         * @param points
         *     The data points in the range
         * @param markers
         *     The markers in the range
         * @param events
         *     The events in the range
         * @param min
         *     The minimum value in the range
         * @param max
         *     The maximum value in the range
         */
        public DataRange(Date from, Date to, List<DataPoint> points, Set<String> markers, Set<String> events, DataPoint min, DataPoint max){
            this.from = from.getTime();
            this.to = to.getTime();
            this.points = points;
            this.markers = markers;
            this.events = events;
            minimum = min;
            maximum = max;
        }

        /**
         * Checks if a date is in the range
         * @param date
         *     The date to check
         * @return
         *     Returns true if date is in range, else false
         */
        public boolean inRange(Date date){
            Long time = date.getTime();
            return time >= from && time <= to;
        }

        /**
         * Gets the points from the range
         * @return
         *     Returns the points as a list of datapoints
         */
        public List<DataPoint> getPoints(){
            return points;
        }

        /**
         * Gets the markers in the range
         * @return
         *     Returns the markers as a set of strings
         */
        public Set<String> getMarkers(){
            return markers;
        }

        /**
         * Gets the events in the range
         * @return
         *     Returns the events as a set of strings
         */
        public Set<String> getEvents(){
            return events;
        }

        /**
         * Gets the starting time of the range
         * @return
         *     The starting time as Long
         */
        public Long getStartTime(){
            return from;
        }

        /**
         * Gets the ending time of the range
         * @return
         *     The ending time
         */
        public Long getEndTime(){
            return to;
        }

        /**
         * Gets the minimum value of the range
         * @return
         *     The minimum data point
         */
        public DataPoint getMinimum(){
            return minimum;
        }

        /**
         * Gets the maximum value of the range
         * @return
         *     Them maximum data point
         */
        public DataPoint getMaximum(){
            return maximum;
        }

        /*
         * (non-Javadoc)
         * @see java.lang.Comparable#compareTo(java.lang.Object)
         */
        @Override
        public int compareTo(DataRange o) {
            Date start = new Date(o.getStartTime());
            Date end = new Date(o.getEndTime());

            if (inRange(start) || inRange(end)) {
                return 0;
            }

            if(o.getStartTime() > to) {
                return -1;
            }

            return 1;
        }

        /*
         * (non-Javadoc)
         *
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }

            if (o instanceof DataRange) {
                DataRange r = (DataRange) o;
                Date start = new Date(r.getStartTime());
                Date end = new Date(r.getEndTime());
                if (inRange(start) || inRange(end)) {
                    return true;
                }
            }

            return false;
        }

        /*
         * (non-Javadoc)
         *
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            return from.hashCode() + to.hashCode();
        }

        /*
         * (non-Javadoc)
         *
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString(){
            DateTimeFormat formatter = DateTimeFormat.getShortDateFormat();
            Date f = new Date(from);
            Date t = new Date(to);
            return "Datarange: "+formatter.format(f)+" - "+formatter.format(t)+", points="+points.size()+",max="+maximum.getValue()+", min="+minimum.getValue();
        }
    }

    /**
     * The loading timer to for executing background loading
     */
    private class LoadingTimer extends Timer{

        private final VTimelineWidget widget;
        private final VClientCache cache;

        public LoadingTimer(VTimelineWidget widget, VClientCache cache){
            super();
            this.widget = widget;
            this.cache = cache;
        }

        /*
         * (non-Javadoc)
         * @see com.google.gwt.user.client.Timer#run()
         */
        @Override
        public void run() {
            if(widget.isIdle() && !waitingForCache && widget.getNumGraphs() > 0){
                for(int g=0; g<widget.getNumGraphs(); g++){
                    widget.getDateData(cache, g, currentLoadingStart, currentLoadingEnd, 1);
                }
                widget.getFromServer();
                waitingForCache = true;
            }
        }
    }

    // Graph - Data range map
    private final Map<Integer, List<DataRange>> dataCache;

    // The main widget
    private final VTimelineWidget widget;

    // Background loader variables
    private LoadingTimer loadingTimer;
    private Date currentLoadingStart;
    private Date currentLoadingEnd;
    private final Map<Long, Integer> requestMap = new HashMap<Long, Integer>();
    private boolean waitingForCache = false;
    private int percentCounter = 0;

    public VClientCache(VTimelineWidget widget, boolean enableBackgroundLoading){
        dataCache = new HashMap<Integer, List<DataRange>>();
        this.widget = widget;

        if(enableBackgroundLoading && widget.usePreloading()){
            Long timeDiff = widget.getEndDate().getTime() - widget.getStartDate().getTime();
            Float loadUnit = timeDiff.floatValue() / 100f;

            currentLoadingEnd = widget.getEndDate();
            currentLoadingStart = new Date(widget.getEndDate().getTime()-loadUnit.longValue());

            loadingTimer = new LoadingTimer(widget, this);
            loadingTimer.scheduleRepeating(1000);
        }
    }

    /**
     * Get a date range by start and end dates.
     * Note: A range with different start and end dates might be returned!
     *
     * @param graph
     *     The graph of the range
     * @param from
     *     The start date of the range
     * @param to
     *     The end date of the range
     * @return
     *     A date range
     */
    private DataRange getRange(Integer graph, Date from, Date to){
        List<DataRange> ranges = dataCache.get(graph);

        if(ranges == null) {
            return null;
        }

        for(DataRange r : ranges){
            if(r.inRange(from) || r.inRange(to)) {
                return r;
            }
        }

        return null;
    }

    /**
     * Merge two overlapping date ranges into one
     * @param graph
     *     The graph of the ranges
     * @param r1
     *     The first date range
     * @param r2
     *     The second date range
     */
    private void merge(Integer graph, DataRange r1, DataRange r2){
        List<DataRange> ranges = dataCache.get(graph);
        if(ranges == null) {
            return;
        }

        // Remove both ranges from the cache
        if(ranges.contains(r1)){
            ranges.remove(r1);
        }

        if(ranges.contains(r2)){
            ranges.remove(r2);
        }

        // Calculate new from and to times
        Date from = r1.getStartTime() > r2.getStartTime() ? new Date(r2.getStartTime()) : new Date(r1.getStartTime());
        Date to = r1.getEndTime() > r2.getEndTime() ? new Date(r1.getEndTime()) : new Date(r2.getEndTime());

        // Add markers
        Set<String> markers = new HashSet<String>();
        if(r1.getMarkers() != null) {
            markers.addAll(r1.getMarkers());
        }
        if(r2.getMarkers() != null) {
            markers.addAll(r2.getMarkers());
        }

        // Add events
        Set<String> events = new HashSet<String>();
        if(r1.getEvents() != null) {
            events.addAll(r1.getEvents());
        }
        if(r2.getEvents() != null) {
            events.addAll(r2.getEvents());
        }

        // Add all points, skip duplicates
        Set<DataPoint> uniquePoints = new HashSet<DataPoint>();
        if(r1.getPoints() != null) {
            uniquePoints.addAll(r1.getPoints());
        }
        if(r2.getPoints() != null) {
            uniquePoints.addAll(r2.getPoints());
        }

        // Sort the points
        List<DataPoint> points = new ArrayList<DataPoint>(uniquePoints);
        Collections.sort(points);

        // Get minimum and maximum
        DataPoint min=null, max=null;
        for(DataPoint p : points){
            if(min == null || min.getValue() > p.getValue()) {
                min = p;
            }
            if(max == null || max.getValue() < p.getValue()) {
                max = p;
            }
        }

        // Create a new Data range
        DataRange range = new DataRange(from, to, points, markers, events, min, max);
        ranges.add(range);
    }

    /**
     * Add data points to cache
     * @param graph
     *     The graph index
     * @param from
     *     THe from date
     * @param to
     *     The to date
     * @param values
     *     The values
     * @param dates
     *     The dates
     * @param markers
     *     The markers
     * @param events
     *     THe events
     */
    public void addToCache(Integer graph, Date from, Date to, List<Float> values, List<Date> dates, Set<String> markers, Set<String> events){

        List<DataRange> ranges = dataCache.get(graph);
        if(ranges == null){
            ranges = new LinkedList<DataRange>();
            dataCache.put(graph, ranges);
        }

        // Check if we have an mergable data range
        DataRange range = getRange(graph, from, to);

        //No existing range was found, so creating a new one
        if(range == null){
            range = new DataRange(from, to, values, dates, markers, events);
            ranges.add(range);
        }

        // Else merge the ranges
        else {
            merge(graph, range, new DataRange(from, to, values, dates, markers, events));
        }
    }

    /**
     * Get graph data points from cache
     * @param graph
     *     The graph index number
     * @param from
     *     The start date
     * @param to
     *     The end date
     * @return
     *     Returns an object array with 4 values, the dates, the values,
     *     the markers and the events. If the range was not found in cache
     *     null is returned.
     */
    public Object[] getFromCache(Integer graph, Date from, Date to) {
        if (graph == null || from == null || to == null) {
            return null;
        }

        List<DataRange> ranges = dataCache.get(graph);
        if (ranges == null) {
            return null;
        }


        for (DataRange dr : ranges) {
            if ((dr.inRange(from) && dr.inRange(to))
                    || (dr.inRange(from)
                            && to.getTime() > widget.getEndDate().getTime() && dr
                            .getEndTime() == widget.getEndDate().getTime())
                            || (dr.inRange(to)
                                    && from.getTime() < widget.getStartDate().getTime() && dr
                                    .getStartTime() == widget.getStartDate().getTime())) {
                List<Float> values = new LinkedList<Float>();
                List<Date> dates = new LinkedList<Date>();
                Set<String> markers = new HashSet<String>();
                Set<String> events = new HashSet<String>();

                // Approximate the first index
                Long totalDiffTime = dr.getEndTime() - dr.getStartTime();
                Float pointSize = new Float(dr.getPoints().size());
                Float sizeRatio = pointSize / totalDiffTime.floatValue();
                Long startDiffTime = from.getTime() - dr.getStartTime();

                // Since we are approximating reduce the start point with 1/3 so
                // we definitly start
                // searching for the points outside the range
                Float startPoint = (startDiffTime.floatValue() * sizeRatio) / 3F;

                // Find the real first point index
                int firstPointIndex = startPoint.intValue();
                for (int d = startPoint.intValue(); d < dr.getPoints().size(); d++) {
                    Date date = dr.getPoints().get(d).getDate();
                    if (date.after(from) && date.before(to)) {
                        firstPointIndex = d > 0 ? d - 1 : 0; // Reducing 1 for
                        // rendering
                        // purposes if
                        // possible
                        break;
                    }
                }

                // Approximate the last index
                Long endDiffTime = dr.getEndTime() - to.getTime();

                // Since we are approximating increase the end point so we
                // definitly start
                // searching for the points outsize the range
                Float endPoint = pointSize - endDiffTime.floatValue()
                * sizeRatio;
                endPoint += (endPoint - startPoint);

                // Boundary checl
                if (endPoint >= pointSize) {
                    endPoint = pointSize - 1F;
                }


                // Find the real last point index
                int lastPointIndex = endPoint.intValue();

                if (to.getTime() <= widget.getEndDate().getTime()) {
                    for (int d = endPoint.intValue(); d > startPoint.intValue(); d--) {
                        Date date = dr.getPoints().get(d).getDate();

                        if (date.after(from) && date.before(to)) {
                            if (d == dr.getPoints().size() - 1) {
                                lastPointIndex = d;
                            } else {
                                lastPointIndex = d + 1; // Adding 1 for
                            }
                            // rendering purposes
                            // Last point found
                            break;
                        }
                    }
                }

                // Add the subset
                for (int i = firstPointIndex; i <= lastPointIndex; i++) {
                    if (i >= 0 && i < dr.getPoints().size()) {
                        DataPoint dp = dr.getPoints().get(i);
                        dates.add(dp.getDate());
                        values.add(dp.getValue());
                    }
                }

                // Get the markers
                if (dr.getMarkers() != null) {
                    for (String markerStr : dr.getMarkers()) {
                        String[] params = markerStr.split("_");
                        Long time = Long.parseLong(params[0]);
                        if (time >= dr.getStartTime()
                                && time <= dr.getEndTime()) {
                            markers.add(markerStr);
                        }
                    }
                }

                // Get the events
                if (dr.getEvents() != null) {
                    for (String eventStr : dr.getEvents()) {
                        String[] params = eventStr.split("_");
                        Long time = Long.parseLong(params[0]);
                        if (time >= dr.getStartTime()
                                && time <= dr.getEndTime()) {
                            events.add(eventStr);
                        }
                    }
                }

                // Get the minumum and maximum indexes
                int minIndex = dr.getPoints().indexOf(dr.getMinimum());
                int maxIndex = dr.getPoints().indexOf(dr.getMaximum());

                // Set minimum value
                Float min = null;
                if (minIndex >= firstPointIndex && minIndex <= lastPointIndex) {
                    min = dr.getMinimum().getValue();
                } else {
                    min = new Float(VTimelineWidget.getMinValue(values));
                }

                // Set maximum value
                Float max = null;
                if (maxIndex >= firstPointIndex && maxIndex <= lastPointIndex) {
                    max = dr.getMaximum().getValue();
                } else {
                    max = new Float(VTimelineWidget.getMaxValue(values));
                }

                return new Object[] { values, dates, markers, events, min, max };
            }
        }

        return null;
    }

    /*
     * (non-Javadoc)
     * @see com.vaadin.trends.ws.client.VDataListener#dataRecieved(java.lang.Long, java.util.List, java.util.List, java.util.Set, java.util.Set)
     */
    @Override
    public void dataRecieved(Long requestID, List<Float> values,
            List<Date> dates, Set<String> markers, Set<String> events) {
        int graph = requestMap.get(requestID);
        addToCache(graph, currentLoadingStart, currentLoadingEnd, values, dates, markers, events);
        requestMap.remove(requestID);

        if(requestMap.isEmpty()){
            waitingForCache = false;

            Long timeDiff = widget.getEndDate().getTime() - widget.getStartDate().getTime();
            Float loadUnit = timeDiff.floatValue() / 100f;
            currentLoadingEnd = currentLoadingStart;
            currentLoadingStart = new Date(currentLoadingEnd.getTime()-loadUnit.longValue());
            percentCounter++;
            widget.setPreloadingPercent(percentCounter);

            // If everything is loaded then stop the timer
            if(currentLoadingEnd.before(widget.getStartDate()) || !widget.usePreloading()){
                loadingTimer.cancel();
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see com.vaadin.trends.ws.client.VDataListener#dataRecievedAll(java.util.List, java.util.Map, java.util.Map, java.util.Set, java.util.Set, java.util.Map, java.util.Map)
     */
    @Override
    public void dataRecievedAll(List<Long> requestID,
            Map<Integer, List<Float>> values, Map<Integer, List<Date>> dates,
            Set<String> markers, Set<String> events, Map<Integer, Float> min,
            Map<Integer, Float> max, Float totalMinumum, Float totalMaximum) {
        // This should never be called since all data is recieved from the server.
    }

    /*
     * (non-Javadoc)
     * @see com.vaadin.trends.ws.client.VDataListener#setCurrentRequestId(java.lang.Long, int)
     */
    @Override
    public void setCurrentRequestId(Long requestID, Integer graphIndex) {
        requestMap.put(requestID, graphIndex);
    }

    /**
     * Stop the preloading
     */
    public void stopPreloading(){
        if(loadingTimer != null) {
            loadingTimer.cancel();
        }
    }

}
TOP

Related Classes of com.vaadin.addon.timeline.gwt.client.VClientCache$DataRange

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.