package php.runtime.ext.java;
import php.runtime.Memory;
import php.runtime.common.HintType;
import php.runtime.env.Environment;
import php.runtime.memory.ArrayMemory;
import php.runtime.memory.LongMemory;
import php.runtime.memory.ObjectMemory;
import php.runtime.memory.StringMemory;
import php.runtime.memory.support.MemoryUtils;
import php.runtime.reflection.ClassEntity;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import static php.runtime.annotation.Reflection.*;
@Name("php\\lang\\JavaClass")
final public class JavaClass extends JavaReflection {
protected Class<?> clazz;
public JavaClass(Environment env, Class<?> clazz) {
super(env);
this.clazz = clazz;
}
public JavaClass(Environment env, ClassEntity clazz) {
super(env, clazz);
}
@Signature(@Arg("class"))
public Memory __construct(Environment env, Memory... args){
try {
setClazz(Class.forName(args[0].toString()));
} catch (ClassNotFoundException e) {
exception(env, e);
}
return Memory.NULL;
}
public void setClazz(Class<?> clazz) {
this.clazz = clazz;
}
@Signature(@Arg("name"))
public Memory __get(Environment env, Memory... args){
String name = args[0].toString();
try {
Field field = clazz.getField(name);
field.setAccessible(true);
return MemoryUtils.valueOf(env, field.get(null));
} catch (NoSuchFieldException | IllegalAccessException e) {
exception(env, e);
}
return Memory.NULL;
}
@Signature({@Arg("name"), @Arg("value")})
public Memory __set(Environment env, Memory... args){
String name = args[0].toString();
try {
Field field = clazz.getField(name);
field.setAccessible(true);
field.set(null, MemoryUtils.fromMemory(args[1], field.getType()));
} catch (NoSuchFieldException | IllegalAccessException e) {
exception(env, e);
}
return Memory.NULL;
}
@Signature
public Memory isInterface(Environment env, Memory... args){
return clazz.isInterface() ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isAnnotation(Environment env, Memory... args){
return clazz.isAnnotation() ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isEnum(Environment env, Memory... args){
return clazz.isEnum() ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isArray(Environment env, Memory... args){
return clazz.isArray() ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isPrimitive(Environment env, Memory... args){
return clazz.isPrimitive() ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isAnonymousClass(Environment env, Memory... args){
return clazz.isAnonymousClass() ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isMemberClass(Environment env, Memory... args){
return clazz.isMemberClass() ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isFinal(Environment env, Memory... args){
return Modifier.isFinal(clazz.getModifiers()) ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory isAbstract(Environment env, Memory... args){
return Modifier.isAbstract(clazz.getModifiers()) ? Memory.TRUE : Memory.FALSE;
}
@Signature
public Memory getName(Environment env, Memory... args){
return new StringMemory(clazz.getName());
}
@Signature
public Memory getSimpleName(Environment env, Memory... args){
return new StringMemory(clazz.getSimpleName());
}
@Signature
public Memory getSuperClass(Environment env, Memory... args){
return clazz.getSuperclass() == null ? Memory.NULL : new ObjectMemory(JavaClass.of(env, clazz.getSuperclass()));
}
@Signature
public Memory getCanonicalName(Environment env, Memory... args){
return new StringMemory(clazz.getCanonicalName());
}
@Signature
public Memory getModifiers(Environment env, Memory... args){
return LongMemory.valueOf(clazz.getModifiers());
}
@Signature(@Arg("annotationClass"))
@SuppressWarnings("unchecked")
public Memory isAnnotationPresent(Environment env, Memory... args){
try {
return clazz.isAnnotationPresent((Class<? extends Annotation>) Class.forName(args[0].toString()))
? Memory.TRUE : Memory.FALSE;
} catch (ClassNotFoundException | ClassCastException e) {
exception(env, e);
}
return Memory.NULL;
}
@Signature
public Memory getComponentType(Environment env, Memory... args){
return new ObjectMemory(JavaClass.of(env, clazz.getComponentType()));
}
@Signature
public Memory getInterfaces(Environment env, Memory... args){
ArrayMemory result = new ArrayMemory();
for(Class<?> el : clazz.getInterfaces()){
result.add(new ObjectMemory(JavaClass.of(env, el)));
}
return result.toConstant();
}
@Signature({@Arg("name"), @Arg(value = "types", type = HintType.ARRAY, optional = @Optional(type = HintType.ARRAY))})
public Memory getDeclaredMethod(Environment env, Memory... args){
try {
return new ObjectMemory(JavaMethod.of(env,
clazz.getDeclaredMethod(args[0].toString(), types(env, args[1].toValue(ArrayMemory.class)))
));
} catch (NoSuchMethodException e) {
exception(env, e);
}
return Memory.NULL;
}
@Signature
public Memory getDeclaredMethods(Environment env, Memory... args){
ArrayMemory result = new ArrayMemory();
for(Method method : clazz.getDeclaredMethods()){
result.add(new ObjectMemory(
JavaMethod.of(env, method)
));
}
return result.toConstant();
}
@Signature(@Arg("name"))
public Memory getDeclaredField(Environment env, Memory... args){
try {
Field field = clazz.getDeclaredField(args[0].toString());
return new ObjectMemory(JavaField.of(env, field));
} catch (NoSuchFieldException e) {
exception(env, e);
}
return Memory.NULL;
}
@Signature
public Memory getDeclaredFields(Environment env, Memory... args) {
ArrayMemory result = new ArrayMemory();
for(Field field : clazz.getDeclaredFields()){
result.put(field.getName(), new ObjectMemory(JavaField.of(env, field)));
}
return result.toConstant();
}
@Signature
public Memory newInstance(Environment env, Memory... args){
try {
return new ObjectMemory(JavaObject.of(env, clazz.newInstance()));
} catch (InstantiationException | IllegalAccessException e) {
exception(env, e);
}
return Memory.NULL;
}
@Signature({@Arg(value = "types", type = HintType.ARRAY), @Arg(value = "arguments", type = HintType.ARRAY)})
public Memory newInstanceArgs(Environment env, Memory... args){
try {
Constructor constructor = clazz.getConstructor(types(env, args[0].toValue(ArrayMemory.class)));
MemoryUtils.Converter[] converters = MemoryUtils.getConverters(constructor.getParameterTypes());
Memory[] passed = args[1].toValue(ArrayMemory.class).values();
if (passed.length != converters.length)
throw new IllegalArgumentException("Invalid argument count");
return new ObjectMemory(JavaObject.of(env,
constructor.newInstance(JavaMethod.makePassed(env, converters, passed))
));
} catch (NoSuchMethodException | InstantiationException | IllegalArgumentException | IllegalAccessException e) {
exception(env, e);
} catch (InvocationTargetException e) {
exception(env, e.getTargetException());
}
return Memory.NULL;
}
@Signature(@Arg(value = "class", nativeType = JavaClass.class))
public Memory isAssignableFrom(Environment env, Memory... args){
JavaClass javaClass = ((JavaClass)args[0].toValue(ObjectMemory.class).value);
return clazz.isAssignableFrom(javaClass.clazz) ? Memory.TRUE : Memory.FALSE;
}
@Signature(@Arg("className"))
public Memory isSubClass(Environment env, Memory... args){
try {
Class<?> clazz = Class.forName(args[0].toString());
return clazz.isAssignableFrom(clazz) ? Memory.TRUE : Memory.FALSE;
} catch (ClassNotFoundException e) {
exception(env, e);
}
return Memory.FALSE;
}
@Signature
public Memory getEnumConstants(Environment env, Memory... args){
ArrayMemory result = new ArrayMemory();
for(Object el : clazz.getEnumConstants()){
result.add(new ObjectMemory(JavaObject.of(env, el)));
}
return result;
}
@Signature(@Arg("name"))
public Memory getResource(Environment env, Memory... args){
URL url = clazz.getResource(args[0].toString());
if (url == null || url.getFile() == null)
return Memory.NULL;
return new StringMemory(url.getFile());
}
public static JavaClass of(Environment env, Class<?> clazz){
return new JavaClass(env, clazz);
}
private final static Map<String, Class<?>> primitives = new HashMap<String, Class<?>>(){{
put("int", Integer.TYPE);
put("byte", Byte.TYPE);
put("short", Short.TYPE);
put("char", Character.TYPE);
put("long", Long.TYPE);
put("float", Float.TYPE);
put("double", Double.TYPE);
put("boolean", Boolean.TYPE);
put("string", String.class);
}};
@Signature(@Arg("name"))
public static Memory primitive(Environment env, Memory... args){
String name = args[0].toString();
Class<?> cls = primitives.get(name);
if (cls == null || !cls.isPrimitive())
exception(env, new ClassNotFoundException(name));
return new ObjectMemory(JavaClass.of(env, cls));
}
public static Class<?>[] types(Environment env, ArrayMemory arrays){
Class<?>[] result = new Class[arrays.size()];
int i = 0;
for(Memory el : arrays.values()){
String name = el.toString();
Class<?> cls = primitives.get(name);
if (cls != null)
result[i] = cls;
else {
try {
result[i] = Class.forName(name);
} catch (ClassNotFoundException e) {
exception(env, e);
}
}
i++;
}
return result;
}
}