// Copyright (c) 2008, NTT DATA Corporation.
//
// 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.

using System;
using System.Configuration;
using System.Text;
using TERASOLUNA.Fw.Common.Configuration.BLogic;
using TERASOLUNA.Fw.Common.Logging;

namespace TERASOLUNA.Fw.Common.Configuration
{
    /// <summary>
    /// アプリケーションの構成ファイルから、
    ///  TERASOLUNA が提供する設定ファイルの設定情報を取得します。
    /// </summary>
    /// <remarks>
    /// 以下の設定ファイルから設定情報を取得します。
    /// <list type="bullet">
    /// <item>ビジネスロジック設定ファイル</item>
    /// </list>
    /// </remarks>
    public abstract class TerasolunaConfiguration
    {
        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスです。
        /// </summary>
        /// <remarks>
        /// ログ出力に利用します。
        /// </remarks>
        private static ILog _log = LogFactory.GetLogger(typeof(TerasolunaConfiguration));

        /// <summary>
        /// BLogicConfigurationSection の要素名です。
        /// </summary>
        /// <remarks>
        /// この定数の値は "blogicConfiguration" です。
        /// </remarks>
        private static readonly string BLOGIC_CONFIGURATION_SECTION_NAME = "blogicConfiguration";

        /// <summary>
        /// blogicConfiguration セクションを保持します。
        /// </summary>
        /// <remarks>
        /// デフォルトの値は、 null です。
        /// </remarks>
        private static BLogicConfigurationSection _blogicConfigSection = null;

        /// <summary>
        /// ロック用のオブジェクトです。
        /// </summary>
        private static object _syncRoot = new Object();

        /// <summary>
        /// BLogicConfigurationSection を取得します。
        /// </summary>
        /// <remarks>
        /// <see cref="ConfigurationManager.GetSection"/> メソッドを使用して、
        /// <see cref="BLogicConfigurationSection"/> を取得します。
        /// </remarks>
        /// <exception cref="ConfigurationErrorsException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// "blogicConfiguration" をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 解決した型は、 <see cref="BLogicConfigurationSection"/> 型ではない。
        /// </item>
        /// <item>
        /// 構成ファイルを読み込むことができませんでした。
        /// </item>
        /// </list>
        /// </exception>
        public static BLogicConfigurationSection BLogicConfigSection
        {
            get
            {
                if (_blogicConfigSection == null)
                {
                    lock (_syncRoot)
                    {
                        if (_blogicConfigSection == null)
                        {
                            object bcsObject = ConfigurationManager.GetSection(BLOGIC_CONFIGURATION_SECTION_NAME);
                            if (bcsObject == null)
                            {
                                return null;
                            }

                            BLogicConfigurationSection bcs = bcsObject as BLogicConfigurationSection;                          
                            if(bcs == null)
                            {
                                string message = string.Format(
                                    Properties.Resources.E_CONFIGURATION_INVALID_CAST, "BLogicConfiguration", bcsObject.GetType().FullName);
                                ConfigurationErrorsException exception = new ConfigurationErrorsException(message);
                                if (_log.IsErrorEnabled)
                                {
                                    _log.Error(message, exception);
                                }
                                throw exception;
                            }

                            bcs.CreateBLogicElements();
                            _blogicConfigSection = bcs;
                            if (_log.IsTraceEnabled)
                            {
                                StringBuilder message = new StringBuilder();
                                message.AppendLine(string.Format(Properties.Resources.T_CONFIGURATION_LOAD_PARAMETER, "BLogicConfiguration", "files"));
                                foreach (FileElement element in bcs.Files)
                                {
                                    message.AppendLine(string.Format(Properties.Resources.T_CONFIGURATION_LOAD_KEY, "path", element.Path));
                                }
                                _log.Trace(message.ToString().Trim());
                            }
                        }
                    }
                }
                return _blogicConfigSection;
            }
        }
    }
}
