package org.csstudio.opibuilder.util;

import java.util.concurrent.ConcurrentLinkedQueue;

import org.csstudio.opibuilder.datadefinition.WidgetIgnorableUITask;
import org.csstudio.opibuilder.preferences.PreferencesHelper;
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 Thread thread;
	
	private int guiRefreshCycle = 100;
	
	private long start;

	/**
	 * Standard constructor.
	 */
	private GUIRefreshThread() {
		tasksQueue = new ConcurrentLinkedQueue<WidgetIgnorableUITask>();
		reSchedule();
		thread = new Thread(this, "OPI GUI Rrefresh Thread"); //$NON-NLS-1$
		thread.start();
	}

	/**
	 * 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 void reSchedule(){
		guiRefreshCycle = PreferencesHelper.getGUIRefreshCycle();
	}

	/**
	 * {@inheritDoc}.
	 */
	public void run() {
		while (true) {		
			if(!tasksQueue.isEmpty()){
					start = System.currentTimeMillis();
					processQueue();		
			}
			try {
				long current = System.currentTimeMillis();
				if(current - start < guiRefreshCycle)
					Thread.sleep(guiRefreshCycle - (current -start));
			} catch (InterruptedException e) {
				//ignore
			}
		}
	}

	/**
	 * Process the complete queue.
	 */
	private void processQueue() {
		Display display = PlatformUI.getWorkbench().getDisplay();
		Object[] tasksArray;
		//copy the tasks queue.
		synchronized (this) {
			tasksArray = tasksQueue.toArray();
			tasksQueue.clear();
		}		
		for(Object o : tasksArray){	
				if(display!=null && !display.isDisposed())
					display.syncExec(((WidgetIgnorableUITask) o).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);
	}

	
	
	
}

@@ -215,16 +215,68 @@
 Helper;%0A
+import org.csstudio.platform.logging.CentralLogger;%0A
 import o
@@ -1846,15 +1846,10 @@
 ();%09
-%09
 %0A%09
-%09%09%7D%0A
 %09%09%09t
@@ -1857,16 +1857,17 @@
 y %7B%0A%09%09%09%09
+%09
 long cur
@@ -1897,24 +1897,25 @@
 meMillis();%0A
+%09
 %09%09%09%09if(curre
@@ -1949,16 +1949,17 @@
 e)%0A%09%09%09%09%09
+%09
 Thread.s
@@ -2003,16 +2003,18 @@
 t));%0A%09%09%09
+%09
+%09
 %7D catch 
@@ -2044,16 +2044,18 @@
 ) %7B%0A%09%09%09%09
+%09%09
 //ignore
@@ -2058,17 +2058,146 @@
 nore%0A%09%09%09
-%7D
+%09%09%7D%0A%09%09%09%7Delse%0A%09%09%09%09try %7B%09%09%09%09%09%0A%09%09%09%09%09%09Thread.sleep(guiRefreshCycle);%0A%09%09%09%09%09%7D catch (InterruptedException e) %7B%0A%09%09%09%09%09%09//ignore%0A%09%09%09%09%09%7D%0A%09%09%09
 %0A%09%09%7D%0A%09%7D%0A
@@ -2548,16 +2548,28 @@
 osed())%0A
+%09%09%09%09%09try %7B%0A%09
 %09%09%09%09%09dis
@@ -2630,16 +2630,102 @@
 ask());%0A
+%09%09%09%09%09%7D catch (Exception e) %7B%0A%09%09%09%09%09%09CentralLogger.getInstance().error(this, e);%0A%09%09%09%09%09%7D%0A
 %09%09%7D%09%09%0A%09%7D

Fix a bug in GUIRefreshThread that will cause high CPU usage