
package orc.run.porce.runtime;

import scala.Function1;

import orc.Accessor;
import orc.NoSuchMemberAccessor;
import orc.OrcRuntime;
import orc.run.distrib.DOrcMarshalingReplacement;
import orc.values.Field;
import orc.values.Format;
import orc.values.sites.AccessorValue;

public final class PorcEObject implements AccessorValue, DOrcMarshalingReplacement {
    public final Field[] fieldNames;
    public final Object[] fieldValues;

    // TODO: PERFORMANCE: Using a frame instead of an array for field values may
    // perform better. Though that will mainly be true when we start using
    // native values.
    public PorcEObject(final Field[] fieldNames, final Object[] fieldValues) {
        assert fieldNames.length == fieldValues.length;

        this.fieldNames = fieldNames;
        this.fieldValues = fieldValues;
    }
    
    @Override
    public String toString() {
    	StringBuilder sb = new StringBuilder();
    	sb.append("{ ");
    	for (int i = 0; i < fieldNames.length; i++) {
			Field field = fieldNames[i];
			Object value = fieldValues[i];
			if (i > 0) {
				sb.append(" # ");
			}
			sb.append(field);
			sb.append(" = ");
			sb.append(Format.formatValue(value));
		}
    	sb.append(" }");
    	return sb.toString();
    }

    @Override
    public Accessor getAccessor(final OrcRuntime runtime, final Field field) {
        for (int i = 0; i < fieldNames.length; i++) {
            if (field.equals(fieldNames[i])) {
                final int index = i;
                final Field[] theseFieldNames = fieldNames;
                return new Accessor() {
                    @Override
                    public boolean canGet(final Object target) {
                        return target instanceof PorcEObject && theseFieldNames == ((PorcEObject) target).fieldNames;
                    }

                    @Override
                    public Object get(final Object target) {
                        return ((PorcEObject) target).fieldValues[index];
                    }
                };
            }
        }
        return new NoSuchMemberAccessor(this, field.name());
    }

    @Override
    public boolean isReplacementNeededForMarshaling(final Function1<Object, Object> marshalValueWouldReplace) {
        return JavaMarshalingUtilities.existsMarshalValueWouldReplace(fieldValues, marshalValueWouldReplace);
    }

    @Override
    public Object replaceForMarshaling(final Function1<Object, Object> marshaler) {
        return new PorcEObject(fieldNames, JavaMarshalingUtilities.mapMarshaler(fieldValues, marshaler));
    }

    @Override
    public boolean isReplacementNeededForUnmarshaling(final Function1<Object, Object> unmarshalValueWouldReplace) {
        return JavaMarshalingUtilities.existsMarshalValueWouldReplace(fieldValues, unmarshalValueWouldReplace);
    }

    @Override
    public Object replaceForUnmarshaling(final Function1<Object, Object> unmarshaler) {
        return new PorcEObject(fieldNames, JavaMarshalingUtilities.mapMarshaler(fieldValues, unmarshaler));
    }
}

@@ -842,49 +842,606 @@
     
-@Override%0A    public String toString() %7B%0A
+private final ThreadLocal%3CBoolean%3E toStringRecursionCheck = new ThreadLocal%3CBoolean%3E() %7B%0A        @Override%0A        @SuppressWarnings(%22boxing%22)%0A        protected Boolean initialValue() %7B%0A            return false;%0A        %7D%0A    %7D;%0A    %0A    @Override%0A    @SuppressWarnings(%22boxing%22)%0A    public String toString() %7B%0A        // FIXME: The recursion check will be SLOW. But it may not matter. However it may not even be good to have this as a default.%0A        if (toStringRecursionCheck.get()) %7B%0A            return %22%5B... recursive ...%5D%22;%0A        %7D else %7B%0A            toStringRecursionCheck.set(true);%0A    
     
@@ -1477,24 +1477,28 @@
 gBuilder();%0A
+    
     %09sb.appe
@@ -1511,16 +1511,20 @@
 %22);%0A    
+  
+  
 %09for (in
@@ -1562,16 +1562,20 @@
  i++) %7B%0A
+    
 %09%09%09Field
@@ -1598,16 +1598,20 @@
 mes%5Bi%5D;%0A
+    
 %09%09%09Objec
@@ -1636,16 +1636,20 @@
 ues%5Bi%5D;%0A
+    
 %09%09%09if (i
@@ -1656,16 +1656,20 @@
  %3E 0) %7B%0A
+    
 %09%09%09%09sb.a
@@ -1686,13 +1686,21 @@
 %22);%0A
+    
 %09%09%09%7D%0A
+    
 %09%09%09s
@@ -1716,16 +1716,20 @@
 field);%0A
+    
 %09%09%09sb.ap
@@ -1741,16 +1741,20 @@
 %22 = %22);%0A
+    
 %09%09%09sb.ap
@@ -1786,24 +1786,28 @@
 alue));%0A
+    
 %09%09%7D%0A    
 %09sb.appe
@@ -1794,24 +1794,28 @@
     %09%09%7D%0A    
+   
+ 
 %09sb.append(%22
@@ -1816,24 +1816,75 @@
 pend(%22 %7D%22);%0A
+            toStringRecursionCheck.set(false);%0A    
     %09return 
@@ -1894,24 +1894,34 @@
 toString();%0A
+        %7D%0A
     %7D%0A%0A    @

Fix stack overflow due to PorcEObject self reference.