package org.eclipse.scanning.test.event.queues.processors;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.eclipse.scanning.api.event.bean.BeanEvent;
import org.eclipse.scanning.api.event.core.IPublisher;
import org.eclipse.scanning.api.event.queues.IQueueBroadcaster;
import org.eclipse.scanning.api.event.queues.IQueueProcessor;
import org.eclipse.scanning.api.event.status.Status;
import org.eclipse.scanning.event.queues.QueueProcess;
import org.eclipse.scanning.event.queues.processors.QueueListener;
import org.eclipse.scanning.test.event.queues.dummy.DummyAtom;
import org.eclipse.scanning.test.event.queues.dummy.DummyHasQueue;
import org.eclipse.scanning.test.event.queues.mocks.MockPublisher;
import org.eclipse.scanning.test.event.queues.mocks.MockQueueProcessor;
import org.junit.Before;
import org.junit.Test;

/**
 * QueueListener listens to the progress (status/percent complete) of one or 
 * more beans on a child queue & updates the progress of the parent bean.
 * 
 * @author Michael Wharmby
 *
 */
public class QueueListenerTest {
	
	private QueueListener<DummyHasQueue, DummyAtom> qList;
	private DummyHasQueue parent, originalParent;
	private double initPercent = 5d;
	private DummyAtom childA, childB;
	private List<DummyAtom> queue;
	
	private IPublisher<DummyHasQueue> statPub;
	private IQueueProcessor<DummyHasQueue> processor;
	private IQueueBroadcaster<DummyHasQueue> broadcaster;
	
	@Before
	public void setUp() {
		//Set initial state on parent
		parent = new DummyHasQueue("Big momma", 60);
		parent.setStatus(Status.RUNNING);
		parent.setPercentComplete(initPercent);
		originalParent = new DummyHasQueue();
		originalParent.merge(parent);
		
		//Set initial state on child
		childA = new DummyAtom("Baby", 10);
		childA.setStatus(Status.SUBMITTED);
		childA.setPercentComplete(0d);
		childB = new DummyAtom("Bobby", 10);
		childB.setStatus(Status.SUBMITTED);
		childB.setPercentComplete(0d);
		
		queue = new ArrayList<>();
		queue.add(childA);
		queue.add(childB);
		
		statPub = new MockPublisher<>(null, "test.topic");
		broadcaster = new QueueProcess<>(parent, statPub, false);//
		processor = new MockQueueProcessor<>(parent, new CountDownLatch(1));//TODO Update to allow broadcaster to be set
	}
	
	@Test
	public void testNothingHappened() {
		qList = new QueueListener<DummyHasQueue, DummyAtom>(processor, childA);
		qList.beanChangePerformed(new BeanEvent<DummyAtom>(childA));
		
		assertEquals("Parent has been updated, even thogh no changes happened on child", originalParent, parent);
	}
	
	@Test
	public void testIgnoreNonChildren() {
		DummyAtom friend = new DummyAtom("Bilbo", 10);
		
		qList = new QueueListener<DummyHasQueue, DummyAtom>(processor, childA);
		
		friend.setPercentComplete(50d);
		friend.setStatus(Status.RUNNING);
		qList.beanChangePerformed(new BeanEvent<DummyAtom>(friend));
		
		assertEquals("Percentage incremented even though non-child in event", parent.getPercentComplete(), originalParent.getPercentComplete(), 0d);
		assertEquals("Status should not have changed as event was non-child", originalParent.getStatus(), broadcaster.getBean().getStatus());
		
	}
	
	@Test
	public void testNormalRunUpdate() {
		qList = new QueueListener<>(processor, queue);
		//Change childA percentage only (not active)
		childA.setPercentComplete(50d);
		qList.beanChangePerformed(new BeanEvent<DummyAtom>(childA));
		
		assertEquals("Percentage incremented even though child not active", broadcaster.getBean().getPercentComplete(), originalParent.getPercentComplete(), 0d);
		assertEquals("Status changed even though child not active", originalParent.getStatus(), broadcaster.getBean().getStatus());
		
		//Now with the status actually set...
		childA.setStatus(Status.RUNNING);
		qList.beanChangePerformed(new BeanEvent<DummyAtom>(childA));
		
		assertEquals("Percentage incorrectly incremented", 28.75d, broadcaster.getBean().getPercentComplete(), 0d);
		assertEquals("Status should not have changed", originalParent.getStatus(), broadcaster.getBean().getStatus());
		
		//Complete childA percentage & Status
		childA.setPercentComplete(100d);
		childA.setStatus(Status.COMPLETE);
		qList.beanChangePerformed(new BeanEvent<DummyAtom>(childA));
		
		assertEquals("Percentage incorrectly incremented", 52.5d, broadcaster.getBean().getPercentComplete(), 0d);
		assertEquals("Status should not have changed", originalParent.getStatus(), broadcaster.getBean().getStatus());
		
		//Complete childB percentage & Status
		childB.setPercentComplete(100d);
		childB.setStatus(Status.COMPLETE);
		qList.beanChangePerformed(new BeanEvent<DummyAtom>(childA));
		
		assertTrue("Processor not marked complete on completion of all children", processor.isComplete());
	}

}

@@ -465,32 +465,94 @@
 QueueProcessor;%0A
+import org.eclipse.scanning.api.event.queues.beans.Queueable;%0A
 import org.eclip
@@ -2517,32 +2517,8 @@
 ner%3C
-DummyHasQueue, DummyAtom
 %3E(pr
@@ -2650,16 +2650,17 @@
 even tho
+u
 gh no ch
@@ -2845,32 +2845,8 @@
 ner%3C
-DummyHasQueue, DummyAtom
 %3E(pr
@@ -3245,35 +3245,32 @@
 atus(), 
-broadcaster.getBean
+getLastBroadcast
 ().getSt
@@ -3596,35 +3596,32 @@
 ctive%22, 
-broadcaster.getBean
+getLastBroadcast
 ().getPe
@@ -3769,35 +3769,32 @@
 atus(), 
-broadcaster.getBean
+getLastBroadcast
 ().getSt
@@ -4008,35 +4008,32 @@
 28.75d, 
-broadcaster.getBean
+getLastBroadcast
 ().getPe
@@ -4131,35 +4131,32 @@
 atus(), 
-broadcaster.getBean
+getLastBroadcast
 ().getSt
@@ -4405,35 +4405,32 @@
  52.5d, 
-broadcaster.getBean
+getLastBroadcast
 ().getPe
@@ -4532,27 +4532,24 @@
 (), 
-broadcaster.getBean
+getLastBroadcast
 ().g
@@ -4847,10 +4847,179 @@
 ));%0A%09%7D%0A%0A
+%09private Queueable getLastBroadcast() %7B%0A%09%09List%3CQueueable%3E broadBeans = ((MockPublisher%3C?%3E)statPub).getBroadcastBeans();%0A%09%09return broadBeans.get(broadBeans.size()-1);%0A%09%7D%0A
 %7D%0A

Set test to use publisher rather than broadcaster for testing bean states.