package ru.rsdn.patterns.behavioral.observer.test;

import java.util.concurrent.atomic.AtomicBoolean;

import org.junit.Assert;
import org.junit.Test;

import ru.rsdn.patterns.behavioral.observer.ISubscriber;
import ru.rsdn.patterns.behavioral.observer.MultiPublisher;

/**
 * Тестирование примера множественного издателя, использующего слабую связь с
 * подписчиками
 */
public class ConcreteMultiPublisherTest extends MultiPublisher {
	private boolean state;

	private boolean state1;

	/**
	 * @return состояние
	 */
	public boolean getState() {
		return state;
	}

	/**
	 * Установить состояние
	 * @param _state состояние
	 */
	public void setState(boolean _state) {
		state = _state;
		notifySubscribers();
	}

	private void notifySubscribers() {
		for (final ISubscriber subscriber : getSubscribers(ISubscriber.class))
			try {
				subscriber.eventHappen();
			} catch (final RuntimeException e) {
				System.err.println("Обнаружен дефектный подписчик: " +
						subscriber);
				unsubscribe(ISubscriber.class, subscriber);
			}
	}

	/**
	 * @return дополнительное состояние
	 */
	public boolean getState1() {
		return state1;
	}

	/**
	 * Установить дополнительное состояние
	 * @param _state дополнительное состояние
	 */
	public void setState1(boolean _state) {
		state1 = _state;
		notifySubscribers1();
	}

	private void notifySubscribers1() {
		for (final ISubscriber1 subscriber : getSubscribers(ISubscriber1.class))
			try {
				subscriber.eventHappen();
			} catch (final RuntimeException e) {
				System.err.println("Обнаружен дефектный подписчик: " +
						subscriber);
				unsubscribe(ISubscriber1.class, subscriber);
			}
	}

	/**
	 * @return количество подписчиков состояния
	 */
	public int getSubscribersCount() {
		return getSubscribers(ISubscriber.class).size();
	}

	/**
	 * @return количество подписчиков дополнительного состояния
	 */
	public int getSubscribers1Count() {
		return getSubscribers(ISubscriber1.class).size();
	}

	/**
	 * Тестирование оповещения
	 */
	@Test
	public void testNotify() {
		final boolean state = true;
		final AtomicBoolean notified = new AtomicBoolean();
		subscribe(ISubscriber.class, new ISubscriber() {
			public void eventHappen() {
				notified.set(true);
				Assert.assertTrue(getState() == state);
			}
		});
		final AtomicBoolean notified1 = new AtomicBoolean();
		subscribe(ISubscriber1.class, new ISubscriber1() {
			public void eventHappen() {
				notified1.set(true);
				Assert.assertTrue(getState1() == state);
			}
		});
		setState(state);
		Assert.assertTrue(notified.get());
		Assert.assertFalse(notified1.get());
		setState1(state);
		Assert.assertTrue(notified1.get());
	}

	/**
	 * Тестирование слабой связи
	 */
	@Test
	public void testWeakReference() {
		ISubscriber subscriber = new ISubscriber() {
			public void eventHappen() {
				Assert.fail();
			}
		};
		subscribe(ISubscriber.class, subscriber);
		subscriber = null;
		System.gc();
		setState(true);
		Assert.assertFalse(getSubscribersCount() > 0);
	}
}
