#region Licence

/*
 * Copyright © 2002-2007 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 NHibernate;
using Spring.Context;
using Spring.Context.Support;
using Spring.Objects.Factory.Config;
using Spring.Util;

#endregion

namespace Spring.Data.NHibernate.Support
{
    /// <summary>
    /// Holds the references and configuration settings for a <see cref="SessionScope"/> instance. 
    /// References are resolved by looking up the given object names in the root <see cref="IApplicationContext"/> obtained by <see cref="ContextRegistry.GetContext()"/>.
    /// </summary>
    public class ConfigSectionSessionScopeSettings 
        : SessionScopeSettings
    {
        /// <summary>
        /// The default session factory name to use when retrieving the Hibernate session factory from
        /// the root context.
        /// </summary>
        public static readonly string DEFAULT_SESSION_FACTORY_OBJECT_NAME = "SessionFactory";

        private readonly string sessionFactoryObjectName = DEFAULT_SESSION_FACTORY_OBJECT_NAME;
        private readonly string entityInterceptorObjectName = null;

        /// <summary>
        /// Initializes a new <see cref="ConfigSectionSessionScopeSettings"/> instance.
        /// </summary>
        /// <param name="ownerType">The type, who's name will be used to prefix setting variables with</param>
        public ConfigSectionSessionScopeSettings(Type ownerType)
            : this(ownerType, "appSettings")
        {
            // noop
        }

        /// <summary>
        /// Initializes a new <see cref="ConfigSectionSessionScopeSettings"/> instance.
        /// </summary>
        /// <param name="ownerType">The type, who's name will be used to prefix setting variables with</param>
        /// <param name="sectionName">The configuration section to read setting variables from.</param>
        public ConfigSectionSessionScopeSettings(Type ownerType, string sectionName)
            : this(ownerType, new ConfigSectionVariableSource(sectionName))
        {
            // noop
        }

        /// <summary>
        /// Initializes a new <see cref="ConfigSectionSessionScopeSettings"/> instance.
        /// </summary>
        /// <param name="ownerType">The type, who's name will be used to prefix setting variables with</param>
        /// <param name="variableSource">The variable source to obtain settings from.</param>
        public ConfigSectionSessionScopeSettings(Type ownerType, IVariableSource variableSource)
            : base()
        {
            string sessionFactoryObjectNameSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "SessionFactoryObjectName");
            string entityInterceptorObjectNameSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "EntityInterceptorObjectName");
            string singleSessionSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "SingleSession");
            string defaultFlushModeSettingsKey = UniqueKey.GetTypeScopedString(ownerType, "DefaultFlushMode");

            VariableAccessor variables = new VariableAccessor(variableSource);
            this.sessionFactoryObjectName = variables.GetString(sessionFactoryObjectNameSettingsKey, DEFAULT_SESSION_FACTORY_OBJECT_NAME);
            this.entityInterceptorObjectName = variables.GetString(entityInterceptorObjectNameSettingsKey, null);
            this.SingleSession = variables.GetBoolean(singleSessionSettingsKey, this.SingleSession);
            this.DefaultFlushMode = (FlushMode)variables.GetEnum(defaultFlushModeSettingsKey, this.DefaultFlushMode);

            AssertUtils.ArgumentNotNull(sessionFactoryObjectName, "sessionFactoryObjectName"); // just to be sure
        }

        /// <summary>
        /// Resolve the entityInterceptor by looking up <see cref="entityInterceptorObjectName"/> 
        /// in the root application context.
        /// </summary>
        /// <returns>The resolved <see cref="IInterceptor"/> instance or <see langword="null"/></returns>
        protected override IInterceptor ResolveEntityInterceptor()
        {
            if (StringUtils.HasText(entityInterceptorObjectName))
            {
                return (IInterceptor)ContextRegistry.GetContext().GetObject(entityInterceptorObjectName);
            }
            return null;
        }

        /// <summary>
        /// Resolve the <see cref="ISessionFactory"/> by looking up <see cref="sessionFactoryObjectName"/> 
        /// in the root application context.
        /// </summary>
        /// <returns>The resolved <see cref="ISessionFactory"/> instance or <see langword="null"/></returns>
        protected override ISessionFactory ResolveSessionFactory()
        {
            if (StringUtils.HasText(sessionFactoryObjectName))
            {
                return (ISessionFactory)ContextRegistry.GetContext().GetObject(sessionFactoryObjectName);
            }
            return null;
        }
    }
}