package org.helioviewer.jhv.display;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.Timer;

import org.helioviewer.jhv.layers.LayersModel;
import org.helioviewer.jhv.gui.components.layerTable.LayerTableModel;
import org.helioviewer.jhv.gui.components.MoviePanel;
import org.helioviewer.jhv.gui.components.statusplugins.FramerateStatusPanel;
import org.helioviewer.viewmodel.view.jp2view.JHVJP2View;
import org.helioviewer.viewmodel.view.jp2view.datetime.ImmutableDateTime;

import org.helioviewer.jhv.data.datatype.event.JHVEvent;
import org.helioviewer.jhv.data.datatype.event.JHVEventHighlightListener;
import org.helioviewer.jhv.plugin.renderable.RenderableContainer;
import org.helioviewer.jhv.plugin.renderable.RenderableContainerPanel;

public class Displayer implements JHVEventHighlightListener {

    private static final Displayer instance = new Displayer();
    private static final RenderableContainer renderableContainer = new RenderableContainer();
    private static final RenderableContainerPanel renderableContainerPanel = new RenderableContainerPanel(renderableContainer);

    public static Displayer getSingletonInstance() {
        return instance;
    }

    private static final ArrayList<DisplayListener> listeners = new ArrayList<DisplayListener>();
    private static final ArrayList<RenderListener> renderListeners = new ArrayList<RenderListener>();
    private static final ArrayList<TimeListener> timeListeners = new ArrayList<TimeListener>();
    private static Date lastTimestamp;

    private static boolean torender = false;
    private static boolean todisplay = false;
    private final MyListener timerListener = new MyListener();

    private static LayersModel layersModel;
    private static LayerTableModel tableModel;

    private Displayer() {
        layersModel = LayersModel.getSingletonInstance();
        tableModel = LayerTableModel.getSingletonInstance();

        Timer timer = new Timer(1000 / 20, timerListener);
        timer.start();
    }

    public static void render() {
        torender = true;
    }

    public static void display() {
        todisplay = true;
    }

    private class MyListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (todisplay == true) {
                todisplay = false;
                for (final DisplayListener listener : listeners) {
                    listener.display();
                }
            }

            if (torender == true) {
                torender = false;
                for (final RenderListener renderListener : renderListeners) {
                    renderListener.render();
                }
            }
        }
    }

    public static void addListener(final DisplayListener listener) {
        listeners.add(listener);
    }

    public static void removeListener(final DisplayListener listener) {
        listeners.remove(listener);
    }

    public static void removeListeners() {
        listeners.clear();
    }

    public static void addRenderListener(final RenderListener renderListener) {
        renderListeners.add(renderListener);
    }

    public static void removeRenderListener(final RenderListener renderListener) {
        renderListeners.remove(renderListener);
    }

    public static void addTimeListener(final TimeListener timeListener) {
        timeListeners.add(timeListener);
    }

    public static void removeTimeListener(final TimeListener timeListener) {
        timeListeners.remove(timeListener);
    }

    public static void fireTimeChanged(Date time) {
        for (final TimeListener listener : timeListeners) {
            listener.timeChanged(time);
        }
    }

    public static void fireFrameChanged(JHVJP2View view, ImmutableDateTime dateTime) {
        int idx = layersModel.findView(view);
        if (layersModel.isValidIndex(idx)) {
            // update LayerTableModel (timestamp labels)
            tableModel.fireTableRowsUpdated(idx, idx);

            if (idx == layersModel.getActiveLayer() && dateTime != null) {
                MoviePanel.setFrameSlider(view);
                lastTimestamp = dateTime.getTime();
                fireTimeChanged(lastTimestamp);
                FramerateStatusPanel.getSingletonInstance().updateFramerate(layersModel.getFPS(view));
            }
            display();
        }
    }

    public static Date getLastUpdatedTimestamp() {
        if (lastTimestamp == null) {
            Date lastDate = layersModel.getLastDate();
            if (lastDate != null) {
                lastTimestamp = layersModel.getLastDate();
                return lastTimestamp;
            }
            return null;
        } else {
            return lastTimestamp;
        }
    }

    @Override
    public void eventHightChanged(JHVEvent event) {
        this.display();
    }

    public static RenderableContainer getRenderablecontainer() {
        return renderableContainer;
    }

    public static RenderableContainerPanel getRenderableContainerPanel() {
        return renderableContainerPanel;
    }

}

@@ -1774,24 +1774,30 @@
 vate static 
+final 
 LayersModel 
@@ -1807,16 +1807,53 @@
 ersModel
+ = LayersModel.getSingletonInstance()
 ;%0A    pr
@@ -1865,16 +1865,22 @@
  static 
+final 
 LayerTab
@@ -1901,129 +1901,133 @@
 odel
-;%0A%0A    private Displayer() %7B%0A        layersModel = LayersModel.getSingletonInstance();%0A        tableModel = LayerTableMod
+ = LayerTableModel.getSingletonInstance();%0A    private static final FramerateStatusPanel framerateStatus = FramerateStatusPan
 el.g
@@ -2046,24 +2046,50 @@
 nstance();%0A%0A
+    private Displayer() %7B%0A
         Time
@@ -3706,177 +3706,8 @@
  %7D%0A%0A
-    public static void fireTimeChanged(Date time) %7B%0A        for (final TimeListener listener : timeListeners) %7B%0A            listener.timeChanged(time);%0A        %7D%0A    %7D%0A%0A
     
@@ -3785,24 +3785,24 @@
 dateTime) %7B%0A
+
         int 
@@ -4060,32 +4060,107 @@
 Time != null) %7B%0A
+                framerateStatus.updateFramerate(layersModel.getFPS(view));%0A
                 
@@ -4184,32 +4184,33 @@
 meSlider(view);%0A
+%0A
                 
@@ -4260,21 +4260,25 @@
         
+ //
  fire
+ 
 TimeChan
@@ -4284,24 +4284,8 @@
 nged
-(lastTimestamp);
 %0A   
@@ -4301,94 +4301,134 @@
     
-FramerateStatusPanel.getSingletonInstance().updateFramerate(layersModel.getFPS(view));
+for (final TimeListener listener : timeListeners) %7B%0A                    listener.timeChanged(lastTimestamp);%0A                %7D
 %0A   

Consolidate FrameChanged