package org.helioviewer.jhv.data.container;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.helioviewer.jhv.data.container.cache.JHVEventCache;
import org.helioviewer.jhv.data.container.cache.JHVEventHandlerCache;
import org.helioviewer.jhv.data.datatype.JHVEvent;
import org.helioviewer.jhv.data.lock.JHVEventContainerLocks;

public class JHVEventContainer {

    /** Singleton instance */
    private static JHVEventContainer singletonInstance;

    /** The handlers of requests */
    private final List<JHVEventContainerRequestHandler> handlers;

    /** the event cache */
    private final JHVEventCache eventCache;

    /** the event handler cache */
    private final JHVEventHandlerCache eventHandlerCache;

    /**
     * Private constructor.
     */
    private JHVEventContainer() {
        handlers = new ArrayList<JHVEventContainerRequestHandler>();
        eventHandlerCache = JHVEventHandlerCache.getSingletonInstance();
        eventCache = JHVEventCache.getSingletonInstance();
    }

    /**
     * Gets the singleton instance of the JHVEventContainer
     * 
     * @return the singleton instance
     */
    public static JHVEventContainer getSingletonInstance() {
        if (singletonInstance == null) {
            singletonInstance = new JHVEventContainer();
        }
        return singletonInstance;
    }

    /**
     * Register a JHV event container request handler.
     * 
     * @param handler
     *            the handler to register
     */
    public void registerHandler(JHVEventContainerRequestHandler handler) {
        handlers.add(handler);
    }

    /**
     * Removes the JHV event container request handler.
     * 
     * @param handler
     *            the handler to remove
     */
    public void removeHandler(JHVEventContainerRequestHandler handler) {
        handlers.remove(handler);
    }

    /**
     * Request the JHVEventContainer for events from a specific date. The events
     * will be send to the given handler. Events already available will directly
     * be send to the handler. Events becoming available will also be send to
     * the handler in the future.
     * 
     * @param date
     *            the date to send events for
     * @param handler
     *            the handler to send events to
     */
    public void requestForDate(Date date, JHVEventHandler handler) {
        synchronized (JHVEventContainerLocks.dateLock) {
            eventHandlerCache.add(handler, date);
            List<JHVEvent> events = eventCache.get(date);
            handler.newEventsReceived(events);
        }
    }

    /**
     * Request the JHVEventContainer for events from a specific list of dates.
     * The events will be send to the given handler. Events already available
     * will directly be send to the handler. Events becoming available will also
     * be send to the handler in the future.
     * 
     * @param dateList
     *            the list of dates to send events for
     * @param handler
     *            the handler to send events to
     */
    public void requestForDateList(List<Date> dateList, JHVEventHandler handler) {
        synchronized (JHVEventContainerLocks.dateLock) {
            for (Date date : dateList) {
                requestForDate(date, handler);
            }
        }
    }

    /**
     * Request the JHVEventContainer for events from a specific time interval.
     * The events will be send to the given handler. Events already available
     * will directly be send to the handler. Events becoming available will also
     * be send to the handler in the future.
     * 
     * @param startDate
     *            the start date of the interval
     * @param endDate
     *            the end date of the interval
     * @param handler
     *            the handler
     */
    public void requestForInterval(Date startDate, Date endDate, JHVEventHandler handler) {
        synchronized (JHVEventContainerLocks.intervalLock) {
            eventHandlerCache.add(handler, startDate, endDate);
            List<JHVEvent> events = eventCache.get(startDate, endDate);
            handler.newEventsReceived(events);
        }
    }
}

@@ -572,17 +572,24 @@
 andler%3E 
-h
+requestH
 andlers;
@@ -838,25 +838,32 @@
 ) %7B%0A        
-h
+requestH
 andlers = ne
@@ -1444,32 +1444,40 @@
 andler.%0A     * %0A
+     * %0A
      * @param ha
@@ -1607,33 +1607,111 @@
 dler) %7B%0A        
-h
+synchronized (JHVEventContainerLocks.requestHandlerLock) %7B%0A            requestH
 andlers.add(hand
@@ -1708,32 +1708,42 @@
 s.add(handler);%0A
+        %7D%0A
     %7D%0A%0A    /**%0A 
@@ -1952,25 +1952,103 @@
 ) %7B%0A        
-h
+synchronized (JHVEventContainerLocks.requestHandlerLock) %7B%0A            requestH
 andlers.remo
@@ -2056,24 +2056,34 @@
 e(handler);%0A
+        %7D%0A
     %7D%0A%0A    /
@@ -2783,32 +2783,65 @@
 ceived(events);%0A
+            requestEvents(date);%0A
         %7D%0A    %7D%0A
@@ -4337,32 +4337,32 @@
 Date, endDate);%0A
-
             hand
@@ -4384,32 +4384,1038 @@
 ceived(events);%0A
+            requestEvents(startDate, endDate);%0A        %7D%0A    %7D%0A%0A    /**%0A     * Request data from the request handlers for a date.%0A     * %0A     * @param date%0A     *            the date for which to request the data%0A     */%0A    private void requestEvents(Date date) %7B%0A        synchronized (JHVEventContainerLocks.requestHandlerLock) %7B%0A            for (JHVEventContainerRequestHandler handler : requestHandlers) %7B%0A                handler.handleRequestForDate(date);%0A            %7D%0A        %7D%0A    %7D%0A%0A    /**%0A     * Request data from the request handlers over an interval.%0A     * %0A     * @param startDate%0A     *            the start of the interval%0A     * @param endDate%0A     *            the end of the interval%0A     */%0A    private void requestEvents(Date startDate, Date endDate) %7B%0A        synchronized (JHVEventContainerLocks.requestHandlerLock) %7B%0A            for (JHVEventContainerRequestHandler handler : requestHandlers) %7B%0A                handler.handleRequestForInterval(startDate, endDate);%0A            %7D%0A
         %7D%0A    %7D%0A

Send requests to the request handlers