/**
 * Copyright (C) 2010-14 pvmanager developers. See COPYRIGHT.TXT
 * All rights reserved. Use is subject to license terms. See LICENSE.TXT
 */
package org.epics.pvmanager.vtype;

import org.epics.vtype.Time;
import java.util.*;
import org.epics.pvmanager.Collector;
import org.epics.pvmanager.ReadFunction;
import org.epics.util.time.TimeDuration;
import org.epics.util.time.TimeInterval;

/**
 *
 * @author carcassi
 */
class TimedCacheCollector<T extends Time> implements Collector<T, List<T>> {

    private final Deque<T> buffer = new ArrayDeque<T>();
    private final ReadFunction<T> function;
    private final TimeDuration cachedPeriod;
    
    public TimedCacheCollector(ReadFunction<T> function, TimeDuration cachedPeriod) {
        this.function = function;
        this.cachedPeriod = cachedPeriod;
    }

    @Override
    public void writeValue(T newValue) {
        // Buffer is locked and updated
        if (newValue != null) {
            synchronized(buffer) {
                buffer.add(newValue);
                prune();
            }
        }
    }

    /**
     * Returns all values since last check and removes values from the queue.
     * @return a new array with the value; never null
     */
    @Override
    public List<T> readValue() {
        synchronized(buffer) {
            if (buffer.isEmpty())
                return Collections.emptyList();

            return new ArrayList<T>(buffer);
        }
    }
    
    private void prune() {
        // Remove all values that are too old
        TimeInterval periodAllowed = cachedPeriod.before(buffer.getLast().getTimestamp());
        while (!buffer.isEmpty() && !periodAllowed.contains(buffer.getFirst().getTimestamp())) {
            // Discard value
            buffer.removeFirst();
        }
    }

}

@@ -641,21 +641,56 @@
 Period;%0A
+    private Runnable notification;%0A
     %0A
-
     publ
@@ -846,24 +846,196 @@
 iod;%0A    %7D%0A%0A
+    @Override%0A    public void setChangeNotification(Runnable notification) %7B%0A        synchronized (buffer) %7B%0A            this.notification = notification;%0A        %7D%0A    %7D%0A%0A
     @Overrid
@@ -1073,24 +1073,47 @@
 newValue) %7B%0A
+        Runnable task;%0A
         // B
@@ -1245,16 +1245,16 @@
 Value);%0A
-
         
@@ -1266,24 +1266,188 @@
    prune();%0A
+                task = notification;%0A            %7D%0A            // Run the task without holding the lock%0A            if (task != null) %7B%0A                task.run();%0A
             

update to current SNAPSHOT