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

namespace TERASOLUNA.Fw.Common.Validation.Validators
{
    /// <summary>
    /// 検証ルール"全角カナ文字列チェック"に対応する全角カナ文字種チェックを行う <see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> 継承クラスです。
    /// </summary>
    /// <remarks>
    /// <para>
    /// 検証対象の値が文字列表現であり、
    /// 全ての文字が全角カナ文字であることをチェックする検証機能を提供します。
    ///  null または空文字列に対しては検証は行わないため、 <seealso cref="ValueValidator.Negated"/> の状態に関わらず、必ず検証成功となります。 
    /// </para>
    /// <para>
    /// 文字種のチェックに利用するロジックを変更する場合、派生クラスを作成し、 <see cref="ZenkakuKanaStringValidator.IsZenkakuKanaString"/> 
    /// メソッドをオーバーライドします。
    /// </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>検証エラーメッセージのテンプレートとして使用する文字列。
    /// 未設定の場合は、 <see cref="ZenkakuKanaStringValidator.DefaultNonNegatedMessageTemplate"/> 、 <see cref="ZenkakuKanaStringValidator.DefaultNegatedMessageTemplate"/> の 
    /// いずれかが使用されます。
    /// </para>
    /// </item>
    /// <item>
    /// <description>messageTemplateResourceName</description>
    /// <para>メッセージテンプレートをリソースから読み込む際の名前。</para>
    /// </item>
    /// <item>
    /// <description>messageTemplateResourceType</description>
    /// <para>メッセージテンプレートをリソースから読み込む際のリソースの型。</para>
    /// </item>
    /// <item>
    /// <description>tag</description>
    /// <para>メッセージテンプレートのプレースホルダ{2}に渡される文字列。
    /// 検証対象項目の論理名を指定します。</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>
    /// </list>
    /// </para>
    /// <example>
    /// <code>
    /// &lt;validator negated="false"  
    /// messageTemplate="" messageTemplateResourceName=""
    /// messageTemplateResourceType="" tag="検証対象項目名" name="zenkaku kana validator"  
    /// type="TERASOLUNA.Fw.Common.Validation.Validators.ZenkakuKanaStringValidator,TERASOLUNA.Fw.Common"/&gt;
    /// </code>
    /// </example>
    /// </remarks>
    [ConfigurationElementType(typeof(ZenkakuKanaStringValidatorData))]
    public class ZenkakuKanaStringValidator : ValueValidator
    {
        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスです。
        /// </summary>
        /// <remarks>
        /// ログ出力に利用します。
        /// </remarks>
        private static ILog _log = LogFactory.GetLogger(typeof(ZenkakuKanaStringValidator));

        /// <summary>
        /// 新しい <see cref="ZenkakuKanaStringValidator"/> のインスタンスを初期化します。
        /// </summary>
        /// <param name="tag">検証対象の項目名。検証失敗の際、メッセージ生成に利用されます。</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>
        /// </list>
        /// </param>
        /// <param name="negated">検証条件の反転を示すフラグ。
        /// 反転した条件で検証を実施する場合には true を指定します。</param>
        public ZenkakuKanaStringValidator(string messageTemplate, string tag, bool negated)
            : base(messageTemplate, tag, negated)
        {
        }

        /// <summary>
        /// <seealso cref="ValueValidator.Negated"/> が true である場合に使用されるデフォルトのメッセージテンプレートを取得します。
        /// </summary>
        /// <value>検証ルール反転時のデフォルトメッセージテンプレート文字列。</value>
        protected override string DefaultNegatedMessageTemplate
        {
            get { return Properties.Resources.ZENKAKUKANA_STRING_VALIDATOR_NEGATED_MESSAGETEMPLATE; }
        }

        /// <summary>
        /// <seealso cref="ValueValidator.Negated"/> が false である場合に使用されるデフォルトのメッセージテンプレートを取得します。
        /// </summary>
        /// <value>デフォルトメッセージテンプレート文字列。</value>
        protected override string DefaultNonNegatedMessageTemplate
        {
            get { return Properties.Resources.ZENKAKUKANA_STRING_VALIDATOR_NONNEGATED_MESSAGETEMPLATE; }
        }

        /// <summary>
        /// 全角カナ文字種チェックを行うメソッドです。検証対象値の文字列表現が、
        /// 全角カナのみで構成されない場合、検証失敗となります。
        /// </summary>
        /// <remarks>
        /// <para>
        /// <paramref name="objectToValidate"/> が null または空文字列の場合、検証処理は行われません。
        /// </para>
        /// </remarks>
        /// <param name="objectToValidate">検証対象の値。</param>
        /// <param name="currentTarget">検証対象のオブジェクト。</param>
        /// <param name="key">検証対象のプロパティ名またはメソッド名。</param>
        /// <param name="validationResults">検証結果を格納する <see cref="ValidationResults"/> 。</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="validationResults"/> が null 参照です。
        /// </exception> 
        protected override void DoValidate(object objectToValidate,
                                           object currentTarget,
                                           string key,
                                           ValidationResults validationResults)
        {
            if (validationResults == null)
            {
                ArgumentNullException exception = new ArgumentNullException("validationResults");
                if (_log.IsErrorEnabled)
                {
                    _log.Error(string.Format(
                        Properties.Resources.E_NULL_ARGUMENT, "validationResults"), exception);
                }
                throw exception;
            }

            if (objectToValidate == null || string.IsNullOrEmpty(objectToValidate.ToString()))
            {
                return;
            }

            if (IsZenkakuKanaString(objectToValidate.ToString()) == Negated)
            {
                LogValidationResult(validationResults,
                                    GetMessage(objectToValidate, key),
                                    currentTarget,
                                    key);
            }

        }

        /// <summary>
        /// <paramref name="str"/> が全角カナのみで構成される文字列であるかどうかを判定します。
        /// </summary>
        /// <param name="str">判定対象文字列。</param>
        /// <returns><paramref name="str"/> が全角カナのみで構成される場合 true 、そうでない場合 false 。</returns>
        protected virtual bool IsZenkakuKanaString(string str)
        {
            return CaseCheckUtil.IsZenkakuKanaString(str);
        }
    }
}
