//===============================================================================
// Microsoft patterns & practices Enterprise Library
// Core
//===============================================================================
// Copyright © Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================

using System;
using System.Configuration;


using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Manageability.Adm;

namespace Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Manageability
{
    /// <summary>
    /// Represents the behavior required to provide Group Policy updates for a <see cref="NamedConfigurationElement"/>.
    /// </summary>
    /// <remarks>
    /// Subclasses define the implementation necessary to provide manageability for a specific type of configuration
    /// element.
    /// Element providers are usually necessary when dealing with collections of <see cref="NameTypeConfigurationElement"/>,
    /// as the concrete type of the elements in the collections is only known at runtime, and it is possible that 
    /// the elements are defined in 'extension' assemblies.
    /// Element providers are registered with the configuration element types they provide manageability to using 
    /// the <see cref="ConfigurationElementManageabilityProviderAttribute"/> attribute, which is bound to assemblies.
    /// Element providers are also responsible for generating the ADM instructions that describe the policies that can be
    /// used to override the values in the configuration elements. Usually the ADM instructions generated by element providers
    /// consist of a single policy with parts that map to the specific configuration element instance of the type the provider 
    /// manages. This is not mandatory, however, and the ADM instructions generated by element providers must be consistent 
    /// with the ADM structure determined by the section provider that interacts with them.
    /// ADM instructions must be generated for each element instance in a given context, using the elements' names to build
    /// each instruction key.
    /// </remarks>
    /// <seealso cref="ConfigurationSectionManageabilityProvider"/>
    /// <seealso cref="ConfigurationElementManageabilityProviderAttribute"/>
    public abstract class ConfigurationElementManageabilityProvider
    {
        /// <summary>
        /// The name of the value used to hold policy enablement status.
        /// </summary>
        public const String PolicyValueName = ConfigurationSectionManageabilityProvider.PolicyValueName;

        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigurationElementManageabilityProvider"/> class.
        /// </summary>
        protected ConfigurationElementManageabilityProvider()
        { }

        /// <summary>
        /// Adds the ADM instructions that describe the policies that can be used to override the properties of
        /// a specific instance of the configuration element type managed by the receiver.
        /// </summary>
        /// <param name="contentBuilder">The <see cref="AdmContentBuilder"/> to which the Adm instructions are to be appended.</param>
        /// <param name="configurationObject">The configuration object instance.</param>
        /// <param name="configurationSource">The configuration source from where to get additional configuration
        /// information, if necessary.</param>
        /// <param name="parentKey">The key path for which the generated instructions' keys must be subKeys of.</param>
        /// <remarks>
        /// ADM instructions are generated on a per-instance basis.
        /// </remarks>
        public abstract void AddAdministrativeTemplateDirectives(AdmContentBuilder contentBuilder,
            ConfigurationElement configurationObject,
            IConfigurationSource configurationSource,
            String parentKey);

        /// <summary>
        /// Overrides the <paramref name="configurationObject"/>'s properties with the Group Policy values from the 
        /// registry, if any.
        /// </summary>
        /// <param name="configurationObject">The configuration object for instances that must be managed.</param>
        /// <param name="readGroupPolicies"><see langword="true"/> if Group Policy overrides must be applied; otherwise, 
        /// <see langword="false"/>.</param>
        /// <param name="machineKey">The <see cref="IRegistryKey"/> which holds the Group Policy overrides for the 
        /// configuration element at the machine level, or <see langword="null"/> 
        /// if there is no such registry key.</param>
        /// <param name="userKey">The <see cref="IRegistryKey"/> which holds the Group Policy overrides for the 
        /// configuration element at the user level, or <see langword="null"/> 
        /// if there is no such registry key.</param>
        /// <returns><see langword="true"/> if the policy settings do not disable the configuration element, otherwise
        /// <see langword="false"/>.</returns>
        /// <exception cref="ArgumentException">when the type of <paramref name="configurationObject"/> is not 
        /// the type.</exception>
        public abstract bool OverrideWithGroupPolicies(ConfigurationElement configurationObject,
            bool readGroupPolicies, IRegistryKey machineKey, IRegistryKey userKey);

        /// <summary>
        /// Logs an error detected while overriding a configuration object with policy values.
        /// </summary>
        /// <param name="exception">The exception representing the error.</param>
        protected virtual void LogExceptionWhileOverriding(Exception exception)
        {
            ManageabilityExtensionsLogger.LogExceptionWhileOverriding(exception);
        }
    }
}
