package de.uka.ipd.consensus.impl;

import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;

import org.tm4j.net.Locator;
import org.tm4j.topicmap.Association;
import org.tm4j.topicmap.BaseName;
import org.tm4j.topicmap.Member;
import org.tm4j.topicmap.Occurrence;
import org.tm4j.topicmap.Topic;
import org.tm4j.topicmap.TopicMapObject;

import de.uka.ipd.consensus.foundation.logging.LoggingManager;

/**
 * 
 * TODO
 * @author Thomas Much
 * @version 2006-06-14
 */
public class TM4JObjectWrapper implements Serializable {

	protected static final Topic[] EMPTY_SCOPE = new Topic[0];

	private static Map cache = new WeakHashMap();

	private transient OntologyManagerImpl omi;
	private           TopicMapObject      tmObject;


	public TM4JObjectWrapper(OntologyManagerImpl omi, TopicMapObject tmObject) {
		this.omi      = omi;
		this.tmObject = tmObject;
	}

	
	protected OntologyManagerImpl getOntologyManager() {
		return omi;
	}
	
	
	protected LoggingManager getLoggingManager() {
		return omi.getLoggingManager();
	}


	protected TopicMapObject getWrappedObject() {
		return tmObject;
	}
	
	
	protected String getObjectId() {
		return tmObject.getID();
	}


	public boolean equals(Object other) {
		// as they do in TMAPI
		if (other == null) return false;
		if (this.getClass().equals( other.getClass() )) {
			return this.getObjectId().equals( ((TM4JObjectWrapper)other).getObjectId() );
		}
		return super.equals( other );
	}


	public int hashCode() {
		// as they do in TMAPI
		if (this.getObjectId() == null) {
			return super.hashCode();
		}
		return this.getObjectId().hashCode();
	}


	protected static org.tm4j.topicmap.Occurrence getOccurrence(org.tm4j.topicmap.Topic tmTopic, org.tm4j.topicmap.Topic tmType) {
		Collection c = tmTopic.getOccurrences();
		if (c != null) {
			Iterator it = c.iterator();
			while (it.hasNext()) {
				org.tm4j.topicmap.Occurrence occ = (org.tm4j.topicmap.Occurrence)it.next();
				if (occ.isOfType( tmType )) {
					return occ;
				}
			}
		}
		return null;
	}
	

	protected static Object getCache(String key) {
		WeakReference weakRef = (WeakReference)cache.get( key );
		if (weakRef != null) {
			return weakRef.get();
		}
		else {
			return null;
		}
	}


	protected static void putCache(String key, Object value) {
		cache.put( key, new WeakReference(value) );
	}


	protected static Object wrap(OntologyManagerImpl omi, Topic t) {
		if (t == null) return null;
		
		if (t.isOfType(omi.getUserTopicType())) {
			return UserImpl.getInstance(omi,t);
		}

		Object obj = getCache( t.getID() );

		if (obj == null) {
// deprecated - enable only for testing purposes:
//			RatingManager rm = omi.getRatingManager();
//			if ((rm != null) && (rm instanceof TM4JRatingManagerImpl) && t.isOfType(((TM4JRatingManagerImpl)rm).getRatingTopicType())) {
//				obj = new TM4JRatingImpl(omi,t);
//			}
//			else
			if (t.isOfType(omi.getAttributeTopicType())) {
				obj = new AttributeImpl(omi,t);
			}
			else {
				obj = new TopicImpl(omi,t);
			}
			putCache( t.getID(), obj );
		}

		return obj;
	}


	protected static AssociationImpl wrap(OntologyManagerImpl omi, Association a) {
		if (a == null) return null;
		
		AssociationImpl ai = (AssociationImpl)getCache( a.getID() );
		if (ai == null) {
			ai = new AssociationImpl(omi,a);
			putCache( a.getID(), ai );
		}
		return ai;
	}


	protected static AssociationRoleImpl wrap(OntologyManagerImpl omi, Member m) {
		if (m == null) return null;
		
		AssociationRoleImpl ari = (AssociationRoleImpl)getCache( m.getID() );
		if (ari == null) {
			ari = new AssociationRoleImpl(omi,m);
			putCache( m.getID(), ari );
		}
		return ari;
	}


	protected static OccurrenceImpl wrap(OntologyManagerImpl omi, Occurrence occ) {
		if (occ == null) return null;

		OccurrenceImpl oi = (OccurrenceImpl)getCache( occ.getID() );
		if (oi == null) {
			oi = new OccurrenceImpl(omi,occ);
			putCache( occ.getID(), oi );
		}
		return oi;
	}


	protected static String wrap(OntologyManagerImpl omi, BaseName bn) {
		if (bn == null) return null;
		return bn.getData();
	}

	
	protected static String wrap(OntologyManagerImpl omi, Locator loc) {
		if (loc == null) return null;
		return loc.getAddress();
	}

	
	protected static Object wrap(OntologyManagerImpl omi, Object obj) {
		if (obj == null) return null;

		if (obj instanceof Topic) {
			return wrap(omi,(Topic)obj);
		}

		if (obj instanceof Association) {
			return wrap(omi,(Association)obj);
		}
		
		if (obj instanceof Member) {
			return wrap(omi,(Member)obj);
		}

		if (obj instanceof BaseName) {
			return wrap(omi,(BaseName)obj);
		}

		if (obj instanceof Locator) {
			return wrap(omi,(Locator)obj);
		}

		if (obj instanceof Occurrence) {
			return wrap(omi,(Occurrence)obj);
		}
		
		// don't know how to wrap, return unwrapped!
		return obj;
	}

}
