package org.csstudio.opibuilder.util;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.csstudio.opibuilder.datadefinition.WidgetIgnorableUITask;
import org.csstudio.opibuilder.preferences.PreferencesHelper;
import org.csstudio.platform.ExecutionService;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;



/**
 * 
 * A singleton back thread which will help to execute tasks for OPI GUI refreshing.
 * This thread sleeps for a time which can be set in the preference page. It can
 * help throttle the unnecessary repaint caused by fast PV value updating.
 * 
 * @author Xihui Chen
 * 
 */
public final class GUIRefreshThread implements Runnable {
	/**
	 * The singleton instance.
	 */
	private static GUIRefreshThread instance;

	/**
	 * A queue, which contains {@link WidgetIgnorableUITask}. 
	 * It will be processed by this thread periodically. 
	 */
	private ConcurrentLinkedQueue<WidgetIgnorableUITask> tasksQueue;
	
	private ScheduledFuture<?> thisTask;

	/**
	 * Standard constructor.
	 */
	private GUIRefreshThread() {
		tasksQueue = new ConcurrentLinkedQueue<WidgetIgnorableUITask>();
		
		thisTask = ExecutionService.getInstance().getScheduledExecutorService()
				.scheduleWithFixedDelay(this, 100, PreferencesHelper.getGUIRefreshCycle(), TimeUnit.MILLISECONDS);
	}

	/**
	 * Gets the singleton instance.
	 * 
	 * @return the singleton instance
	 */
	public static synchronized GUIRefreshThread getInstance() {
		if (instance == null) {
			instance = new GUIRefreshThread();
		}

		return instance;
	}
	
	/**
	 * Reschedule this task upon the new GUI refresh cycle.
	 */
	public synchronized void reSchedule(){
		if(!tasksQueue.isEmpty())
			processQueue();
		thisTask.cancel(false);		
		thisTask = ExecutionService.getInstance().getScheduledExecutorService()
		.scheduleWithFixedDelay(this, 100, PreferencesHelper.getGUIRefreshCycle(), TimeUnit.MILLISECONDS);

	}

	/**
	 * {@inheritDoc}.
	 */
	public void run() {
		if(!tasksQueue.isEmpty())
			processQueue();
	}

	/**
	 * Process the complete queue.
	 */
	private synchronized void processQueue() {
		Display display = PlatformUI.getWorkbench().getDisplay();
		WidgetIgnorableUITask r;
			while( (r=tasksQueue.poll()) != null){	
				display.asyncExec(r.getRunnableTask());
		}		
	}

	/**
	 * Adds the specified runnable to the queue.
	 * 
	 * @param task
	 *            the ignorable UI task.
	 */
	public synchronized void addIgnorableTask(final WidgetIgnorableUITask task) {
		if(tasksQueue.contains(task))
			tasksQueue.remove(task);
		tasksQueue.add(task);
	}

	
	
	
}

@@ -86,91 +86,8 @@
 eue;
-%0Aimport java.util.concurrent.ScheduledFuture;%0Aimport java.util.concurrent.TimeUnit;
 %0A%0Aim
@@ -219,55 +219,8 @@
 er;%0A
-import org.csstudio.platform.ExecutionService;%0A
 impo
@@ -920,35 +920,59 @@
 ate 
-ScheduledFuture%3C?%3E thisTask
+Thread thread;%0A%09%0A%09private int guiRefreshCycle = 100
 ;%0A%0A%09
@@ -1109,183 +1109,107 @@
 ;%0A%09%09
-%0A%09%09thisTask = ExecutionService.getInstance().getScheduledExecutorServic
+reSchedul
 e()
+;
 %0A%09%09
-%09%09.scheduleWithFixedDelay(this, 100, PreferencesHelper.getGUIRefreshCycle(), TimeUnit.MILLISECONDS
+thread = new Thread(this, %22OPI GUI Rrefresh Thread%22); //$NON-NLS-1$%0A%09%09thread.start(
 );%0A%09
@@ -1519,37 +1519,24 @@
  */%0A%09public 
-synchronized 
 void reSched
@@ -1548,191 +1548,25 @@
 %7B%0A%09%09
-if(!tasksQueue.isEmpty())%0A%09%09%09processQueue();%0A%09%09thisTask.cancel(false);%09%09%0A%09%09thisTask = ExecutionService.getInstance().getScheduledExecutorService()%0A%09%09.scheduleWithFixedDelay(this, 100,
+guiRefreshCycle =
  Pre
@@ -1604,34 +1604,9 @@
 le()
-, TimeUnit.MILLISECONDS);%0A
+;
 %0A%09%7D%0A
@@ -1652,24 +1652,44 @@
 oid run() %7B%0A
+%09%09while (true) %7B%09%09%0A%09
 %09%09if(!tasksQ
@@ -1707,16 +1707,18 @@
 y())%0A%09%09%09
+%09%09
 processQ
@@ -1720,24 +1720,131 @@
 cessQueue();
+%09%09%09%0A%09%09%09try %7B%0A%09%09%09%09Thread.sleep(guiRefreshCycle);%0A%09%09%09%7D catch (InterruptedException e) %7B%0A%09%09%09%09//ignore%0A%09%09%09%7D%0A%09%09%7D
 %0A%09%7D%0A%0A%09/**%0A%09 
@@ -1887,29 +1887,16 @@
 private 
-synchronized 
 void pro
@@ -1975,88 +1975,237 @@
 ;%0A%09%09
-WidgetIgnorableUITask r;%0A%09%09%09while( (r=tasksQueue.poll()) 
+Object%5B%5D tasksArray;%0A%09%09//copy the tasks queue.%0A%09%09synchronized (this) %7B%0A%09%09%09tasksArray = tasksQueue.toArray();%0A%09%09%09tasksQueue.clear();%0A%09%09%7D%09%09%0A%09%09for(Object o : tasksArray)%7B%09%0A%09%09%09%09if(display
 !=
- 
 null
-)%7B%09
+ && !display.isDisposed())
 %0A%09%09%09%09
+%09
 display.
 asyn
@@ -2200,17 +2200,16 @@
 display.
-a
 syncExec
@@ -2209,17 +2209,43 @@
 yncExec(
-r
+((WidgetIgnorableUITask) o)
 .getRunn

fix the bug that the GUI update tasks will be queued up because of using Display.asyncExec()