// 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 または空文字列に対しては検証は行わないため、 <see 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="NumericStringValidator.DefaultNonNegatedMessageTemplate"/> 、 <seealso cref="NumericStringValidator.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>使用するValidatorクラスの型を完全修飾型名で指定します。</para>
    /// </item>
    /// <item>
    /// <description>name</description>
    /// <para>使用する <see cref="Microsoft.Practices.EnterpriseLibrary.Validation.Validator"/> に名前をつけます。特に利用しない値です。 
    /// 任意の名前をつけることができますが、同一の検証対象の場合、同一の名前をつけることは許されません。
    /// また、空文字列も許されません。必須です。</para>
    /// </item>
    /// <item>
    /// <description>characterSet</description>
    /// <para>チェック対象の文字。</para>
    /// </item>
    /// <item>
    /// <description>containsCharacter</description>
    /// <para>文字のチェック方式です。</para>
    /// </item>
    /// </list>
    /// </para>
    /// <example>
    /// <code>
    /// &lt;validator characterSet="qwerty" containsCharacter="All" negated="true"
    /// messageTemplate="" messageTemplateResourceName="" messageTemplateResourceType=""  tag=""
    /// type="TERASOLUNA.FW.Common.Validation.Validators. ContainsCharactersValidatorEx,TERASOLUNA.FW.Common.Validation"
    /// name="Contains Characters Ex Validator" /&gt;
    /// </code>
    /// </example>
    /// </remarks>
    [ConfigurationElementType(typeof(ContainsCharactersValidatorExData))]
    public class ContainsCharactersValidatorEx : ContainsCharactersValidator
    {
        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスです。
        /// </summary>
        /// <remarks>
        /// ログ出力に利用します。
        /// </remarks>
        private static ILog _log = LogFactory.GetLogger(typeof(ContainsCharactersValidatorEx));

        /// <summary>
        /// 検証の振る舞いを保持する <see cref="ContainsCharacters"/>クラスのインスタンス。
        /// </summary>
        private ContainsCharacters _containsCharacters = ContainsCharacters.Any;

        /// <summary>
        /// <see cref="ContainsCharactersValidatorEx"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="characterSet">チェック対象の文字列。</param>
        /// <param name="containsCharacters">文字のチェック方式。</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>チェック対象の文字</description>
        /// </item>
        /// <item>
        /// <term>{4}</term>
        /// <description>文字のチェック方式</description>
        /// </item>
        /// </list>
        /// </param>
        /// <param name="negated">検証ルールを反転するフラグ。</param>
        public ContainsCharactersValidatorEx(string characterSet, ContainsCharacters containsCharacters, string messageTemplate, bool negated)
            : base(characterSet, containsCharacters, messageTemplate, negated)
        {
            _containsCharacters = containsCharacters;
        }

        /// <summary>
        /// 文字列存在チェックValidatorで利用する、
        /// <seealso cref="ValueValidator.Negated"/> が true である場合に使用されるデフォルトのメッセージテンプレートを取得します。
        /// </summary>
        /// <value>検証ルール反転時のデフォルトメッセージテンプレート文字列。</value>
        protected override string DefaultNegatedMessageTemplate
        {
            get
            {
                if (_containsCharacters == ContainsCharacters.All)
                {
                    return Properties.Resources.CONTAINS_VALIDATOR_ALL_NEGATED_MESSAGETEMPLATE;
                }
                else
                {
                    return Properties.Resources.CONTAINS_VALIDATOR_ANY_NEGATED_MESSAGETEMPLATE;
                }
            }
        }

        /// <summary>
        /// 文字列存在チェックValidatorで利用する、
        /// <seealso cref="ValueValidator.Negated"/> が false である場合に使用されるデフォルトのメッセージテンプレートを取得します。
        /// </summary>
        /// <value>デフォルトメッセージテンプレート文字列。</value>
        protected override string DefaultNonNegatedMessageTemplate
        {
            get
            {
                if (_containsCharacters == ContainsCharacters.All)
                {
                    return Properties.Resources.CONTAINS_VALIDATOR_ALL_NONNEGATED_MESSAGETEMPLATE;
                }
                else
                {
                    return Properties.Resources.CONTAINS_VALIDATOR_ANY_NONNEGATED_MESSAGETEMPLATE;
                }
            }
        }

        /// <summary>
        /// 必須文字列チェックを行うメソッドです。
        /// 検証対象文字列が、指定した文字を含んでいるかのチェックします。
        /// </summary>
        /// <remarks>
        /// <para>
        /// <paramref name="objectToValidate"/> が null または空文字列の場合、
        /// 検証処理は行われず、検証結果は必ず成功となります。
        /// negatedがtrueの場合、検証条件が反転します。
        /// </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(string 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 (string.IsNullOrEmpty(objectToValidate))
            {
                return;
            }

            base.DoValidate(objectToValidate, currentTarget, key, validationResults);
        }

    }
}
