package de.uka.ipd.consensus.impl;

import java.util.Properties;
import java.util.StringTokenizer;

import javax.swing.event.EventListenerList;

import de.uka.ipd.consensus.foundation.AbstractConsensusFoundationModule;
import de.uka.ipd.consensus.foundation.ConsensusFoundation;
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.logging.LoggingManager;
import de.uka.ipd.consensus.foundation.ontology.OntologyEvent;
import de.uka.ipd.consensus.foundation.ontology.OntologyListener;
import de.uka.ipd.consensus.foundation.ontology.OntologyManager;
import de.uka.ipd.consensus.foundation.rating.RatingEvent;
import de.uka.ipd.consensus.foundation.rating.RatingListener;
import de.uka.ipd.consensus.foundation.rating.RatingManager;
import de.uka.ipd.consensus.foundation.schema.Concept;
import de.uka.ipd.consensus.foundation.schema.Occurrence;
import de.uka.ipd.consensus.foundation.schema.Rating;
import de.uka.ipd.consensus.foundation.schema.Synonym;
import de.uka.ipd.consensus.foundation.schema.Topic;
import de.uka.ipd.consensus.foundation.schema.User;
import de.uka.ipd.consensus.foundation.scoring.IncentiveManager;
import de.uka.ipd.consensus.foundation.scoring.ScoringEvent;
import de.uka.ipd.consensus.foundation.scoring.ScoringListener;
import de.uka.ipd.consensus.foundation.user.UserManager;

/**
 * 
 * TODO
 * @author Thomas Much
 * @version 2006-06-14
 */
public class IncentiveManagerImpl extends AbstractConsensusFoundationModule implements IncentiveManager,RatingListener,OntologyListener,EvolutionListener {

	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("IncentiveManager init done.");		
	}


	public void initCompleted(Properties config, ConsensusFoundationManager cfm) throws Exception {
		super.initCompleted(config, cfm);

		String scoringListeners = config.getProperty( ConsensusFoundation.CF_SCORING_KEY );
		
		if (scoringListeners != null) {

			StringTokenizer st = new StringTokenizer(scoringListeners,",");

			while (st.hasMoreTokens()) {

				String listenerClassName = st.nextToken().trim();
				
				if (listenerClassName.length() > 0) {

					Class listenerClass = Class.forName(listenerClassName);
					
					ScoringListener listener;

					try {
						java.lang.reflect.Constructor constr = listenerClass.getDeclaredConstructor(new Class[] { Properties.class, ConsensusFoundationManager.class });

						listener = (ScoringListener)constr.newInstance(new Object[] { config, cfm });
					}
					catch (NoSuchMethodException e) {

						try {
							java.lang.reflect.Constructor constr = listenerClass.getDeclaredConstructor(new Class[] { ConsensusFoundationManager.class });

							listener = (ScoringListener)constr.newInstance(new Object[] { cfm });
						}
						catch (NoSuchMethodException e2) {

							listener = (ScoringListener)listenerClass.newInstance();
						}
					}
					
					this.addScoringListener( listener );
				}
			}
		}

		RatingManager rm = cfm.getRatingManager();
		
		if (rm != null) {
			rm.addRatingListener( this );
		}
		
		OntologyManager om = cfm.getOntologyManager();
		
		if (om != null) {
			om.addOntologyListener( this );
		}
		
		EvolutionManager cm = cfm.getEvolutionManager();
		
		if (cm != null) {
			cm.addEvolutionListener( this );
		}

		cfm.getLoggingManager().debug("IncentiveManager initCompleted done.");
	}

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

	
	public double getInitialUserScore() {
		return 0.0;
	}


	public void conceptRatingChanged(RatingEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.CONCEPT_RATING_CHANGED,event.getRatedConcept(),event.getRatedUser(),event.getRating(),event.getOldRatingValue(),null,null,null,null,null);
	}

	
	public void conceptRatingSet(RatingEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.CONCEPT_RATING_SET,event.getRatedConcept(),event.getRatedUser(),event.getRating(),event.getOldRatingValue(),null,null,null,null,null);
	}
	
	
	public void conceptRatingRemoved(RatingEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.CONCEPT_RATING_REMOVED,event.getRatedConcept(),event.getRatedUser(),event.getRating(),event.getOldRatingValue(),null,null,null,null,null);
	}


	public void userRatingChanged(RatingEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.USER_RATING_CHANGED,event.getRatedConcept(),event.getRatedUser(),event.getRating(),event.getOldRatingValue(),null,null,null,null,null);
	}


	public void userRatingSet(RatingEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.USER_RATING_SET,event.getRatedConcept(),event.getRatedUser(),event.getRating(),event.getOldRatingValue(),null,null,null,null,null);
	}
	
	
	public void userRatingRemoved(RatingEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.USER_RATING_REMOVED,event.getRatedConcept(),event.getRatedUser(),event.getRating(),event.getOldRatingValue(),null,null,null,null,null);
	}


	public void topicCreated(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.TOPIC_CREATED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,null,null,null);
	}


	public void associationCreated(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.ASSOCIATION_CREATED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,null,null,null);
	}


	public void conceptCommentChanged(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.CONCEPT_COMMENT_CHANGED,event.getConcept(),null,null,Rating.NEUTRAL,event.getOldValue(),null,null,null,null);
	}
	
	
	public void conceptNameChanged(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.CONCEPT_NAME_CHANGED,event.getConcept(),null,null,Rating.NEUTRAL,event.getOldValue(),null,null,null,null);
	}
	
	
	public void conceptTypeChanged(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.CONCEPT_TYPE_CHANGED,event.getConcept(),null,null,Rating.NEUTRAL,null,event.getOldType(),null,null,null);
	}


	public void topicClassChanged(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.TOPIC_CLASS_CHANGED,event.getConcept(),null,null,Rating.NEUTRAL,null,event.getOldType(),null,null,null);
	}


	public void associationTopicAdded(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.ASSOCIATION_TOPIC_ADDED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,event.getTopic(),null,null);
	}
	
	
	public void associationTopicRemoved(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.ASSOCIATION_TOPIC_REMOVED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,event.getTopic(),null,null);
	}


	public void occurrenceCreated(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.OCCURRENCE_CREATED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,null,event.getOccurrence(),null);
	}


	public void occurrenceChanged(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.OCCURRENCE_CHANGED,event.getConcept(),null,null,Rating.NEUTRAL,event.getOldValue(),null,null,event.getOccurrence(),null);
	}


	public void occurrenceRemoved(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.OCCURRENCE_REMOVED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,null,event.getOccurrence(),null);
	}


	public void attributeAdded(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.ATTRIBUTE_ADDED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,event.getTopic(),null,null);
	}


	public void attributeRemoved(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.ATTRIBUTE_REMOVED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,event.getTopic(),null,null);
	}


	public void attributeValueChanged(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.ATTRIBUTE_VALUE_CHANGED,event.getConcept(),null,null,Rating.NEUTRAL,event.getOldValue(),null,null,null,null);
	}


	public void synonymAdded(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.SYNONYM_ADDED,event.getConcept(),null,null,Rating.NEUTRAL,event.getOldValue(),null,event.getTopic(),null,event.getSynonym());
	}


	public void synonymRemoved(OntologyEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.SYNONYM_REMOVED,event.getConcept(),null,null,Rating.NEUTRAL,event.getOldValue(),null,event.getTopic(),null,event.getSynonym());
	}


	public void associationDeleted(EvolutionEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.ASSOCIATION_DELETED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,event.getTopic(),null,null);
	}


	public void topicDeleted(EvolutionEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.TOPIC_DELETED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,event.getTopic(),null,null);
	}


	public void topicsMerged(EvolutionEvent event) {
		fireScoringEvent(event.getUser(),ScoringEvent.TOPICS_MERGED,event.getConcept(),null,null,Rating.NEUTRAL,null,null,event.getTopic(),null,null);
	}

	
	public void addScoringListener(ScoringListener listener) {
		listenerList.add(ScoringListener.class, listener);
	}

	
	public void removeScoringListener(ScoringListener listener) {
		listenerList.remove(ScoringListener.class, listener);
	}

	
	protected void fireScoringEvent(User source, int id, Concept concept, User ratedUser, Rating rating, double oldRatingValue, String oldValue, Topic oldType, Topic topic, Occurrence occurrence, Synonym synonym) {
		 ScoringEvent event = null;
	     Object[] listeners = listenerList.getListenerList();

	     // erst die Punkte vergeben lassen:
	     for (int i = listeners.length-2; i>=0; i-=2) {
	         if (listeners[i]==ScoringListener.class) {
	             if (event == null) event = new ScoringEvent(getConsensusFoundationManager(),source,id,concept,ratedUser,rating,oldRatingValue,oldValue,oldType,topic,occurrence,synonym);
	             ((ScoringListener)listeners[i+1]).score(event);
	         }
	     }
	     
	     // dann darf darauf reagiert werden:
	     for (int i = listeners.length-2; i>=0; i-=2) {
	         if (listeners[i]==ScoringListener.class) {
	             if (event == null) event = new ScoringEvent(getConsensusFoundationManager(),source,id,concept,ratedUser,rating,oldRatingValue,oldValue,oldType,topic,occurrence,synonym);
	             ((ScoringListener)listeners[i+1]).scored(event);
	         }
	     }
	 }


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