/
area/
classes/net/sourceforge/pain/logic/
classes/net/sourceforge/pain/logic/event/
classes/net/sourceforge/pain/logic/fn/util/
classes/net/sourceforge/pain/network/console/
classes/net/sourceforge/pain/plugin/
classes/net/sourceforge/pain/plugin/reset/
classes/net/sourceforge/pain/plugin/shutdown/
classes/net/sourceforge/pain/plugin/social/
classest/net/sourceforge/pain/db/data/
doc/
doc/paindb/resources/
src/net/sourceforge/pain/logic/
src/net/sourceforge/pain/logic/event/
src/net/sourceforge/pain/logic/fn/util/
src/net/sourceforge/pain/network/console/
src/net/sourceforge/pain/network/console/telnet/
src/net/sourceforge/pain/plugin/
src/net/sourceforge/pain/plugin/command/
src/net/sourceforge/pain/plugin/reset/
src/net/sourceforge/pain/plugin/shutdown/
src/net/sourceforge/pain/plugin/social/
src/net/sourceforge/pain/util/
tests/
tests/net/sourceforge/pain/db/data/
package net.sourceforge.pain.logic.fn.factory;

import net.sourceforge.pain.data.*;
import net.sourceforge.pain.data.prototype.*;
import net.sourceforge.pain.logic.fn.util.*;
import net.sourceforge.pain.util.*;

import java.lang.reflect.*;
import java.util.*;

/**
 * User: fmike * Date: Aug 21, 2003  * Time: 1:46:52 AM
 */
public final class GlobalFactory {

	private final static String FACTORY_PACKAGE = "net.sourceforge.pain.logic.fn.factory.";

	private static final Map roleDestructors = new HashMap();
	private static Method stubDestructor = null;
	private static final Object[] destructorParams = new Object[1];
	private static final Class[] destructorArgs = new Class[1];


	private static final Map roleConstructors = new HashMap();
	private static final Object[] constructorParams = new Object[2];
	private static final Class[] constructorArgs = new Class[2];


	public static final void destroyObject(LogicalObject obj) throws Exception {
		//Hungry loop:
		boolean hasMoreRoles;
		do {
			hasMoreRoles = false;
//			int i = 0;
			for (Iterator it = obj.rolesIterator(); it.hasNext(); /*i++*/) {
				Role role = (Role) it.next();
				if (role.hasSubroles()) {
					obj = role;
					hasMoreRoles = true;
					continue;
				}
				detachRole(role);
				it.remove();
			}
		} while (hasMoreRoles);
	}

	private static void detachRole(Role role) throws Exception {
		Class rClass = role.getClass();
		Method m = (Method) roleDestructors.get(rClass);
		if (m == null) {
			m = lookupDestructorMethod(rClass);
			roleDestructors.put(rClass, m);
		}
		destructorParams[0] = role;
		m.invoke(null, destructorParams);
	}

	private static Method lookupDestructorMethod(Class rClass) throws Exception {
		destructorArgs[0] = rClass;
		try {
			return Class.forName(FACTORY_PACKAGE + Utils.classNameWithoutPackage(rClass) + "Factory").getDeclaredMethod("destroy", destructorArgs);
		} catch (Exception e) {
			if (stubDestructor == null) {
				stubDestructor = GlobalFactory.class.getDeclaredMethod("stubDestructor", new Class[]{Role.class});
			}
		}
		return stubDestructor;
	}


	static void stubDestructor(Role role) {
		// do nothing.
	}


	private static Method lookupConstructorMethod(Class protoClass, Class rClass) {
		constructorArgs[0] = protoClass;
		constructorArgs[1] = rClass;
		final String className = FACTORY_PACKAGE + Utils.classNameWithoutPackage(rClass) + "Factory";
		try {
			return Class.forName(className).getDeclaredMethod("init", constructorArgs);
		} catch (Exception e) {
			throw new RuntimeException("Init method not found:" + className + "." + "init(" + Utils.classNameWithoutPackage(protoClass) + "," + Utils.classNameWithoutPackage(rClass) + ")");
		}
	}


	public static LogicalObject createObject(Prototype proto) throws Exception {
		LogicalObject obj = null;
		for (Iterator it = proto.rolesIterator(); it.hasNext();) {
			final Prototype p = (Prototype) it.next();
			final Class prototypedRoleClass = p.getPrototypedRoleClass();
			if (prototypedRoleClass == null) {
				continue;
			}
			if (obj == null) {
				obj = ObjectFactory.create(prototypedRoleClass);
			} else {
				final Role role = obj.getRole(prototypedRoleClass);
				obj = role == null ? obj.addRole(prototypedRoleClass) : role;
			}

			Method m = (Method) roleConstructors.get(prototypedRoleClass);
			if (m == null) {
				m = lookupConstructorMethod(p.getClass(), prototypedRoleClass);
				roleConstructors.put(prototypedRoleClass, m);
			}
			constructorParams[0] = p;
			constructorParams[1] = obj;
			Log.debug("GlobalFactory.create.invoke:" + m + " params" + p.getClass() + "," + obj.getClass());
			m.invoke(null, constructorParams);
		}
		return obj;
	}

}