using System;
using System.CodeDom;
using System.Linq;
using System.Reflection;
using Chernobyl.Event;
namespace Chernobyl.Reflection.Template.CodeDom
{
///
/// An that can take any
/// instance that represents an event and generate CodeDom for it.
///
public class CodeDomEvent : CodeDomMember
{
///
/// Initializes a new instance of the class.
///
/// The instance to
/// generate CodeDom for and provide the
/// implementation for this class.
/// Thrown if the member is not
/// a event. In other words, the
/// on the is not equal to
/// .
public CodeDomEvent(IMember member) : base(member)
{
if (Info.MemberType != MemberTypes.Event)
throw new ArgumentException("The member must be an event.", "member");
AttachStatement.Event.EventName = EventName;
}
///
/// The that is the parent to this
/// . This will be
/// added to the parent 's
/// list. If this
/// is already a child to another
/// then it will be removed from that
/// 's
/// list. Setting null on this property will cause this
/// to be removed from it's parent, if necessary.
///
public override IComponent Parent
{
get { return base.Parent; }
set
{
if (base.Parent != value)
{
base.Parent = value;
if (base.Parent == value)
Configure();
}
}
}
///
/// The qualifier that exists in front of the name of an event members
/// 'add' method. For example, if an event was named "SomeEvent", then
/// the add method for that event would be "add_SomeEvent".
///
public const string AddNameQualifier = "add_";
///
/// The qualifier that exists in front of the name of an event members
/// 'remove' method. For example, if an event was named "SomeEvent",
/// then the remove method for that event would be "remove_SomeEvent".
///
public const string RemoveNameQualifier = "remove_";
///
/// An event handler that is invoked right after an argument
/// s are added to the
/// list.
///
/// The instance that generated the event.
/// The instance
/// containing the event data.
protected override void ArgumentExpressionAdded(object sender, ItemsEventArgs e)
{
if (AttachStatement.Listener != null || e.Items.Length > 1)
throw new Exception("Unable to add new argument expression. This member only supports one argument.");
AttachStatement.Listener = e.Items.First();
InitializeMethod.Statements.Add(AttachStatement);
Configure();
base.ArgumentExpressionAdded(sender, e);
}
///
/// An event handler that is invoked right after an argument
/// s are removed from the
/// list.
///
/// The instance that generated the event.
/// The instance
/// containing the event data.
protected override void ArgumentExpressionRemoved(object sender, ItemsEventArgs e)
{
InitializeMethod.Statements.Remove(AttachStatement);
AttachStatement.Listener = null;
base.ArgumentExpressionRemoved(sender, e);
}
///
/// The CodeDom method where the value of the member is set (in the case
/// of a field, property, etc) or the method is invoked. By default, this
/// is set to the . Note
/// that, when set, this property will move the
/// from the old
/// to the newly specified one.
///
public override CodeMemberMethod InitializeMethod
{
get { return base.InitializeMethod; }
set
{
CodeMemberMethod previousInitializeMethod = InitializeMethod;
base.InitializeMethod = value;
// If a new InitializeMethod has been set that is not null and
// we've already added our AttachStatement to the old
// InitializeMethod then we need to move the AttachStatement to
// the new InitializeMethod.
if(base.InitializeMethod == value && value != null &&
previousInitializeMethod.Statements.Contains(AttachStatement) == true)
{
previousInitializeMethod.Statements.Remove(AttachStatement);
base.InitializeMethod.Statements.Add(AttachStatement);
}
}
}
///
/// Initializes a portion of this . This
/// method is called after the parent is set so that the necessary
/// CodeDom instances can be retrieved from the parent
/// .
///
void Configure()
{
// note that we don't configure the AttachStatement.Event.TargetObject
// if our Parent is not set to a CodeDomInstance because the property
// TheGenericInstancePropertyReference uses the CodeDomInstance
// Parent reference to generate the required code.
if (Parent != null && Parent is CodeDomInstance && AttachStatement.Event.TargetObject == null)
AttachStatement.Event.TargetObject = TheGenericInstancePropertyReference;
}
///
/// The name of the event without the "add_" or "remove_" event
/// qualifiers.
///
string EventName
{
get
{
if (_eventName == null)
{
if (Name.StartsWith(AddNameQualifier) == true)
_eventName = Name.Remove(0, AddNameQualifier.Length);
else if (Name.StartsWith(RemoveNameQualifier) == true)
_eventName = Name.Remove(0, RemoveNameQualifier.Length);
else
_eventName = Name;
}
return _eventName;
}
}
///
/// The statement that generates the event attachment code.
///
public CodeAttachEventStatement AttachStatement
{
get
{
if(_attachStatement == null)
{
_attachStatement = new CodeAttachEventStatement
{
Event = new CodeEventReferenceExpression()
};
}
return _attachStatement;
}
}
///
/// The backing field to .
///
string _eventName;
///
/// The backing field to .
///
CodeAttachEventStatement _attachStatement;
}
}