using System;
using System.Linq;
using System.Reflection;
using Jint.Native;
using Jint.Native.Object;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Descriptors.Specialized;
using System.Collections;
using System.Collections.Generic;
namespace Jint.Runtime.Interop
{
///
/// Wraps a CLR instance
///
public sealed class ObjectWrapper : ObjectInstance, IObjectWrapper
{
public Object Target { get; set; }
///
/// A private instance to cache methods
///
private Dictionary DelegateCache = new Dictionary();
public ObjectWrapper(Engine engine, Object obj)
: base(engine)
{
Target = obj;
}
public override void Put(string propertyName, JsValue value, bool throwOnError)
{
if (!CanPut(propertyName))
{
if (throwOnError)
{
throw new JavaScriptException(Engine.TypeError);
}
return;
}
var ownDesc = GetOwnProperty(propertyName);
if (ownDesc == null)
{
if (throwOnError)
{
throw new JavaScriptException(Engine.TypeError, "Unknown member: " + propertyName);
}
else
{
return;
}
}
ownDesc.Value = value;
}
public override PropertyDescriptor GetOwnProperty(string propertyName)
{
PropertyDescriptor x;
if (Properties.TryGetValue(propertyName, out x))
return x;
var type = Target.GetType();
// look for a property
var property = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
var descriptor = new PropertyInfoDescriptor(Engine, property, Target);
Properties.Add(propertyName, descriptor);
return descriptor;
}
// look for a field
var field = type.GetField(propertyName, BindingFlags.Instance | BindingFlags.Public);
if (field != null)
{
var descriptor = new FieldInfoDescriptor(Engine, field, Target);
Properties.Add(propertyName, descriptor);
return descriptor;
}
// if no properties were found then look for a method
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
.Where(m => m.Name == propertyName)
.ToArray();
if (methods.Any())
{
var descriptor = new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, methods), false, true, false);
Properties.Add(propertyName, descriptor);
return descriptor;
}
// if no methods are found check if target implemented indexing
if (type.GetProperties().Where(p => p.GetIndexParameters().Length != 0).FirstOrDefault() != null)
{
return new IndexDescriptor(Engine, propertyName, Target);
}
var interfaces = type.GetInterfaces();
// try to find a single explicit property implementation
var explicitProperties = (from iface in interfaces
from iprop in iface.GetProperties()
where propertyName.Equals(iprop.Name)
select iprop).ToArray();
if (explicitProperties.Length == 1)
{
var descriptor = new PropertyInfoDescriptor(Engine, explicitProperties[0], Target);
Properties.Add(propertyName, descriptor);
return descriptor;
}
// try to find explicit method implementations
var explicitMethods = (from iface in interfaces
from imethod in iface.GetMethods()
where propertyName.Equals(imethod.Name)
select imethod).ToArray();
if (explicitMethods.Length > 0)
{
var descriptor = new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, explicitMethods), false, true, false);
Properties.Add(propertyName, descriptor);
return descriptor;
}
// try to find explicit indexer implementations
var explicitIndexers =
(from iface in interfaces
from iprop in iface.GetProperties()
where iprop.GetIndexParameters().Length != 0
select iprop).ToArray();
if (explicitIndexers.Length == 1)
{
return new IndexDescriptor(Engine, explicitIndexers[0].DeclaringType, propertyName, Target);
}
return PropertyDescriptor.Undefined;
}
}
}