package de.uka.ipd.consensus.impl;

import java.util.Properties;

import javax.swing.event.EventListenerList;

import de.uka.ipd.consensus.foundation.AbstractConsensusFoundationModule;
import de.uka.ipd.consensus.foundation.ConsensusFoundationManager;
import de.uka.ipd.consensus.foundation.evolution.EvolutionEvent;
import de.uka.ipd.consensus.foundation.evolution.EvolutionListener;
import de.uka.ipd.consensus.foundation.evolution.EvolutionManager;
import de.uka.ipd.consensus.foundation.evolution.EvolutionManagerException;
import de.uka.ipd.consensus.foundation.logging.LoggingManager;
import de.uka.ipd.consensus.foundation.ontology.OntologyManager;
import de.uka.ipd.consensus.foundation.ontology.OntologyManagerException;
import de.uka.ipd.consensus.foundation.rating.RatingManager;
import de.uka.ipd.consensus.foundation.rights.DynamicRightsManager;
import de.uka.ipd.consensus.foundation.rights.DynamicRightsManagerException;
import de.uka.ipd.consensus.foundation.schema.Association;
import de.uka.ipd.consensus.foundation.schema.Attribute;
import de.uka.ipd.consensus.foundation.schema.Topic;
import de.uka.ipd.consensus.foundation.schema.User;
import de.uka.ipd.consensus.foundation.user.UserManager;

/**
 * 
 * TODO
 * @author Thomas Much
 * @version 2006-06-14
 */
public class EvolutionManagerImpl extends AbstractConsensusFoundationModule implements EvolutionManager {

	private EventListenerList listenerList = new EventListenerList();

	private boolean running = false;

	
	public void init(Properties config, LoggingManager logging, UserManager users, OntologyManager ontology) throws Exception {
		running = true;
		logging.debug("EvolutionManager init done.");
	}

	
	public void initCompleted(Properties config, ConsensusFoundationManager cfm) throws Exception {
		super.initCompleted(config, cfm);
		cfm.getLoggingManager().debug("EvolutionManager initCompleted done.");
	}

	
	public void shutdown() {
		if (running) {
			running = false;
			getLoggingManager().debug("EvolutionManager shutdown...");
		}
	}


	public void deleteTopic(User user, Topic topic) throws EvolutionManagerException,DynamicRightsManagerException {
		if (topic == null) return;

		DynamicRightsManager drm = this.getDynamicRightsManager();
		if (drm != null) {
			drm.checkDeleteTopic( user, topic );
		}

		try {
			// TODO: bei Instanzen dieses Topic als Typ löschen
			// TODO: bei Assoz. als Spieler löschen
			
			RatingManager rm = this.getRatingManager();
			if (rm != null) {
				rm.deleteRatings( topic );
			}
			
			((TopicImpl)topic).getWrappedTopic().destroy();

			this.fireTopicDeleted( user, topic );
		}
		catch (Exception e) {
			throw new EvolutionManagerException( e );
		}
	}
	
	
	public void deleteTopicAndSubtopics(User user, Topic topic) throws EvolutionManagerException,DynamicRightsManagerException {
		if (topic == null) return;
		
		DynamicRightsManager drm = this.getDynamicRightsManager();
		if (drm != null) {
			drm.checkDeleteTopic( user, topic );
		}

		// TODO: *alle* Instanzen/Unterklassen (rekursiv); problematisch, wenn eine zirkuläre Typen-Beziehung besteht...
		throw new UnsupportedOperationException();
//		this.fireTopicDeleted( user, topic );
	}
	
	
	public void deleteAssociation(User user, Association assoc) throws EvolutionManagerException,DynamicRightsManagerException {
		if (assoc == null) return;
		
		DynamicRightsManager drm = this.getDynamicRightsManager();
		if (drm != null) {
			drm.checkDeleteAssociation( user, assoc );
		}
		
		org.tm4j.topicmap.Association tmAssoc = ((AssociationImpl)assoc).getWrappedAssociation();

		try {
			// TODO: Name/Version-Topic löschen?

			RatingManager rm = this.getRatingManager();
			if (rm != null) {
				rm.deleteRatings( assoc );
			}

			tmAssoc.setMembers( null );
			tmAssoc.dispose();
			tmAssoc.destroy();

			this.fireAssociationDeleted( user, assoc );
		}
		catch (Exception e) {
			throw new EvolutionManagerException( e );
		}
	}
	
	
	public void deleteAttribute(User user, Topic topic, Attribute attr) throws EvolutionManagerException,DynamicRightsManagerException {
		if (topic != null) {
			try {
				topic.removeAttribute( user, attr );
			}
			catch (OntologyManagerException e) {
				throw new EvolutionManagerException( e );
			}
		}
	}


	public Topic mergeTopics(User user, Topic topic1, Topic topic2) throws EvolutionManagerException,DynamicRightsManagerException {
		if (topic1 == null) return topic2;
		if (topic2 == null) return topic1;
		if (topic1.equals( topic2 )) return topic1;

		DynamicRightsManager drm = this.getDynamicRightsManager();
		if (drm != null) {
			drm.checkMergeTopics( user, topic1, topic2 );
		}
		
		try {
			((TopicImpl)topic1).getWrappedTopic().addMergedTopic( ((TopicImpl)topic2).getWrappedTopic() );
			
			// TODO: Bewertungen? Name/Version?

			this.fireTopicsMerged( user, topic1, topic2 );
		}
		catch (Exception e) {
			throw new EvolutionManagerException( e );
		}
		
		return topic1;
	}


	public Topic makeClass(User user, Topic instance) throws EvolutionManagerException,DynamicRightsManagerException {
		if ((instance == null) || instance.isClassTopic()) return instance;
		// TODO
		throw new UnsupportedOperationException();
//		this.fireClassInstanceChanged( user, instance );
	}


	public Topic makeInstance(User user, Topic cls) throws EvolutionManagerException,DynamicRightsManagerException {
		if ((cls == null) || !cls.isClassTopic()) return cls;
		// TODO
		throw new UnsupportedOperationException();
//		this.fireClassInstanceChanged( user, cls );
	}


	public void addEvolutionListener(EvolutionListener listener) {
		listenerList.add(EvolutionListener.class, listener);
	}


	public void removeEvolutionListener(EvolutionListener listener) {
		listenerList.remove(EvolutionListener.class, listener);
	}


	private void fireTopicDeleted(User user, Topic topic) {
		EvolutionEvent event = null;
		Object[] listeners = listenerList.getListenerList();
		for (int i = listeners.length - 2; i >= 0; i -= 2) {
			if (listeners[i] == EvolutionListener.class) {
				if (event == null) event = new EvolutionEvent( this.getConsensusFoundationManager(), topic, user );
				((EvolutionListener) listeners[i + 1]).topicDeleted(event);
			}
		}
	}
	
	
	private void fireAssociationDeleted(User user, Association assoc) {
		EvolutionEvent event = null;
		Object[] listeners = listenerList.getListenerList();
		for (int i = listeners.length - 2; i >= 0; i -= 2) {
			if (listeners[i] == EvolutionListener.class) {
				if (event == null) event = new EvolutionEvent( this.getConsensusFoundationManager(), assoc, user );
				((EvolutionListener) listeners[i + 1]).associationDeleted(event);
			}
		}
	}
	
	
	private void fireTopicsMerged(User user, Topic topic1, Topic topic2) {
		EvolutionEvent event = null;
		Object[] listeners = listenerList.getListenerList();
		for (int i = listeners.length - 2; i >= 0; i -= 2) {
			if (listeners[i] == EvolutionListener.class) {
				if (event == null) event = new EvolutionEvent( this.getConsensusFoundationManager(), topic1, user, topic2 );
				((EvolutionListener) listeners[i + 1]).topicsMerged(event);
			}
		}
	}


	public String getVersion() {
		return "2006-06-14 tm (" + this.getClass().getName() + ")";
	}

}
