/*******************************************************************************
 * Copyright (c) 2015 Google, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Stefan Xenos (Google) - initial API and implementation
 ******************************************************************************/
package org.eclipse.core.tests.databinding;

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

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

import org.eclipse.core.databinding.observable.sideeffect.ISideEffect;
import org.eclipse.core.databinding.observable.value.ComputedValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.jface.tests.databinding.AbstractDefaultRealmTestCase;
import org.junit.Before;
import org.junit.Test;

/**
 * Test cases for the {@link ISideEffect}.
 *
 * @since 3.2
 */
public class SideEffectTest extends AbstractDefaultRealmTestCase {
	// TODO: Add test cases for {@link SideEffect#create(Runnable)},
	// {@link SideEffect#create(java.util.function.Supplier,
	// java.util.function.Consumer)}
	// {@link SideEffect#pause()}, and {@link SideEffect#resume()}
	// - Validate that runIfDirty does nothing when paused

	private ISideEffect sideEffect;
	private int sideEffectInvocations;

	private WritableValue<String> defaultDependency;
	private WritableValue<String> alternateDependency;
	private WritableValue<Boolean> useDefaultDependency;

	@Override
	@Before
	public void setUp() throws Exception {
		super.setUp();

		defaultDependency = new WritableValue<>("", null);
		alternateDependency = new WritableValue<>("", null);
		useDefaultDependency = new WritableValue<>(true, null);

		sideEffect = ISideEffect.createPaused(() -> {
			if (useDefaultDependency.getValue()) {
				defaultDependency.getValue();
			} else {
				alternateDependency.getValue();
			}
			sideEffectInvocations++;
		});
	}

	@Test
	public void testSideEffectDoesntRunUntilResumed() throws Exception {
		runAsync();
		assertEquals(0, sideEffectInvocations);
	}

	@Test
	public void testSideEffectRunsWhenResumed() throws Exception {
		sideEffect.resume();
		runAsync();
		assertEquals(1, sideEffectInvocations);
	}

	@Test(expected = IllegalStateException.class)
	public void testResumingSideEffectMultipleTimesThrowsIllegalStateException() throws Exception {
		sideEffect.resume();
		sideEffect.resume();
		runAsync();
		assertEquals(1, sideEffectInvocations);
	}

	@Test
	public void testSideEffectSelectsCorrectDependency() throws Exception {
		// Run the side-effect once
		sideEffect.resume();
		runAsync();
		assertEquals(1, sideEffectInvocations);

		// Confirm that the SideEffect is reacting to defaultDependency
		defaultDependency.setValue("foo");
		runAsync();
		assertEquals(2, sideEffectInvocations);

		// Confirm that the SideEffect is not reacting to alternateDependency
		alternateDependency.setValue("foo");
		runAsync();
		assertEquals(2, sideEffectInvocations);

		// Now change the branch that the side effect ran through and ensure
		// that it selected the correct new dependency (and removed the old one)
		useDefaultDependency.setValue(false);
		runAsync();
		assertEquals(3, sideEffectInvocations);

		// Confirm that the SideEffect is not reacting to defaultDependency
		defaultDependency.setValue("bar");
		runAsync();
		assertEquals(3, sideEffectInvocations);

		// Confirm that the SideEffect is reacting to alternateDependency
		alternateDependency.setValue("bar");
		runAsync();
		assertEquals(4, sideEffectInvocations);
	}

	@Test
	public void testChangingMultipleDependenciesOnlyRunsTheSideEffectOnce() throws Exception {
		sideEffect.resume();
		runAsync();
		assertEquals(1, sideEffectInvocations);

		defaultDependency.setValue("Foo");
		alternateDependency.setValue("Foo");
		useDefaultDependency.setValue(false);

		runAsync();
		assertEquals(2, sideEffectInvocations);
	}

	@Test
	public void testChangingDependencyRerunsSideEffect() throws Exception {
		// Run the side-effect once
		sideEffect.resume();
		runAsync();

		assertEquals(1, sideEffectInvocations);
		// Now change the dependency
		defaultDependency.setValue("Foo");
		runAsync();

		// Ensure that the side effect ran again as a result
		assertEquals(2, sideEffectInvocations);
	}

	@Test
	public void testChangingUnrelatedNodeDoesntRunSideEffect() throws Exception {
		// Run the side-effect once
		sideEffect.resume();
		runAsync();

		assertEquals(1, sideEffectInvocations);
		// Now change the currently-unused dependency
		alternateDependency.setValue("Bar");
		runAsync();

		// Ensure that the side effect did not run again
		assertEquals(1, sideEffectInvocations);
	}

	@Test
	public void testDeactivatedSideEffectWontRunWhenTriggeredByDependency() throws Exception {
		// Run the side-effect once
		sideEffect.resume();
		runAsync();

		assertEquals(1, sideEffectInvocations);
		// Now deactivate the side-effect and trigger one of its dependencies
		defaultDependency.setValue("Foo");
		sideEffect.dispose();
		runAsync();

		// Ensure that the side effect did not run again
		assertEquals(1, sideEffectInvocations);
	}

	@Test
	public void testDeactivatedSideEffectWontRunWhenRunIfDirtyInvoked() throws Exception {
		// Run the side-effect once
		sideEffect.resume();
		runAsync();

		assertEquals(1, sideEffectInvocations);
		sideEffect.pause();
		defaultDependency.setValue("MakeItDirty");
		sideEffect.runIfDirty();
		runAsync();

		// Ensure that the side effect did not run again
		assertEquals(1, sideEffectInvocations);
	}

	@Test
	public void testRunIfDirtyDoesNothingIfSideEffectNotDirty() throws Exception {
		// Run the side-effect once
		sideEffect.resume();
		runAsync();

		assertEquals(1, sideEffectInvocations);
		// Now deactivate the side-effect and trigger one of its dependencies
		sideEffect.runIfDirty();

		// Ensure that the side effect did not run again
		assertEquals(1, sideEffectInvocations);
	}

	@Test
	public void testRunIfDirty() throws Exception {
		sideEffect.resume();
		runAsync();
		assertEquals(1, sideEffectInvocations);
		defaultDependency.setValue("Foo");
		sideEffect.runIfDirty();
		assertEquals(2, sideEffectInvocations);
	}

	@Test
	public void testNestedDependencyChangeAndRunIfDirtyCompletes() throws Exception {
		AtomicBoolean hasRun = new AtomicBoolean();
		WritableValue<Object> invalidator = new WritableValue<Object>(new Object(), null);
		ISideEffect innerSideEffect = ISideEffect.create(() -> {
			invalidator.getValue();
		});

		ISideEffect.createPaused(() -> {
			// Make sure that there are no infinite loops.
			assertFalse(hasRun.get());
			hasRun.set(true);
			invalidator.setValue(new Object());
			innerSideEffect.runIfDirty();
		}).resume();

		runAsync();
		assertTrue(hasRun.get());
	}

	@Test
	public void testNestedInvalidateAndRunIfDirtyCompletes() throws Exception {
		AtomicBoolean hasRun = new AtomicBoolean();
		final WritableValue<Object> makesThingsDirty = new WritableValue<>(null, null);
		ISideEffect innerSideEffect = ISideEffect.createPaused(() -> {
			makesThingsDirty.getValue();
		});

		innerSideEffect.resume();

		ISideEffect.createPaused(() -> {
			// Make sure that there are no infinite loops.
			assertFalse(hasRun.get());
			hasRun.set(true);
			makesThingsDirty.setValue(new Object());
			innerSideEffect.runIfDirty();
		}).resume();

		runAsync();
		assertTrue(hasRun.get());
	}

	@Test
	public void testConsumeOnceDoesntPassNullToConsumer() throws Exception {
		AtomicBoolean consumerHasRun = new AtomicBoolean();
		WritableValue<Object> makesThingsDirty = new WritableValue<>(null, null);
		ComputedValue<Object> value = new ComputedValue<Object>() {
			@Override
			protected Object calculate() {
				makesThingsDirty.getValue();
				return null;
			}
		};

		ISideEffect consumeOnce = ISideEffect.consumeOnceAsync(value::getValue, (Object) -> {
			consumerHasRun.set(true);
		});

		makesThingsDirty.setValue(new Object());
		runAsync();
		makesThingsDirty.setValue(new Object());
		runAsync();
		assertFalse(consumerHasRun.get());
		consumeOnce.dispose();
	}

	@Test
	public void testConsumeOnceDoesntRunTwice() throws Exception {
		AtomicInteger numberOfRuns = new AtomicInteger();
		WritableValue<Object> makesThingsDirty = new WritableValue<>(null, null);
		WritableValue<Object> returnValue = new WritableValue<>(null, null);
		ComputedValue<Object> value = new ComputedValue<Object>() {
			@Override
			protected Object calculate() {
				makesThingsDirty.getValue();
				return returnValue.getValue();
			}
		};

		ISideEffect consumeOnce = ISideEffect.consumeOnceAsync(value::getValue, (Object) -> {
			numberOfRuns.set(numberOfRuns.get() + 1);
		});

		makesThingsDirty.setValue(new Object());
		runAsync();
		assertEquals(0, numberOfRuns.get());

		returnValue.setValue("Foo");
		runAsync();
		assertEquals(1, numberOfRuns.get());

		returnValue.setValue("Bar");
		runAsync();
		assertEquals(1, numberOfRuns.get());
		consumeOnce.dispose();
	}

	@Test
	public void testConsumeOnceDoesntRunAtAllIfDisposed() throws Exception {
		AtomicInteger numberOfRuns = new AtomicInteger();
		WritableValue<Object> returnValue = new WritableValue<>("foo", null);

		ISideEffect consumeOnce = ISideEffect.consumeOnceAsync(returnValue::getValue, (Object) -> {
			numberOfRuns.set(numberOfRuns.get() + 1);
		});

		consumeOnce.dispose();

		runAsync();
		assertEquals(0, numberOfRuns.get());
	}

	@Test
	public void testConsumeOnceRunsIfInitialValueNonNull() throws Exception {
		AtomicInteger numberOfRuns = new AtomicInteger();
		WritableValue<Object> returnValue = new WritableValue<>("foo", null);

		ISideEffect consumeOnce = ISideEffect.consumeOnceAsync(returnValue::getValue, (Object) -> {
			numberOfRuns.set(numberOfRuns.get() + 1);
		});

		runAsync();
		assertEquals(1, numberOfRuns.get());

		consumeOnce.dispose();
	}

	@Test
	public void testNestedSideEffectCreation() throws Exception {
		AtomicBoolean hasRun = new AtomicBoolean();

		// Make sure that creating a SideEffect within another side effect works
		// propely.
		ISideEffect.createPaused(() -> {
			ISideEffect.createPaused(() -> {
				assertFalse(hasRun.get());
				hasRun.set(true);
			}).resume();
		}).resume();
		runAsync();
		assertTrue(hasRun.get());
	}

	@Test
	public void testSideEffectFiresDisposeEvent() throws Exception {
		AtomicBoolean hasRun = new AtomicBoolean();

		// Make sure that a dispose event is sent correctly.
		ISideEffect disposeTest = ISideEffect.createPaused(() -> {
		});
		disposeTest.resume();
		disposeTest.addDisposeListener(sideEffect -> {
			assertTrue(disposeTest == sideEffect);
			hasRun.set(true);
		});
		disposeTest.dispose();
		runAsync();
		assertTrue(hasRun.get());
	}

	@Test
	public void testCanRemoveDisposeListener() throws Exception {
		AtomicBoolean hasRun = new AtomicBoolean();

		// Make sure that a dispose event is sent correctly.
		ISideEffect disposeTest = ISideEffect.createPaused(() -> {
		});
		disposeTest.resume();
		Consumer<ISideEffect> disposeListener = sideEffect -> {
			hasRun.set(true);
		};
		disposeTest.addDisposeListener(disposeListener);
		disposeTest.removeDisposeListener(disposeListener);
		disposeTest.dispose();
		runAsync();
		assertFalse(hasRun.get());
	}

	// Doesn't currently work, but this would be a desirable property for
	// SideEffect to have
	// public void testInvalidateSelf() throws Exception {
	// AtomicInteger runCount = new AtomicInteger();
	// WritableValue<Object> invalidator = new WritableValue<>(null,
	// null);
	// // Make sure that if a side effect invalidates it self, it will run at
	// // least once more but eventually stop.
	// ISideEffect[] sideEffect = new ISideEffect[1];
	// sideEffect[0] = ISideEffect.createPaused(() -> {
	// assertTrue(runCount.get() < 2);
	// invalidator.getValue();
	// int count = runCount.incrementAndGet();
	// if (count == 1) {
	// invalidator.setValue(new Object());
	// }
	// });
	// sideEffect[0].resume();
	// runAsync();
	// assertEquals(2, runCount.get());
	// }
}
