package cucumber.runtime.groovy;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.MissingMethodException;
import groovy.lang.MissingPropertyException;
import groovy.lang.Tuple;
import org.codehaus.groovy.runtime.MetaClassHelper;
import java.util.LinkedList;
import java.util.List;
class GroovyWorld extends GroovyObjectSupport {
private final List<GroovyObject> worlds;
public GroovyWorld() {
super();
worlds = new LinkedList<GroovyObject>();
}
public void registerWorld(Object world) {
if (world instanceof GroovyObject) {
worlds.add((GroovyObject) world);
} else {
throw new RuntimeException("Only GroovyObject supported");
}
}
public Object getProperty(String property) {
return findWorldWithProperty(property).getProperty(property);
}
public void setProperty(String property, Object newValue) {
findWorldWithProperty(property).setProperty(property, newValue);
}
public Object invokeMethod(String name, Object args) {
return findWorldWithMethod(name, args).invokeMethod(name, args);
}
int worldsCount() {
return worlds.size();
}
private GroovyObject findWorldWithProperty(String property) {
if (worlds.isEmpty()) {
throw new MissingPropertyException(property, GroovyWorld.class);
}
if (worlds.size() == 1) {
return worlds.get(0);
}
GroovyObject worldWithProperty = null;
for (GroovyObject world : worlds) {
if (world.getMetaClass().hasProperty(this, property) != null) {
if (worldWithProperty == null) {
worldWithProperty = world;
} else {
throw new RuntimeException("Multiple property call: " + property);
}
}
}
if (worldWithProperty == null) {
throw new MissingPropertyException(property, GroovyWorld.class);
}
return worldWithProperty;
}
private GroovyObject findWorldWithMethod(String methodName, Object arguments) {
Object[] args = unwrapMethodArguments(arguments);
if (worlds.isEmpty()) {
throw new MissingMethodException(methodName, this.getClass(), args);
}
if (worlds.size() == 1) {
return worlds.get(0);
}
GroovyObject worldWithMethod = null;
for (GroovyObject world : worlds) {
if (world.getMetaClass().getMetaMethod(methodName, args) != null) {
if (worldWithMethod == null) {
worldWithMethod = world;
} else {
throw new RuntimeException("Multiple method call: " + methodName);
}
}
}
if (worldWithMethod == null) {
throw new MissingMethodException(methodName, this.getClass(), args);
}
return worldWithMethod;
}
private Object[] unwrapMethodArguments(Object arguments) {
if (arguments == null) {
return MetaClassHelper.EMPTY_ARRAY;
}
if (arguments instanceof Tuple) {
Tuple tuple = (Tuple) arguments;
return tuple.toArray();
}
if (arguments instanceof Object[]) {
return (Object[]) arguments;
} else {
return new Object[]{arguments};
}
}
}