// $Id: example1.java,v 1.1 1998/02/25 16:41:18 oliva Exp $

import BR.unicamp.Guarana.*;

/** A few examples of reflexive behavior

    @author Alexandre Oliva
    @version $Revision: 1.1 $
*/
public class example1 {
    static class myMetaObject extends MetaObject {
	public Result handle(final Operation op, final Object ob) {
	    switch (op.getOpType()) {
	    case Operation.methodInvocation:
		System.out.println("Got method invocation: "+op.getMethod());
		break;
	    case Operation.constructorInvocation:
		System.out.println("Got constructor invocation: "
				   +op.getConstructor());
		break;
	    case Operation.monitorEnter:
		System.out.println("Got monitor enter");
		break;
	    case Operation.monitorExit:
		System.out.println("Got monitor exit");
		break;
	    case Operation.fieldRead:
		System.out.println("Got field read: "+op.getField().getName());
		break;
	    case Operation.fieldWrite:
		System.out.println("Got field write: "
				   +op.getField().getName()
				   +" <- "+op.getValue());
		break;
	    case Operation.arrayLength:
		System.out.println("Got array length");
		break;
	    case Operation.arrayRead:
		System.out.println("Got array read: "+op.getArrayIndex());
		break;
	    case Operation.arrayWrite:
		System.out.println("Got array write: "+op.getArrayIndex()+
				   " <- "+op.getValue());
		break;
	    default:
		System.out.println("Got some other Operation (how come!?!)");
		break;
	    }
	    return Result.inspectResult;
	}
	public Result handle(final Result res, final Object ob) {
	    System.out.println("Got result: "+res.getObjectValue());
	    return null;
	}
	public void handle(final Message msg, final Object ob) {
	    System.out.println("Got message "+msg+" for object "+ob);
	}
	public MetaObject configure(final Object newObject,
				    final Object object) {
	    if (newObject instanceof myObject) {
		System.out.println("Propagating meta-configuration to "+newObject);
		return this;
	    }
	    System.out.println("Not propagating meta-configuration to new instance of "+newObject.getClass());
	    return null;
	}
	public MetaObject reconfigure(final Object object,
				      final MetaObject prev,
				      final MetaObject next) {
	    System.out.println("Rejecting reconfiguration request");
	    return this;
	}
	public void initialize(final OperationFactory fact,
			       final Object obj) {
	    System.out.println("Initializing meta-object for object "+obj);
	    try {
		System.out.println("Trying to assigning 2 to object's field `i'");
		fact.write(obj.getClass().getDeclaredFields()[0],
			   new Integer(2)).perform();
	    } catch (IllegalAccessException t) {
		System.out.println("Expected failure: "+t);
		System.out.println("meta-object was not associated with base-level object yet.");
	    } catch (Throwable t) {
		System.out.println("Failed: "+t);
	    }
	}
	public void release(final Object obj) {
	    /* will be invoked at reconfigure request, even if
	     * reconfiguration doesn't actually take place. */
	    System.out.println("Releasing object "+obj);
	}
    }
  
    public static class myObject {
	int i;
	myObject createAnother() {
	    return new myObject();
	}
    }

    public static void main(String[] argv) {
	final myObject o = new myObject();
	final MetaObject m = new myMetaObject();
	Guarana.reconfigure(o, null, m);
	synchronized(o) {
	    System.out.println(o.i);
	    o.i = 1;
	    System.out.println(o.i);
	}
	final Object[] a = new Object[3];
	Guarana.reconfigure(a, null, m);
	Guarana.reconfigure(myObject.class, null, new myMetaObject());
	synchronized(a) {
	    System.out.println(a.length);
	    a[0] = a[1] = o;
	    System.out.println(a[1]);
	}
	System.out.println(o.hashCode());
	System.out.println(o.equals(o));
	final myObject o2 = o.createAnother();
	Guarana.reconfigure(myObject.class, null, new myMetaObject());
    }
}
