#region COPYRIGHT
//
//     THIS IS GENERATED BY TEMPLATE
//     
//     AUTHOR  :     ROYE
//     DATE       :     2010
//
//     COPYRIGHT (C) 2010, TIANXIAHOTEL TECHNOLOGIES CO., LTD. ALL RIGHTS RESERVED.
//
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Reflection.Emit
{
    internal class MemberSetEmitter : BaseEmitter
    {
        public MemberSetEmitter(MemberInfo memberInfo, Flags bindingFlags)
            : this(memberInfo.DeclaringType, bindingFlags, memberInfo.MemberType, memberInfo.Name, memberInfo)
        {
        }

        public MemberSetEmitter(Type targetType, Flags bindingFlags, MemberTypes memberType, string fieldOrProperty)
            : this(targetType, bindingFlags, memberType, fieldOrProperty, null)
        {
        }

        private MemberSetEmitter(Type targetType, Flags bindingFlags, MemberTypes memberType, string fieldOrProperty, MemberInfo memberInfo)
            : base(new CallInfo(targetType, bindingFlags, memberType, fieldOrProperty, Constants.ArrayOfObjectType, memberInfo))
        {
        }

        protected internal override DynamicMethod CreateDynamicMethod()
        {
            return CallInfo.IsStatic ?
                CreateDynamicMethod("setter", CallInfo.TargetType, null, new[] { Constants.ObjectType }) :
                CreateDynamicMethod("setter", CallInfo.TargetType, null, new[] { Constants.ObjectType, Constants.ObjectType });
        }

        protected internal override Delegate CreateDelegate()
        {
            MemberInfo member = LookupUtils.GetMember(CallInfo);
            bool handleInnerStruct = CallInfo.ShouldHandleInnerStruct;

            Generator.ldarg_0.end();                            // load arg-0 (this or value-to-be-set)
            if (handleInnerStruct)
            {
                Generator.DeclareLocal(CallInfo.TargetType);    // TargetType tmpStr
                LoadInnerStructToLocal(0);                      // tmpStr = ((ValueTypeHolder)this)).Value;
                Generator.ldarg_1.end();                        // load value-to-be-set;
            }
            else if (!CallInfo.IsStatic)
            {
                Generator.castclass(CallInfo.TargetType)      // (TargetType)this
                         .ldarg_1.end();                        // load value-to-be-set;
            }

            Type memberType = member is FieldInfo ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
            Generator.CastFromObject(memberType);               // unbox | cast value-to-be-set
            if (member.MemberType == MemberTypes.Field)
            {
                Generator.stfld(CallInfo.IsStatic, (FieldInfo)member);  // (this|tmpStr).field = value-to-be-set;
            }
            else
            {
                MethodInfo setMethod = LookupUtils.GetPropertySetMethod((PropertyInfo)member, CallInfo);
                Generator.call(CallInfo.IsStatic || CallInfo.IsTargetTypeStruct, setMethod); // (this|tmpStr).set_Prop(value-to-be-set);
            }

            if (handleInnerStruct)
            {
                StoreLocalToInnerStruct(0); // ((ValueTypeHolder)this)).Value = tmpStr
            }

            Generator.ret();

            return CallInfo.IsStatic ? Method.CreateDelegate(typeof(StaticMemberSetter)) : Method.CreateDelegate(typeof(MemberSetter));
        }
    }
}