// 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.Client.Configuration.Conversion;
using TERASOLUNA.Fw.Client.Configuration.View;
using TERASOLUNA.Fw.Common;
using TERASOLUNA.Fw.Common.Configuration;
using TERASOLUNA.Fw.Common.Logging;

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

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

        /// <summary>
        /// viewConfigurationSection セクションを保持します。
        /// </summary>
        private static ViewConfigurationSection _viewConfigSection = null;

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

        /// <summary>
        /// conversionConfiguration セクションを保持します。
        /// </summary>
        private static ConversionConfigurationSection _conversionConfigSection = null;

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

        /// <summary>
        /// <see cref="ViewConfigurationSection"/> を取得します。
        /// </summary>
        /// <remarks>
        /// <see cref="ConfigurationManager.GetSection"/> メソッドを使用して、
        /// <see cref="ViewConfigurationSection"/> を取得します。
        /// </remarks>
        public static ViewConfigurationSection ViewConfigSection
        {
            get
            {
                if (_viewConfigSection == null)
                {
                    lock (_syncRoot)
                    {
                        if (_viewConfigSection == null)
                        {
                            object fcsObject = ConfigurationManager.GetSection(VIEW_CONFIGURATION_NAME);
                            if (fcsObject == null)
                            {
                                return null;
                            }

                            ViewConfigurationSection fcs = fcsObject as ViewConfigurationSection;
                            if(fcs == null)
                            {
                                string message = string.Format(
                                    Properties.Resources.E_CONFIGURATION_INVALID_CAST, "ViewConfiguration", fcsObject.GetType().FullName);
                                ConfigurationErrorsException exception = new ConfigurationErrorsException(message);
                                if (_log.IsErrorEnabled)
                                {
                                    _log.Error(message, exception);
                                }
                                throw exception;
                            }

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

        /// <summary>
        /// <see cref="ConversionConfigurationSection"/> を取得します。
        /// </summary>
        /// <remarks>
        /// <see cref="ConfigurationManager.GetSection"/> メソッドを使用して、
        /// <see cref="ConversionConfigurationSection"/> を取得します。
        /// <para>
        /// アプリケーション構成ファイルに、構成セクション ConversionConfiguration が存在しない場合は 
        /// <see cref="ConfigurationErrorsException"/> が発生します。
        /// </para>
        /// </remarks>
        /// <exception cref="TerasolunaException">
        /// 構成セクションに指定したタイプが <see cref="ConversionConfigurationSection"/> ではありません。
        /// </exception>
        public static ConversionConfigurationSection ConversionConfigSection
        {
            get
            {
                if (_conversionConfigSection == null)
                {
                    lock (_syncRoot)
                    {
                        if (_conversionConfigSection == null)
                        {
                            object dcsObject = ConfigurationManager.GetSection(CONVERSION_CONFIGURAION_SECTION_NAME);
                            if (dcsObject == null)
                            {
                                return null;
                            }

                            ConversionConfigurationSection dcs = dcsObject as ConversionConfigurationSection;
                            if(dcs == null)
                            {
                                string message = string.Format(
                                    Properties.Resources.E_CONFIGURATION_INVALID_CAST, "ConversionConfiguration", dcsObject.GetType().FullName);
                                ConfigurationErrorsException exception = new ConfigurationErrorsException(message);
                                if (_log.IsErrorEnabled)
                                {
                                    _log.Error(message, exception);
                                }
                                throw exception;
                            }

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