package com.refactorerl.ui.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import com.refactorerl.ui.communication.event.IEvent;
import com.refactorerl.ui.communication.event.IEventDispatcher;
import com.refactorerl.ui.communication.event.IEventHandler;

public class MockEventDispatcher implements IEventDispatcher {

	private ExecutorService es = Executors.newSingleThreadExecutor();;
	private Map<String, List<IEventHandler>> registry = new HashMap<>();
	private Map<IEventHandler, String> inverseRegistry = new HashMap<>();

	@Override
	public Object getValue(IEvent event) {
		return event.getProperty("");
	}

	@Override
	public void subscribe(String topic, IEventHandler handler) {
		synchronized (this.registry) { // to avoid
										// ConcurrentModificationException in
										// fire(..) loop
			if (registry.get(topic) == null) {
				List<IEventHandler> hs = new ArrayList<>();
				hs.add(handler);
				registry.put(topic, hs);
			}
			registry.get(topic).add(handler);
		}
		inverseRegistry.put(handler, topic);
	}

	@Override
	public void unsubscribe(IEventHandler handler) {
		String topic = inverseRegistry.get(handler); // null if already deleted
		if (topic != null) {
			// to avoid ConcurrentModificationException in fire(..) loop
			synchronized (this.registry) {
				registry.get(topic).remove(handler);
			}
		}
		inverseRegistry.remove(handler);

	}

	@Override
	public void fire(String topic, Object msg) {
		List<IEventHandler> handlers = registry.get(topic);
		if (handlers == null)
			return; // it's ok not to have any subscribers

		for (IEventHandler h : handlers) {
			es.execute(new Runnable() {

				@Override
				public void run() {
					h.handleEvent(new IEvent() {

						@Override
						public String getTopic() {
							return topic;
						}

						@Override
						public String[] getPropertyNames() {
							return new String[] {};
						}

						@Override
						public Object getProperty(String name) {
							return msg;
						}

						@Override
						public boolean containsProperty(String name) {
							return true;
						}
					});

				}
			});
		}

	}

	@Override
	public void start() {
	}

	@Override
	public void stop() {

		try {
			es.awaitTermination(1000, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		es.shutdown();

	}

}
