// 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 Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
using TERASOLUNA.Fw.Common.Validation.Configuration;

namespace TERASOLUNA.Fw.Common.Validation.Validators
{

    /// <summary>
    /// 検証ルール"日付型範囲チェック"に対応する DateTime 型範囲チェックを行う <see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> 継承クラスです。
    /// </summary>
    /// <remarks>
    /// <para>
    /// 検証対象の値が DateTime 型、または DateTime 型に変換可能な文字列であり、
    /// 指定された範囲に含まれることをチェックする検証機能を提供します。。
    ///  null または空文字に対しては検証は行わないため、<seealso cref="ValueValidator.Negated"/> の状態に関わらず、必ず検証成功となります。 
    /// </para>
    /// <para>
    /// 本クラスを用いて入力値検証を実施するには、入力値検証設定ファイルに記述する
    ///  validator 要素の属性として、以下の設定を行います。
    /// 入力値検証設定ファイル自体の記法については、
    ///  Validation Application Block のドキュメントを参照してください。 
    /// </para>
    /// <para>
    /// <list type="bullet">
    /// <item>
    /// <description>negated</description>
    /// <para>検証ルールを反転するフラグです。 true を設定した場合、検証ルールが反転します。デフォルト値は、 false です。</para>
    /// </item>
    /// <item>
    /// <description>messageTemplate</description>
    /// <para>検証エラーメッセージのテンプレートとして使用する文字列。
    /// 未設定の場合は、<seealso cref="DateTimeRangeValidatorEx.DefaultNonNegatedMessageTemplate"/> 、 <seealso cref="DateTimeRangeValidatorEx.DefaultNegatedMessageTemplate"/> の 
    /// いずれかが使用されます。
    /// </para>
    /// </item>
    /// <item>
    /// <description>messageTemplateResourceName</description>
    /// <para>メッセージテンプレートをリソースから読み込む際の名前。</para>
    /// </item>
    /// <item>
    /// <description>messageTemplateResourceType</description>
    /// <para>メッセージテンプレートをリソースから読み込む際のリソースの型。</para>
    /// </item>
    /// <item>
    /// <description>tag</description>
    /// <para>検証対象項目の名前を指定します。</para>
    /// </item>
    /// <item>
    /// <description>type</description>
    /// <para>使用する <see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> クラスの型を完全修飾型名で指定します。</para>
    /// </item>
    /// <item>
    /// <description>name</description>
    /// <para>使用する <see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> の名前です。フレームワークでは利用されません。
    /// 同時に複数の <see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> を利用した検証を行う場合、重複した名前を使用する
    /// ことはできません。この属性は必須項目です。</para>
    /// </item>
    /// <item>
    /// <description>lowerBound</description>
    /// <para>最小値を表します。デフォルト値は 0 です。</para>
    /// </item>
    /// <item>
    /// <description>lowerBoundType</description>
    /// <para>最小値で指定された値の扱いを指定する<see cref="RangeBoundaryType"/>列挙体の値です。
    ///  <seealso cref="RangeBoundaryType.Inclusive"/> , <seealso cref="RangeBoundaryType.Exclusive"/> , <seealso cref="RangeBoundaryType.Ignore"/> のいずれかを指定します。デフォルト値は <seealso cref="RangeBoundaryType.Ignore"/> (無視する)です。</para>
    /// </item>
    /// <item>
    /// <description>upperBound</description>
    /// <para>最大値を表します。デフォルト値は 0 ( 1 / 1 / 1 )です。</para>
    /// </item>
    /// <item>
    /// <description>upperBoundType</description>
    /// <para>最大値で指定された値の扱いを指定する <see cref="RangeBoundaryType"/> 列挙体の値です。
    ///  <seealso cref="RangeBoundaryType.Inclusive"/> , <seealso cref="RangeBoundaryType.Exclusive"/> , <seealso cref="RangeBoundaryType.Ignore"/> のいずれかを指定します。デフォルト値は <seealso cref="RangeBoundaryType.Inclusive"/> (含む)です。</para>
    /// </item>
    /// </list>
    /// </para>
    /// <example>
    /// <code>
    /// &lt;validator negated="false" lowerBound="7/1/1999" lowerBoundType="Exclusive" upperBound="7/30/1999" 
    /// upperBoundType="Inclusive" messageTemplate="" messageTemplateResourceName=""
    /// messageTemplateResourceType="" tag="検証対象項目名" name="date range validator"  
    /// type="TERASOLUNA.Fw.Common.Validation.Validators.DateTimeRangeValidatorEx,TERASOLUNA.Fw.Common"/&gt;
    /// </code>
    /// </example>
    /// </remarks>
    [ConfigurationElementType(typeof(DateTimeRangeValidatorExData))]
    public class DateTimeRangeValidatorEx : TypeRangeValidator<DateTime>
    {
        /// <summary>
        /// パターンを分析するためのフォーマット。
        /// </summary>
        /// <remarks>
        /// この定数の値は "{0}_{1}" です。
        /// </remarks>
        private static readonly string PATTERN_FORMAT = "{0}_{1}";

        /// <summary>
        /// コンストラクタです。新しい <see cref="DateTimeRangeValidatorEx"/> のインスタンスを初期化します。
        /// </summary>
        /// <param name="lowerBound">最小値。</param>
        /// <param name="lowerBoundType">範囲における最小値の扱いを示す <see cref="RangeBoundaryType"/> 列挙の値。
        /// 指定しない場合、<seealso cref="RangeBoundaryType.Ignore"/>が使用されます。</param>
        /// <param name="upperBound">最大値。</param>
        /// <param name="upperBoundType">範囲における最大値の扱いを示す <see cref="RangeBoundaryType"/> 列挙の値。
        /// 指定しない場合、<seealso cref="RangeBoundaryType.Inclusive"/>が利用されます。</param>
        /// <param name="messageTemplate">検証失敗の際、メッセージを生成するために利用するテンプレート文字列。
        /// 検証に利用するパラメータがプレースホルダに渡されます。
        /// パラメータとそのプレースホルダ番号は以下の通りです。
        /// <list type="table">
        /// <listheader>
        /// <term>プレースホルダ</term>
        /// <description>内容</description>
        /// </listheader>
        /// <item>
        /// <term>{0}</term>
        /// <description>検証対象文字列</description>
        /// </item>
        /// <item>
        /// <term>{1}</term>
        /// <description>key(プロパティ・メソッド名)</description>
        /// </item>
        /// <item>
        /// <term>{2}</term>
        /// <description>Tag文字列</description>
        /// </item>
        /// <item>
        /// <term>{3}</term>
        /// <description>LowerBound</description>
        /// </item>
        /// <item>
        /// <term>{4}</term>
        /// <description>LowerBoundType</description>
        /// </item>
        /// <item>
        /// <term>{5}</term>
        /// <description>UpperBound</description>
        /// </item>
        /// <item>
        /// <term>{6}</term>
        /// <description>UpperBoundType</description>
        /// </item>
        /// </list>
        /// </param>
        /// <param name="negated">検証条件の反転を示すフラグ。
        /// 反転した条件で検証を実施する場合には true を指定します。</param>
        /// <exception cref="ArgumentException">
        /// <list type="bullet">
        /// <item>
        /// <paramref name="lowerBound"/> が <paramref name="upperBound"/> より大きいです。
        /// </item>
        /// <item>
        /// <paramref name="lowerBoundType"/> と <paramref name="upperBoundType"/> がいずれも
        /// <seealso cref="RangeBoundaryType.Ignore"/> です。
        /// </item>
        /// <item>
        /// <paramref name="lowerBound"/> 、<paramref name="upperBound"/> のいずれかが、
        /// <see cref="RangeBoundaryType.Ignore"/> 以外に指定されており、かつ null です。
        /// </item>
        /// </list>
        /// </exception> 
        public DateTimeRangeValidatorEx(DateTime lowerBound,
                                 RangeBoundaryType lowerBoundType,
                                 DateTime upperBound,
                                 RangeBoundaryType upperBoundType,
                                 string messageTemplate,
                                 bool negated)
            : base(lowerBound, lowerBoundType, upperBound, upperBoundType, messageTemplate, negated)
        { }

        /// <summary>
        /// 日付型に型指定された範囲チェック <see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> で利用する、
        /// <seealso cref="ValueValidator.Negated"/> が true である場合に使用されるデフォルトのメッセージテンプレートを取得します。
        /// </summary>
        /// <value>検証ルール反転時のデフォルトメッセージテンプレート文字列。</value>
        protected override string DefaultNegatedMessageTemplate
        {
            get
            {
                string pattern = string.Format(PATTERN_FORMAT, LowerBoundType.ToString(), UpperBoundType.ToString());
                string result = null;
                switch (pattern)
                {
                    case IGNORE_INCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_IG_IN_MESSAGETEMPLATE;
                        break;
                    case IGNORE_EXCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_IG_EX_MESSAGETEMPLATE;
                        break;
                    case INCLUSIVE_IGNORE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_IN_IG_MESSAGETEMPLATE;
                        break;
                    case INCLUSIVE_INCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_IN_IN_MESSAGETEMPLATE;
                        break;
                    case INCLUSIVE_EXCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_IN_EX_MESSAGETEMPLATE;
                        break;
                    case EXCLUSIVE_IGNORE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_EX_IG_MESSAGETEMPLATE;
                        break;
                    case EXCLUSIVE_INCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_EX_IN_MESSAGETEMPLATE;
                        break;
                    case EXCLUSIVE_EXCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NEGATED_EX_EX_MESSAGETEMPLATE;
                        break;
                    default:
                        result = base.DefaultNegatedMessageTemplate;
                        break;
                }
                return result;
            }

        }

        /// <summary>
        /// 日付型に型指定された範囲チェック s<see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> で利用する、
        /// <seealso cref="ValueValidator.Negated"/> が false である場合に使用されるデフォルトのメッセージテンプレートを取得します。
        /// </summary>
        /// <value>デフォルトメッセージテンプレート文字列。</value>
        protected override string DefaultNonNegatedMessageTemplate
        {
            get
            {
                string pattern = string.Format(PATTERN_FORMAT, LowerBoundType.ToString(), UpperBoundType.ToString());
                string result = null;
                switch (pattern)
                {
                    case IGNORE_INCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_IG_IN_MESSAGETEMPLATE;
                        break;
                    case IGNORE_EXCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_IG_EX_MESSAGETEMPLATE;
                        break;
                    case INCLUSIVE_IGNORE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_IN_IG_MESSAGETEMPLATE;
                        break;
                    case INCLUSIVE_INCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_IN_IN_MESSAGETEMPLATE;
                        break;
                    case INCLUSIVE_EXCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_IN_EX_MESSAGETEMPLATE;
                        break;
                    case EXCLUSIVE_IGNORE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_EX_IG_MESSAGETEMPLATE;
                        break;
                    case EXCLUSIVE_INCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_EX_IN_MESSAGETEMPLATE;
                        break;
                    case EXCLUSIVE_EXCLUSIVE:
                        result = Properties.Resources.DATETIME_RANGE_VALIDATOR_NONNEGATED_EX_EX_MESSAGETEMPLATE;
                        break;
                    default:
                        result = base.DefaultNonNegatedMessageTemplate;
                        break;
                }
                return result;
            }
        }
    }
}
