#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 MemberGetEmitter : BaseEmitter
    {
        public MemberGetEmitter(MemberInfo memberInfo, Flags bindingFlags)
            : this(memberInfo.DeclaringType, bindingFlags, memberInfo.MemberType, memberInfo.Name, memberInfo)
        {
        }

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

        private MemberGetEmitter(Type targetType, Flags bindingFlags, MemberTypes memberType, string fieldOrPropertyName, MemberInfo memberInfo)
            : base(new CallInfo(targetType, bindingFlags, memberType, fieldOrPropertyName, Type.EmptyTypes, memberInfo))
        {
        }

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

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

            if (handleInnerStruct)
            {
                Generator
                    .ldarg_0                                                           // load arg-0 (this)
                    .DeclareLocal(CallInfo.TargetType);                 // TargetType tmpStr
                LoadInnerStructToLocal(0);                                 // tmpStr = ((ValueTypeHolder)this)).Value
                Generator.DeclareLocal(Constants.ObjectType);   // object result;
            }
            else if (!CallInfo.IsStatic)
            {
                Generator
                    .ldarg_0                                           // load arg-0 (this)
                    .castclass(CallInfo.TargetType);      // (TargetType)this
            }

            if (member.MemberType == MemberTypes.Field)
            {
                var field = member as FieldInfo;
                Generator
                    .ldfld(CallInfo.IsStatic, field)              // (this|tmpStr).field OR TargetType.field
                    .boxIfValueType(field.FieldType);       // (object)<stack>
            }
            else
            {
                PropertyInfo prop = member as PropertyInfo;
                MethodInfo getMethod = LookupUtils.GetPropertyGetMethod(prop, CallInfo);
                Generator
                    .call(CallInfo.IsStatic || CallInfo.IsTargetTypeStruct, getMethod)   // (this|tmpStr).prop OR TargetType.prop
                    .boxIfValueType(prop.PropertyType);                                               // (object)<stack>
            }

            if (handleInnerStruct)
            {
                Generator.stloc_1.end();                // resultLocal = <stack>
                StoreLocalToInnerStruct(0);        // ((ValueTypeHolder)this)).Value = tmpStr
                Generator.ldloc_1.end();               // push resultLocal
            }

            Generator.ret();

            return CallInfo.IsStatic ? Method.CreateDelegate(typeof(StaticMemberGetter)) : Method.CreateDelegate(typeof(MemberGetter));
        }
    }
}
