using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using ScriptNET;
namespace ScriptNET.Runtime
{
///
/// Manages event subscriptions from the script
///
[Bindable(false)]
public abstract class EventBroker
{
public IInvokable Target
{
get;
set;
}
public static readonly string UnsubscribeAllEvents = "UnsubscribeAllEvents";
public static Dictionary> subscriptions = new Dictionary>();
private static void AddInvokation(object target, EventInfo ei, Delegate deleg)
{
if (!subscriptions.ContainsKey(target))
subscriptions.Add(target, new Dictionary());
if (subscriptions[target].ContainsKey(ei))
throw new ScriptEventException("Duplicate event subscription");
subscriptions[target].Add(ei, deleg);
}
public static void AssignEvent(EventInfo ei, object targetObject, IInvokable function)
{
Type eventHelper = typeof(EventHelper<>);
Type actualHelper = eventHelper.MakeGenericType(
ei.GetAddMethod().GetParameters()[0].ParameterType.GetMethod("Invoke").GetParameters()[1].ParameterType);
MethodInfo eventHandler = actualHelper.GetMethod("EventHandler");
EventBroker target = (EventBroker)Activator.CreateInstance(actualHelper);
target.Target = function;
#if PocketPC || SILVERLIGHT
Delegate deleg = Delegate.CreateDelegate(ei.EventHandlerType, target, eventHandler);
#else
Delegate deleg = Delegate.CreateDelegate(ei.EventHandlerType, target, eventHandler, false);
#endif
ei.AddEventHandler(targetObject, deleg);
AddInvokation(targetObject, ei, deleg);
}
public static void RemoveEvent(EventInfo ei, object targetObject, IInvokable function)
{
if (subscriptions[targetObject].ContainsKey(ei))
{
ei.RemoveEventHandler(targetObject, subscriptions[targetObject][ei]);
subscriptions[targetObject].Remove(ei);
}
}
public static void ClearAllEventsIfNeeded()
{
if (RuntimeHost.GetSettingsItem(UnsubscribeAllEvents))
ClearAllEvents();
}
public static void ClearAllEvents()
{
if (subscriptions == null) return;
foreach (object o in subscriptions.Keys)
{
List keys = new List();
foreach (EventInfo ei in subscriptions[o].Keys)
keys.Add(ei);
foreach (EventInfo ei in keys)
{
RemoveEvent(ei, o, null);
}
}
subscriptions.Clear();
}
}
internal class EventOperatorHandler : IOperatorHandler
{
bool subscribe;
public EventOperatorHandler(bool subscribe)
{
this.subscribe = subscribe;
}
#region IOperatorHandler Members
public object Process(HandleOperatorArgs args)
{
if (args == null) throw new NotSupportedException();
EventInfo @event = args.Arguments.FirstOrDefault() as EventInfo;
if (@event == null) return null;
args.Cancel = true;
if (subscribe)
return args.Arguments[1];
else
return new RemoveDelegate((IInvokable)args.Arguments[1]);
}
#endregion
}
[ComVisible(true)]
internal class EventHelper : EventBroker
{
public void EventHandler(object sender, T e)
{
if (Target == null) return;
IScriptContext context = new ScriptContext();
context.CreateScope(
RuntimeHost.ScopeFactory.Create(ScopeTypes.Event, context.Scope, context));
Target.Invoke(context, new object[] { sender, e });
}
}
internal class RemoveDelegate : IInvokable
{
public IInvokable OriginalMethod
{
get;
private set;
}
public RemoveDelegate(IInvokable original)
{
OriginalMethod = original;
}
#region IInvokable Members
public bool CanInvoke()
{
return false;
}
public object Invoke(IScriptContext context, object[] args)
{
throw new NotImplementedException();
}
#endregion
}
}