/* $Id$
 *
 * Copyright (c) 1999 Xenonsoft Limited. All Rights Reserved.
 *
 * This software is protected by copyright. You are hereby notified from
 * now by reading this message. This software is also the confidential 
 * and proprietary information of Xenonsoft Limited.  ("Confidential
 * Information"). 
 *
 * This software is distributed under the Xenonsoft Public end user 
 * License ("XPeL"), where the machine-readable source code is provided 
 * under the "Open Source" model.
 * For more information, please read the file "LICENSE-XPL.txt" 
 */

// File:`CollisionMapDispatcher.java'
//
//
// DESCRIPTION
//	Collision Map Dispatcher
// 
// Author
//
//	Peter Pilgrim
//	Mon May 24 00:33:27 BST 1999
// 
// RCS HEADER 
// 
//	$Author$
//	$Date$
//	$Source$
//	$Revision$    $State$    $Locker$
//
//
// History:
// --------------------------------------------------------------------------------
//	$Log
//

package xenon.gamekit;

import java.util.Hashtable;

/**
 * This is a <code><b>final</b> class</code> that implements a collision
 * map dispatcher. It permits the technique of <em>double-dispatch</em>
 * in Java.
 * <p>
 * The class is also a <b>Singleton</b>, such that there is only one
 * <code>CollisionMapDispatcher</code> in an application or an applet.
 *
 * @author Peter Pilgrim Thu Aug 05 19:34:32 BST 1999
 * @version $Id$
 */
public final class CollisionMapDispatcher 
{
    private final static String	SEPARATOR="<+>";
    private Hashtable		map;
    
    private static CollisionMapDispatcher dispatcher = new CollisionMapDispatcher();

    private CollisionMapDispatcher() 
    {
	map = new Hashtable();
    }

    /**
     * Returns an instance of the collision map dispatcher
     */
    public static CollisionMapDispatcher getInstance()
    {
	if (dispatcher == null)
	    dispatcher = new CollisionMapDispatcher();
	return (dispatcher);
    }
    
    /**
     * Registers a collision listener which handle collision
     * between objects of these two classes.
     * @param class1 the first world object class
     * @param class2 the second world object class
     * @param listener the collision listener object
     */
    public void addCollisionListener( 
	Class class1, Class class2, CollisionListener listener )
    {
	// FIXME: should check the classes are WorldObject type.
	String s1 = class1.getName();
	String s2 = class2.getName();
	CollisionTuple tuple = new CollisionTuple( s1, s2, listener );
	map.put( s1 + SEPARATOR + s2, tuple );
    }

    /**
     * Fire a collision listener to handle collision
     * between these two world  objects.
     * @param obj1 the first world object.
     * @param obj2 the second world object.
     */
    public void fireCollisionEvent( WorldObject obj1, WorldObject obj2 ) 
    {
	String s1 = obj1.getClass().getName();
	String s2 = obj2.getClass().getName();
	// System.out.println("fireCollisionEvent("+s1+","+s2+")");
	
	CollisionTuple tuple = (CollisionTuple)map.get(  s1 + SEPARATOR + s2 );
	if (tuple != null) {
	    // Call the collision listener object
	    tuple.listener.collisionDetected( obj1, obj2 );
	}
	else {
	    tuple = (CollisionTuple)map.get(  s2 + SEPARATOR + s1 );
	    if (tuple != null) {
		// Call the collision listener object
		tuple.listener.collisionDetected( obj2, obj1 );
	    }
	    else {
		/*
		  throws new InternalError(
		  "cannot handle collision between classes `"+s1+"' and `"+s2+"'" );
		*/
		return;
	    }
	    
	}
    }

    // ----------------------------------------------------------------------
    // I N N E R   C L A S S E S
    // ----------------------------------------------------------------------
    
    /**
     * Collision tuple object
     */
    private static class CollisionTuple {
	String			objectClass1;
	String			objectClass2;
	CollisionListener	listener;

	public CollisionTuple( 
	    String class1, String class2, CollisionListener listener )
	{
	    this.objectClass1 = class1;
	    this.objectClass2 = class2;
	    this.listener = listener;
	}
    }
    
}

// fini
