#region License

/*
 * Copyright © 2002-2005 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#endregion

#region Imports

using System;
using System.Collections;

using AopAlliance.Aop;
using Spring.Aop;
using Spring.Proxy;

#endregion

namespace Spring.Aop.Framework
{
    /// <summary>
    /// Configuration data for an AOP proxy factory.
    /// </summary>
    /// <remarks>
    /// <p>
    /// This configuration includes the
    /// <see cref="AopAlliance.Intercept.IInterceptor"/>s,
    /// <see cref="Spring.Aop.IAdvisor"/>s, and (any) proxied interfaces.
    /// </p>
    /// <p>
    /// Any AOP proxy obtained from Spring.NET can be cast to this interface to
    /// allow the manipulation of said proxy's AOP advice.
    /// </p>
    /// </remarks>
    /// <author>Rod Johnson</author>
    /// <author>Aleksandar Seovic (.NET)</author>
    /// <seealso cref="Spring.Aop.Framework.AdvisedSupport"/>
    [ProxyIgnore]
    public interface IAdvised
    {
        /// <summary>
        /// Should proxies obtained from this configuration expose
        /// the AOP proxy to the
        /// <see cref="Spring.Aop.Framework.AopContext"/> class?
        /// </summary>
        /// <remarks>
        /// <p>
        /// This is useful if an advised object needs to call another advised
        /// method on itself. (If it uses the <c>this</c> reference (<c>Me</c>
        /// in Visual Basic.NET), the invocation will <b>not</b> be advised).
        /// </p>
        /// </remarks>
        bool ExposeProxy { get; }

        /// <summary>
        /// Gets the
        /// <see cref="Spring.Aop.Framework.IAdvisorChainFactory"/>
        /// implementation that will be used to get the interceptor
        /// chains for the advised
        /// <see cref="Spring.Aop.Framework.AdvisedSupport.Target"/>.
        /// </summary>
        /// <value>
        /// The <see cref="Spring.Aop.Framework.IAdvisorChainFactory"/>
        /// implementation that will be used to get the interceptor
        /// chains for the advised
        /// <see cref="Spring.Aop.Framework.AdvisedSupport.Target"/>.
        /// </value>
        IAdvisorChainFactory AdvisorChainFactory { get; }

        /// <summary>
        /// Is the target <see cref="System.Type"/> to be proxied in addition
        /// to any interfaces declared on the proxied <see cref="System.Type"/>?
        /// </summary>
        bool ProxyTargetType { get; }

        /// <summary>
        /// Is target type attributes, method attributes, method's return type attributes 
        /// and method's parameter attributes to be proxied in addition
        /// to any interfaces declared on the proxied <see cref="System.Type"/>?
        /// </summary>
        bool ProxyTargetAttributes { get; }

        /// <summary>
        /// Returns the collection of <see cref="Spring.Aop.IAdvisor"/>
        /// instances that have been applied to this proxy.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Will never return <cref lang="null"/>, but may return an
        /// empty array (in the case where no
        /// <see cref="Spring.Aop.IAdvisor"/> instances have been applied to
        /// this proxy).
        /// </p>
        /// </remarks>
        /// <value>
        /// The collection of <see cref="Spring.Aop.IAdvisor"/>
        /// instances that have been applied to this proxy.
        /// </value>
        IAdvisor[] Advisors { get; }

        /// <summary>
        /// Returns the collection of <see cref="Spring.Aop.IIntroductionAdvisor"/>
        /// instances that have been applied to this proxy.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Will never return <cref lang="null"/>, but may return an
        /// empty array (in the case where no
        /// <see cref="Spring.Aop.IIntroductionAdvisor"/> instances have been
        /// applied to this proxy).
        /// </p>
        /// </remarks>
        /// <value>
        /// The collection of <see cref="Spring.Aop.IIntroductionAdvisor"/>
        /// instances that have been applied to this proxy.
        /// </value>
        IIntroductionAdvisor[] Introductions { get; }

        /// <summary>
        /// Returns the collection of interface <see cref="System.Type"/>s
        /// to be (or that are being) proxied by this proxy.
        /// </summary>
        /// <value>
        /// The collection of interface <see cref="System.Type"/>s
        /// to be (or that are being) proxied by this proxy.
        /// </value>
        Type[] Interfaces { get; }

        /// <summary>
        /// Returns the mapping of the proxied interface
        /// <see cref="System.Type"/>s to their delegates.
        /// </summary>
        /// <value>
        /// The mapping of the proxied interface
        /// <see cref="System.Type"/>s to their delegates.
        /// </value>
        IDictionary InterfaceMap { get; }

        /// <summary>
        /// Is this configuration frozen?
        /// </summary>
        /// <remarks>
        /// <p>
        /// When a config is frozen, no advice changes can be made. This is
        /// useful for optimization, and useful when we don't want callers
        /// to be able to manipulate configuration after casting to
        /// <see cref="Spring.Aop.Framework.IAdvised"/>.
        /// </p>
        /// </remarks>
        bool IsFrozen { get; }

        /// <summary>
        /// Returns the <see cref="Spring.Aop.ITargetSource"/> used by this
        /// <see cref="Spring.Aop.Framework.IAdvised"/> object.
        /// </summary>
        /// <value>
        /// The <see cref="Spring.Aop.ITargetSource"/> used by this
        /// <see cref="Spring.Aop.Framework.IAdvised"/> object.
        /// </value>
        ITargetSource TargetSource { get; }

        /// <summary>
        /// Returns a boolean specifying if this <see cref="IAdvised"/>
        /// instance can be serialized.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance can be serialized, <c>false</c> otherwise.
        /// </value>
        bool IsSerializable { get; }

        /// <summary>
        /// Adds the supplied <paramref name="advice"/> to the end (or tail)
        /// of the advice (interceptor) chain.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Please be aware that Spring.NET's AOP implementation only supports
        /// method advice (as encapsulated by the 
        /// <see cref="AopAlliance.Intercept.IMethodInterceptor"/> interface).
        /// </p>
        /// </remarks>
        /// <param name="advice">
        /// The <see cref="AopAlliance.Aop.IAdvice"/> to be added.
        /// </param>
        /// <seealso cref="Spring.Aop.Support.DefaultPointcutAdvisor"/>
        /// <seealso cref="Spring.Aop.Framework.IAdvised.AddAdvice(int,IAdvice)"/>
        void AddAdvice(IAdvice advice);

        /// <summary>
        /// Adds the supplied <paramref name="advice"/> to the supplied
        /// <paramref name="position"/> in the advice (interceptor) chain.
        /// </summary>
        /// <remarks>
        /// <p>
        /// Please be aware that Spring.NET's AOP implementation only supports
        /// method advice (as encapsulated by the 
        /// <see cref="AopAlliance.Intercept.IMethodInterceptor"/> interface).
        /// </p>
        /// </remarks>
        /// <param name="position">
        /// The zero (0) indexed position (from the head) at which the
        /// supplied <paramref name="advice"/> is to be inserted into the
        /// advice (interceptor) chain.
        /// </param>
        /// <param name="advice">
        /// The <see cref="AopAlliance.Aop.IAdvice"/> to be added.
        /// </param>
        /// <seealso cref="Spring.Aop.Support.DefaultPointcutAdvisor"/>
        /// <seealso cref="Spring.Aop.Framework.IAdvised.AddAdvice(IAdvice)"/>
        void AddAdvice(int position, IAdvice advice);

        /// <summary>
        /// Is the supplied <paramref name="intf"/> (interface)
        /// <see cref="System.Type"/> proxied?
        /// </summary>
        /// <param name="intf">
        /// The interface <see cref="System.Type"/> to test.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the supplied <paramref name="intf"/>
        /// (interface) <see cref="System.Type"/> is proxied;
        /// <see langword="false"/> if not or the supplied
        /// <paramref name="intf"/> is <cref lang="null"/>.
        /// </returns>
        bool IsInterfaceProxied(Type intf);

        /// <summary>
        /// Adds the advisors from the supplied <paramref name="advisors"/> 
        /// to the list of <see cref="Spring.Aop.Framework.IAdvised.Advisors"/>.
        /// </summary>
        /// <param name="advisors">
        /// The <see cref="IAdvisors"/> to add advisors from.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <paramref name="advisors"/> cannot be added.
        /// </exception>
        void AddAdvisors(IAdvisors advisors);

        /// <summary>
        /// Adds the supplied <paramref name="advisor"/> to the list
        /// of <see cref="Spring.Aop.Framework.IAdvised.Advisors"/>.
        /// </summary>
        /// <param name="advisor">
        /// The <see cref="Spring.Aop.IAdvisor"/> to add.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <paramref name="advisor"/> cannot be added.
        /// </exception>
        void AddAdvisor(IAdvisor advisor);

        /// <summary>
        /// Adds the supplied <paramref name="advisor"/> to the list
        /// of <see cref="Spring.Aop.Framework.IAdvised.Advisors"/>.
        /// </summary>
        /// <param name="index">
        /// The index in the <see cref="Spring.Aop.Framework.IAdvised.Advisors"/>
        /// list at which the supplied <paramref name="advisor"/>
        /// is to be inserted.
        /// </param>
        /// <param name="advisor">
        /// The <see cref="Spring.Aop.IIntroductionAdvisor"/> to add.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <paramref name="advisor"/> cannot be added.
        /// </exception>
        void AddAdvisor(int index, IAdvisor advisor);

        /// <summary>
        /// Adds the supplied <paramref name="introductionAdvisor"/> to the list
        /// of <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>.
        /// </summary>
        /// <param name="introductionAdvisor">
        /// The <see cref="Spring.Aop.IIntroductionAdvisor"/> to add.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <paramref name="introductionAdvisor"/> cannot be added.
        /// </exception>
        void AddIntroduction(IIntroductionAdvisor introductionAdvisor);

        /// <summary>
        /// Adds the supplied <paramref name="introductionAdvisor"/> to the list
        /// of <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>.
        /// </summary>
        /// <param name="index">
        /// The index in the <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>
        /// list at which the supplied <paramref name="introductionAdvisor"/>
        /// is to be inserted.
        /// </param>
        /// <param name="introductionAdvisor">
        /// The <see cref="Spring.Aop.IIntroductionAdvisor"/> to add.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <paramref name="introductionAdvisor"/> cannot be added.
        /// </exception>
        void AddIntroduction(int index, IIntroductionAdvisor introductionAdvisor);

        /// <summary> 
        /// Return the index (0 based) of the supplied
        /// <see cref="Spring.Aop.IAdvisor"/> in the interceptor
        /// (advice) chain for this proxy.
        /// </summary>
        /// <remarks>
        /// <p>
        /// The return value of this method can be used to index into
        /// the <see cref="Spring.Aop.Framework.IAdvised.Advisors"/>
        /// list.
        /// </p>
        /// </remarks>
        /// <param name="advisor">
        /// The <see cref="Spring.Aop.IAdvisor"/> to search for.
        /// </param>
        /// <returns>
        /// The zero (0) based index of this advisor, or -1 if the
        /// supplied <paramref name="advisor"/> is not an advisor for this
        /// proxy.
        /// </returns>
        int IndexOf(IAdvisor advisor);

        /// <summary> 
        /// Return the index (0 based) of the supplied
        /// <see cref="Spring.Aop.IIntroductionAdvisor"/> in the introductions
        /// for this proxy.
        /// </summary>
        /// <remarks>
        /// <p>
        /// The return value of this method can be used to index into
        /// the <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>
        /// list.
        /// </p>
        /// </remarks>
        /// <param name="advisor">
        /// The <see cref="Spring.Aop.IIntroductionAdvisor"/> to search for.
        /// </param>
        /// <returns>
        /// The zero (0) based index of this advisor, or -1 if the
        /// supplied <paramref name="advisor"/> is not an introduction advisor
        /// for this proxy.
        /// </returns>
        int IndexOf(IIntroductionAdvisor advisor);

        /// <summary>
        /// Removes the supplied <paramref name="advisor"/> the list of advisors
        /// for this proxy.
        /// </summary>
        /// <param name="advisor">The advisor to remove.</param>
        /// <returns>
        /// <see langword="true"/> if advisor was found in the list of
        /// <see cref="Spring.Aop.Framework.IAdvised.Advisors"/> for this
        /// proxy and was successfully removed; <see langword="false"/> if not
        /// or if the supplied <paramref name="advisor"/> is <cref lang="null"/>.
        /// </returns>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <paramref name="advisor"/> cannot be removed.
        /// </exception>
        bool RemoveAdvisor(IAdvisor advisor);

        /// <summary>
        /// Removes the <see cref="Spring.Aop.IAdvisor"/> at the supplied
        /// <paramref name="index"/> in the
        /// <see cref="Spring.Aop.Framework.IAdvised.Advisors"/> list
        /// from the list of
        /// <see cref="Spring.Aop.Framework.IAdvised.Advisors"/> for this proxy.
        /// </summary>
        /// <param name="index">
        /// The index of the <see cref="Spring.Aop.IAdvisor"/> to remove.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <see cref="Spring.Aop.IAdvisor"/> at the supplied <paramref name="index"/>
        /// cannot be removed; or if the supplied <paramref name="index"/> is out of
        /// range.
        /// </exception>
        void RemoveAdvisor(int index);

        /// <summary>
        /// Removes the supplied <paramref name="advice"/> from the list
        /// of <see cref="Spring.Aop.Framework.IAdvised.Advisors"/>.
        /// </summary>
        /// <param name="advice">
        /// The <see cref="AopAlliance.Aop.IAdvice"/> to remove.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the supplied <paramref name="advice"/> was
        /// found in the list of <see cref="Spring.Aop.Framework.IAdvised.Advisors"/>
        /// and successfully removed.
        /// </returns>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <see cref="AopAlliance.Aop.IAdvice"/> cannot be removed.
        /// </exception>
        bool RemoveAdvice(IAdvice advice);

        /// <summary>
        /// Removes the supplied <paramref name="introduction"/> from the list
        /// of <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>.
        /// </summary>
        /// <param name="introduction">
        /// The <see cref="Spring.Aop.IIntroductionAdvisor"/> to remove.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the supplied <paramref name="introduction"/> was
        /// found in the list of <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>
        /// and successfully removed.
        /// </returns>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <see cref="Spring.Aop.IIntroductionAdvisor"/> cannot be removed.
        /// </exception>
        bool RemoveIntroduction(IIntroductionAdvisor introduction);

        /// <summary>
        /// Removes the <see cref="Spring.Aop.IIntroductionAdvisor"/> at the supplied
        /// <paramref name="index"/> in the list of
        /// <see cref="Spring.Aop.Framework.IAdvised.Introductions"/> for this proxy.
        /// </summary>
        /// <param name="index">The index of the advisor to remove.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <see cref="Spring.Aop.IIntroductionAdvisor"/> at the supplied
        /// <paramref name="index"/> cannot be removed; or if the supplied
        /// <paramref name="index"/> is out of range.
        /// </exception>
        void RemoveIntroduction(int index);

        /// <summary>
        /// Replaces the <see cref="Spring.Aop.IIntroductionAdvisor"/> that
        /// exists at the supplied <paramref name="index"/> in the list of
        /// <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>
        /// with the supplied <paramref name="introduction"/>.
        /// </summary>
        /// <param name="index">
        /// The index of the <see cref="Spring.Aop.IIntroductionAdvisor"/>
        /// in the list of
        /// <see cref="Spring.Aop.Framework.IAdvised.Introductions"/>
        /// that is to be replaced.
        /// </param>
        /// <param name="introduction">
        /// The new (replacement) <see cref="Spring.Aop.IIntroductionAdvisor"/>.
        /// </param>
        /// <exception cref="AopConfigException">
        /// If the supplied <paramref name="index"/> is out of range.
        /// </exception>
        void ReplaceIntroduction(int index, IIntroductionAdvisor introduction);

        /// <summary> 
        /// Replaces the <paramref name="oldAdvisor"/> with the
        /// <paramref name="newAdvisor"/>.
        /// </summary>
        /// <param name="oldAdvisor">
        /// The original (old) advisor to be replaced.
        /// </param>
        /// <param name="newAdvisor">
        /// The new advisor to replace the <paramref name="oldAdvisor"/> with.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the <paramref name="oldAdvisor"/> was
        /// replaced; if the <paramref name="oldAdvisor"/> was not found in the
        /// advisors collection, this method returns <see langword="false"/>
        /// and (effectively) does nothing.
        /// </returns>
        /// <exception cref="AopConfigException">
        /// If this proxy configuration is frozen and the
        /// <paramref name="oldAdvisor"/> cannot be replaced.
        /// </exception>
        /// <seealso cref="Spring.Aop.Framework.ProxyConfig.IsFrozen"/>
        bool ReplaceAdvisor(IAdvisor oldAdvisor, IAdvisor newAdvisor);

        /// <summary>
        /// As <see cref="System.Object.ToString()"/> will normally be passed
        /// straight through to the advised target, this method returns the
        /// <see cref="System.Object.ToString()"/> equivalent for the AOP
        /// proxy itself.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> description of the proxy configuration.
        /// </returns>
        string ToProxyConfigString();
    }
}