package uk.co.uwcs.choob.support;

import java.lang.reflect.*;
import java.util.*;
import uk.co.uwcs.choob.support.*;
import org.mozilla.javascript.*;

public final class ObjectDBObjectJSWrapper implements ObjectDBObject {
	private Scriptable obj;
	
	public int dummy() {
		return 0;
	}
	
	public ObjectDBObjectJSWrapper(Object obj) throws ChoobException, NoSuchFieldException {
		if (obj == null) {
			throw new ChoobException("Can't wrap a null object!");
		}
		if (!(obj instanceof Scriptable)) {
			throw new ChoobException("Get out of here, that's not a JavaScript Scriptable object!");
		}
		this.obj = (Scriptable)obj;
		if (!ScriptRuntime.typeof(this.obj).equals("object")) {
			throw new ChoobException("JavaScript object of the wrong type; only objects with typeof = 'object' allowed.");
		}
		// We ignore the return value, but it will throw an exception if the
		// property is missing, which we want.
		getFieldValue("id");
	}
	
	public String getClassName() {
		try {
			Object ctor = getFieldValue("constructor");
			if (ctor instanceof Function) {
				ObjectDBClass cls = new ObjectDBClassJSWrapper((Function)ctor);
				return cls.getName();
			}
		} catch (NoSuchFieldException e) {
			// Do nothing.
		}
		return ""; // XXX ?!
	}

	public ObjectDBClass getODBClass() {
		try {
			Object ctor = getFieldValue("constructor");
			if (ctor instanceof Function) {
				ObjectDBClass cls = new ObjectDBClassJSWrapper((Function)ctor);
				return cls;
			}
		} catch (NoSuchFieldException e) {
			// Do nothing.
		}
		return null; // XXX ?!
	}

	public int getId() {
		try {
			return ((Number)getFieldValue("id")).intValue();
		} catch (NoSuchFieldException e) {
			// Should not occur (we check for "id" on creation).
		}
		return 0; // XXX ?!
	}
	
	public void setId(int id) {
		try {
			setFieldValue("id", new Integer(id));
		} catch (NoSuchFieldException e) {
			// Should not occur (we check for "id" on creation).
		}
	}
	
	public String[] getFields() {
		List<String> fields = new LinkedList<String>();
		
		Scriptable proto = obj;
		while (proto != null) {
			Object[] props = proto.getIds();
			
			for (int i = 0; i < props.length; i++) {
				if (props[i] instanceof String) {
					String name = (String)props[i];
					// Don't save props starting "_".
					if (!name.startsWith("_")) {
						fields.add(name);
					}
				} else if (props[i] instanceof Number) {
					// Don't do anything for numeric properties.
				} else {
					System.err.println("WARNING: [ObjectDBObjectJSWrapper.getFields] Unexpected property type: " + props[i].getClass().getName());
				}
			}
			
			proto = proto.getPrototype();
		}
		
		String[] sFields = new String[0];
		return fields.toArray(sFields);
	}
	
	public Type getFieldType(String name) throws NoSuchFieldException {
		Object val = getFieldValue(name);
		if (val == null) {
			System.err.println("WARNING: [ObjectDBObjectJSWrapper.getFieldType] Property '" + name + "' does not exist.");
			return null;
		}
		
		String type = ScriptRuntime.typeof(val);
		
		if (type.equals("undefined") || type.equals("object") || type.equals("function") || type.equals("xml")) {
			System.err.println("WARNING: [ObjectDBObjectJSWrapper.getFieldType] Property '" + name + "' of type '" + type + "' cannot be saved to the ObjectDB.");
			return null;
		}
		if (type.equals("string")) {
			return String.class;
		}
		if (type.equals("number")) {
			return Double.TYPE;
		}
		if (type.equals("boolean")) {
			return Boolean.TYPE;
		}
		System.err.println("WARNING: [ObjectDBObjectJSWrapper.getFieldType] Property '" + name + "' had unknown 'typeof' result: " + type);
		return null;
	}
	
	public Object getFieldValue(String name) throws NoSuchFieldException {
		return JSUtils.mapJSToJava(JSUtils.getProperty(obj, name));
	}
	
	public void setFieldValue(String name, Object value) throws NoSuchFieldException {
		JSUtils.setProperty(obj, name, JSUtils.mapJavaToJS(value));
	}
}

@@ -2311,25 +2311,252 @@
 %09%09%09%09
-fields.add(name);
+// Check we like the type of the prop...%0A%09%09%09%09%09%09try %7B%0A%09%09%09%09%09%09%09Type valType = getFieldType(name);%0A%09%09%09%09%09%09%09if (valType != null) %7B%0A%09%09%09%09%09%09%09%09fields.add(name);%0A%09%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09%7D catch (NoSuchFieldException e) %7B%0A%09%09%09%09%09%09%09// Should never happen here!%0A%09%09%09%09%09%09%7D
 %0A%09%09%09
@@ -3059,122 +3059,8 @@
 ) %7B%0A
-%09%09%09System.err.println(%22WARNING: %5BObjectDBObjectJSWrapper.getFieldType%5D Property '%22 + name + %22' does not exist.%22);%0A
 %09%09%09r
@@ -3236,162 +3236,8 @@
 ) %7B%0A
-%09%09%09System.err.println(%22WARNING: %5BObjectDBObjectJSWrapper.getFieldType%5D Property '%22 + name + %22' of type '%22 + type + %22' cannot be saved to the ObjectDB.%22);%0A
 %09%09%09r
@@ -3429,146 +3429,12 @@
 PE;%0A
+
 %09%09%7D%0A
-%09%09System.err.println(%22WARNING: %5BObjectDBObjectJSWrapper.getFieldType%5D Property '%22 + name + %22' had unknown 'typeof' result: %22 + type);%0A
 %09%09re

Change JS object wrapper to only list properties that it knows it likes, as the ObjectDB code for multiple tables can't hack having a field not be liked any later.