package eu.dnetlib.client.managers;

import java.util.ArrayList;
import java.util.logging.Logger;

import javax.inject.Inject;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Singleton;

import de.novanic.eventservice.client.event.RemoteEventService;
import de.novanic.eventservice.client.event.RemoteEventServiceFactory;
import de.novanic.eventservice.client.event.domain.DomainFactory;
import eu.dnetlib.client.GinWidgetGinjector;
import eu.dnetlib.client.notification.NotificationEvent;
import eu.dnetlib.client.notification.NotificationListener;
import eu.dnetlib.client.notification.NotificationListenerAdapter;
import eu.dnetlib.client.notification.NotificationServiceAsync;
import eu.dnetlib.client.notification.Reconnector;
import eu.dnetlib.client.updaters.Updater;
import eu.dnetlib.efg1914.authoring.components.Frame;
import eu.dnetlib.efg1914.authoring.components.Item;
import eu.dnetlib.efg1914.authoring.components.Theme;
import eu.dnetlib.efg1914.authoring.components.Topic;
import eu.dnetlib.efg1914.authoring.users.User;

@Singleton
public class NotificationManagerImpl implements NotificationManager {

	private Reconnector reconnector;

	private RemoteEventService theRemoteEventService;

	private static Logger log = Logger.getLogger("NotificationManager.java");

	private NotificationListener cometListener;

	private NotificationServiceAsync CometService;
	private RemoteEventServiceFactory theRemoteEventHandlerFactory;
	@Inject
	private Updater updater;
	private String userId;

	@Inject
	public NotificationManagerImpl() {
		createService();
	}

	public void InitCometServices(String userId) {
		this.userId = userId;
		addListener(userId);
		addReconnector(userId);
		registerUser(userId);

	}

	public void destroyCometServices() {
		theRemoteEventService.removeListener(DomainFactory.getDomain(userId), cometListener);

	}

	private void addListener(String userId) {
		cometListener = new NotificationListenerAdapter();
		theRemoteEventService.addListener(DomainFactory.getDomain(userId), cometListener);
		log.info(" \n\n  comet Listener done");

	}

	// TODO add listener for user unlisten event-> when user logsout, dont
	// handle it as an exception

	private void createService() {

		theRemoteEventHandlerFactory = RemoteEventServiceFactory.getInstance();
		theRemoteEventService = theRemoteEventHandlerFactory.getRemoteEventService();
		CometService = GinWidgetGinjector.INSTANCE.getNotificationServiceAsync();
		log.info("\n\n  created  CometService  in NotificationManagerImpl ;");
	}

	private void addReconnector(String userId) {
		reconnector = new Reconnector();
		reconnector.setUSER_DOMAIN(userId);
	}

	public void registerUser(String userId) {
		reconnector.setReconnect(true);

		CometService.register(userId, new AsyncCallback<Void>() {

			public void onSuccess(Void arg0) {
				log.info(" Registered on comet! \n\n   ");

			}

			public void onFailure(Throwable arg0) {
				log.info("\n Failed to Register on comet!");

			}
		});
	}

	public void unregisterUser(String userId, ArrayList<String> userLockedComponents) {

		// TODO tell explicitly to reconnector NOT to attempt to re-establish
		// the connectioon
		// since the timeout occurs because the user logged out
		reconnector.setReconnect(false);
		CometService.logout(userId, userLockedComponents, new AsyncCallback<Void>() {

			public void onSuccess(Void arg0) {
				log.info(" Logout from notification service  done! \n\n   ");

			}

			public void onFailure(Throwable arg0) {
				log.info("\n Failed to Logout from notification service!");

			}
		});
	}

	public void addNewItems(NotificationEvent thenewEvent) {

		for (Item item : thenewEvent.getData().getNewItems()) {

			updater.createNewItem(this.getUserId(), item, false);
		}

	}

	public void updateItems(NotificationEvent thenewEvent) {

		for (Item i : thenewEvent.getData().getUpdatedItems()) {
			updater.updateItem(i, this.getUserId(), false);

		}

	}

	public void deleteItems(NotificationEvent thenewEvent) {

		for (Item i : thenewEvent.getData().getDeletedItems()) {

			updater.deleteItem(i, this.getUserId(), false);

		}

	}

	public void addNewFrames(NotificationEvent thenewEvent) {

		for (Frame i : thenewEvent.getData().getNewFrames()) {
			updater.createNewFrame(this.getUserId(), i, false);

		}

	}

	public void updateFrames(NotificationEvent thenewEvent) {

		for (Frame i : thenewEvent.getData().getUpdatedFrames()) {

			updater.updateFrame(i, this.getUserId(), false);

		}

	}

	public void deleteFrames(NotificationEvent thenewEvent) {

		for (Frame i : thenewEvent.getData().getDeletedFrames()) {
			updater.deleteFrame(i, this.getUserId(), false);

		}

	}

	public void addNewTopics(NotificationEvent thenewEvent) {

		for (Topic i : thenewEvent.getData().getNewTopics()) {
			updater.createNewTopic(this.getUserId(), i, false);

		}

	}

	public void updateTopics(NotificationEvent thenewEvent) {

		for (Topic i : thenewEvent.getData().getUpdatedTopics()) {
			updater.updateTopic(i, this.getUserId(), false);

		}

	}

	public void deleteTopics(NotificationEvent thenewEvent) {

		for (Topic i : thenewEvent.getData().getDeletedTopics()) {

			updater.deleteTopic(i, this.getUserId(), false);
		}

	}

	public void addNewThemes(NotificationEvent thenewEvent) {

		for (Theme i : thenewEvent.getData().getNewThemes()) {
			updater.createNewTheme(this.getUserId(), i, false);

		}

	}

	public void updateThemes(NotificationEvent thenewEvent) {

		for (Theme i : thenewEvent.getData().getUpdatedThemes()) {
			updater.updateTheme(i, this.getUserId(), false);
		}
	}

	public void deleteThemes(NotificationEvent thenewEvent) {

		for (Theme i : thenewEvent.getData().getDeletedThemes()) {
			updater.deleteTheme(i, this.getUserId(), false);

		}

	}

	private String getUserId() {
		return userId;
	}

	public void addNewUsers(NotificationEvent thenewEvent) {

		for (User user : thenewEvent.getData().getNewUsers()) {
			updater.createUser(user, getUserId(), false);

		}
	}

	public void updateUsers(NotificationEvent thenewEvent) {
		for (User user : thenewEvent.getData().getUpdatedUsers()) {
			updater.updateUser(user, getUserId(), false);

		}
	}

	public void deleteUsers(NotificationEvent thenewEvent) {
		for (String userId : thenewEvent.getData().getDeletedUsers()) {

			updater.deleteUser(userId, getUserId(), false);

		}
	}

	public void updateEfgProps(NotificationEvent thenewEvent) {
		if (thenewEvent.getData().getConfiguration() != null) {

			updater.updateConfiguration(thenewEvent.getData().getConfiguration(), getUserId(), false);

		}
	}

}
