package gve.calc.formula;
/* MVC stuff.
 * Controllers and Views always come in pairs. They can
 * communicate directly to each other. They can also communicate
 * directly with the model.
 * A single model can be connected to a number of Controller/View pairs.
 * The model is unaware of its controllers.  
 */
import java.util.Hashtable;
import java.util.Vector;
public class MVC {
	|  This class cannot be instantiated.
	  It is a repository of functions.  | 
	private MVC() {}
	/* Keys are models; values are (Vectors of) views */
	private static Hashtable registrations = new Hashtable();
	/* A view wants to be notified whenever a model changes.
	 * This is similar to having Listeners, but avoids the overhead
	 * of adding a "listeners" field in each model */
	public static void registerView(Object model,View view) {
		Object views = registrations.get(model);
		if (views == null) {
			// For efficiency, don't create a Vector
			// when there's only a single listener
			registrations.put(model,view);
		} else if (views instanceof Vector) {
			((Vector)views).addElement(view);
		} else {
			// there was one view registered
			Vector v = new Vector(4);
			v.addElement(views);
			v.addElement(view);
			registrations.put(model,v);
		}
	}
	public static void unregisterView(Object model,View view) {
		Object views = registrations.get(model);
		if (views == null)
			throw new Error("unregisterView: view was not registered");
		else if (views instanceof Vector) {
			Vector v = (Vector)views;
			if (v.removeElement(view)) {
				if (v.size() == 1) {
					// only one registered view left
					view = (View)v.elementAt(0);
					v.setSize(0);
					registrations.put(model,view);
				}
			} else
				throw new Error("unregisterView: view was not registered");
		} else {
			if (views != view)
				throw new Error("unregisterView: view was not registered");
			// All views are unregistered now
			registrations.remove(model);
		}
	}
	public static View [] getViews(Object model) {
		Object views = registrations.get(model);
		if (views == null) return new View[0];
		if (views instanceof Vector) {
			Vector v = (Vector)views;
			View [] result = new View[v.size()];
			v.copyInto(result);
			return result;
		}
		View [] result = new View[1];
		result[0] = (View)views;
		return result;
	}
	/* Model has changed. This function notifies
	 * all the dependent views of the change by calling their
	 * updateView() method. */
	public static void changed(Object model) {
		changed(model,null);
	}
	/* Same as above, but allow us to pass extra parameter. */
	public static void changed(Object model,Object with) {
		Object views = registrations.get(model);
		if (views == null) return;
		if (views instanceof Vector) {
			Vector v = (Vector)views;
			for (int count = v.size()-1; count>-0; count--) {
				View view = (View)v.elementAt(count);
				view.updateView(with);
			}
			return;
		}
		((View)views).updateView(with);
	}
}