using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Chernobyl.Collections.Generic.Event;
using Chernobyl.Event;
using Chernobyl.Switch;
namespace Chernobyl.Reflection.Template.CodeDom
{
///
/// An that can take any
/// instance and generate CodeDom for it.
///
public abstract class CodeDomMember : MemberDecorator
{
///
/// Initializes a new instance of the class.
///
/// The instance to
/// generate CodeDom for and provide the
/// implementation for this class.
protected CodeDomMember(IMember member) : base(false)
{
DecoratingEventCollection argumentExpressions = new DecoratingEventCollection(new List());
argumentExpressions.ItemsAdded += ArgumentExpressionAdded;
argumentExpressions.ItemsRemoved += ArgumentExpressionRemoved;
ArgumentExpressions = argumentExpressions;
// set and configure the implementer
_memberImplementer = member;
ConfigureImplementer();
}
///
/// 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;
// ensure our base class believes this is actually our new parent
// before attempting to do anything
if (base.Parent == value && base.Parent != null)
{
CodeDomInstance parentInstance = base.Parent as CodeDomInstance;
if (parentInstance != null)
{
// create and add the declaration of the member's class
parentInstance.TypeDeclaration.Members.Add(TypeDeclaration);
// add a field and property that will hold an instance of the member's class
string fieldAndPropertyBaseName = TypeDeclaration.Name + "_Instance";
CodeMemberField field = new CodeMemberField(TypeDeclaration.Name, "_" + fieldAndPropertyBaseName);
CodeFieldReferenceExpression fieldReference = new CodeFieldReferenceExpression(parentInstance.ThisReference, field.Name);
parentInstance.TypeDeclaration.Members.Add(field);
CodeMemberProperty property = new CodeMemberProperty();
property.Name = fieldAndPropertyBaseName;
property.Type = new CodeTypeReference(TypeDeclaration.Name);
property.HasGet = true;
property.HasSet = true;
property.GetStatements.Add(new CodeMethodReturnStatement(fieldReference));
property.SetStatements.Add(new CodeAssignStatement(fieldReference, new CodePropertySetValueReferenceExpression()));
parentInstance.TypeDeclaration.Members.Add(property);
// create a reference to the member's class instance property
CodePropertyReferenceExpression memberClassProperty = new CodePropertyReferenceExpression(parentInstance.ThisReference, property.Name);
// create the creation of the member's class in the constructor of the instance's class
CodeExpression[] memberClassArguments = new[] { new CodeVariableReferenceExpression("services"), parentInstance.ThisReference };
CodeAssignStatement memberClassPropertyAssignment = new CodeAssignStatement(memberClassProperty, new CodeObjectCreateExpression(TypeDeclaration.Name, memberClassArguments));
parentInstance.ClassConstructor.Statements.Add(memberClassPropertyAssignment);
// create the expression that adds the member's class instance to the ComponentChildren
// property of the instance's class
CodeMethodInvokeExpression memberClassInstanceAddToComponents = new CodeMethodInvokeExpression(parentInstance.ComponentChildrenReference, "Add", memberClassProperty);
parentInstance.ClassConstructor.Statements.Add(memberClassInstanceAddToComponents);
}
}
}
}
}
///
/// The declaration of the type that can be used to create and initialize
/// this member.
///
public CodeTypeDeclaration TypeDeclaration
{
get
{
if(_typeDeclaration == null)
{
_typeDeclaration = new CodeTypeDeclaration(CodeName) { TypeAttributes = TypeAttributes.NotPublic };
// derive from the Member base class and add our constructor
_typeDeclaration.BaseTypes.Add(typeof(Member));
_typeDeclaration.Members.Add(ClassConstructor);
}
return _typeDeclaration;
}
}
///
/// The constructor of the type specified by
/// which initializes the
/// .
///
public CodeConstructor ClassConstructor
{
get
{
if(_classConstructor == null)
{
_classConstructor = new CodeConstructor { Attributes = MemberAttributes.Public };
// create the parameters of the constructor
CodeParameterDeclarationExpression firstParameter = new CodeParameterDeclarationExpression(typeof (IEventCollection