﻿using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;

namespace Sofire.Aop
{
    class ConstructionCallSink : SinkBase
    {
        private AopAttribute _aop;
        public ConstructionCallSink(AopAttribute aop, IMessageSink nextSink)
            : base(nextSink)
        {
            this._aop = aop;
        }

        private void CreateHandlers(CallAction action, IMethodCallMessage call)
        {
            var qualifiedName = call.TypeName;
            lock(AopSetting.RegisteredHandlers)
            {
                if(!AopSetting.RegisteredHandlers.TryGetValue(qualifiedName, out this._aop.Handlers))
                {
                    this._aop.Handlers = new List<IAopHandler>();
                    AopSetting.RegisteredHandlers.Add(qualifiedName, this._aop.Handlers);
                }
            }
        }

        public override IMessage SyncProcessMessage(IMessage msg)
        {
            var constructionCallMessage = msg as IConstructionCallMessage;

            if(constructionCallMessage == null) return base.SyncProcessMessage(msg);

            this.CreateHandlers(CallAction.Constructor, constructionCallMessage);
            
            Exception exception;
            if(!this._aop.EnterInvoke(null, CallAction.Constructor, constructionCallMessage, out exception))
            {
                if(exception == null) return base.SyncProcessMessage(msg);
                return new ReturnMessage(exception, constructionCallMessage);
            }

            var r = base.SyncProcessMessage(constructionCallMessage) as IConstructionReturnMessage;

            this._aop.LeaveInvoke(null, CallAction.Constructor, constructionCallMessage, r);

            return r;
        }
    }
}
