/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * 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.
 */
package woolpack.visitor.impl;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Locale;

import junit.framework.TestCase;
import woolpack.dom.DomContext;
import woolpack.locale.BranchByLocaleValidator;
import woolpack.test.TestUtils;
import woolpack.utils.SwitchBuilder;
import woolpack.validator.BranchByIdValidator;
import woolpack.validator.BranchByNameIfExistsValidator;
import woolpack.validator.BranchByNameValidator;
import woolpack.validator.CountValidator;
import woolpack.validator.DefaultValueValidator;
import woolpack.validator.DelegationValidator;
import woolpack.validator.DumpValidator;
import woolpack.validator.EqualsValidator;
import woolpack.validator.FormatValidator;
import woolpack.validator.IfNotValidator;
import woolpack.validator.IfValidator;
import woolpack.validator.MaxLengthValidator;
import woolpack.validator.MaxValidator;
import woolpack.validator.MessageValidator;
import woolpack.validator.MinLengthValidator;
import woolpack.validator.MinValidator;
import woolpack.validator.NotValidator;
import woolpack.validator.ParseValidator;
import woolpack.validator.RegExpIdValidator;
import woolpack.validator.RegExpValidator;
import woolpack.validator.RetainNamesValidator;
import woolpack.validator.SerialValidator;
import woolpack.validator.TmpIndexValidator;
import woolpack.validator.TmpKeyValidator;
import woolpack.validator.ValidNamesValidator;
import woolpack.validator.ValidValuesValidator;
import woolpack.validator.ValidatorConstants;
import woolpack.validator.ValidatorExpression;
import woolpack.validator.ValueLoopValidator;
import woolpack.visitor.Visitor;

public class DocValidatorConstantsTest extends TestCase {

	private void scenario(final Object expression, final String expected) {
		final DomContext context = new DomContext();
		TestUtils.getToNode("<HTML><BODY></BODY></HTML>").interpret(context);
		final Visitor visitor = new Visitor();
		visitor.setMap(DocValidatorConstants.MAP);
		visitor.setContext(context.getNode().getFirstChild().getFirstChild());
		visitor.visit(expression);
		assertTrue(TestUtils.equalsBody(context, expected));
	}

	public void testBranchByIdValidator() {
		scenario(
				new BranchByIdValidator(
						new SwitchBuilder<String, ValidatorExpression>().put(
								"id0", new MessageValidator("message0")).get()),
				"リクエスト ID によって以下分岐する。<dl><dt>id0</dt><dd>メッセージ\"message0\"を出力する。</dd><dt>デフォルト</dt><dd>なにもしない。</dd></dl>");
	}

	public void testBranchByNameIfExistsValidator() {
		scenario(
				new BranchByNameIfExistsValidator(
						new SwitchBuilder<String, ValidatorExpression>().put(
								"key0", new MessageValidator("message0")).get()),
				"リクエストされた変数名により以下分岐し、論理積(全部評価する)で全体の検証結果を判定する。<dl><dt>key0</dt><dd>メッセージ\"message0\"を出力する。</dd><dt>デフォルト</dt><dd>なにもしない。</dd></dl>");
	}

	public void testBranchByNameValidator() {
		scenario(
				new BranchByNameValidator(
						new SwitchBuilder<String, ValidatorExpression>().put(
								"key0", new MessageValidator("message0")).get()),
				"指定された変数名により以下分岐し、論理積(全部評価する)で全体の検証結果を判定する。<dl><dt>key0</dt><dd>メッセージ\"message0\"を出力する。</dd><dt>デフォルト</dt><dd>なにもしない。</dd></dl>");
	}

	public void testCountValidator() {
		scenario(new CountValidator(new MessageValidator("message0")),
				"メッセージ\"message0\"を出力する。");
	}

	public void testDefaultValueValidator1() {
		scenario(new DefaultValueValidator("message0"), "値を\"message0\"に設定する。");
	}

	public void testDefaultValueValidator2() {
		scenario(new DefaultValueValidator(new MessageValidator("message0")),
				"値を\"メッセージ\"message0\"を出力する。\"に設定する。");
	}

	public void testDelegationValidator() {
		scenario(new DelegationValidator(new MessageValidator("message0")),
				"メッセージ\"message0\"を出力する。");
	}

	public void testDumpValidator() {
		scenario(new DumpValidator(new MessageValidator("message0")),
				"メッセージ\"message0\"を出力する。");
	}

	public void testEqualsValidator1() {
		scenario(new EqualsValidator("message0"), "値が\"message0\"と同値");
	}

	public void testEqualsValidator2() {
		scenario(new EqualsValidator(new MessageValidator("message0")),
				"値が\"メッセージ\"message0\"を出力する。\"と同値");
	}

	public void testFormatValidator() {
		scenario(new FormatValidator(new DecimalFormat()),
				"パターン\"#,##0.###\"の数値フォーマットによって文字列に変換する。");
	}

	public void testIfNotValidator() {
		scenario(new IfNotValidator(new EqualsValidator("message0"),
				new MessageValidator("message1")),
				"値が\"message0\"と同値そうでない場合メッセージ\"message1\"を出力する。");
	}

	public void testIfValidator() {
		scenario(new IfValidator(new EqualsValidator("message0"),
				new MessageValidator("message1"), new MessageValidator(
						"message2")),
				"値が\"message0\"と同値である場合メッセージ\"message1\"を出力する。そうでない場合メッセージ\"message2\"を出力する。");
	}

	public void testMaxLengthValidator() {
		scenario(new MaxLengthValidator(1), "文字列の長さが1以下");
	}

	public void testMaxValidator() {
		scenario(new MaxValidator(1), "数値が1以下");
	}

	public void testMessageValidator() {
		scenario(new MessageValidator("message0"), "メッセージ\"message0\"を出力する。");
	}

	public void testMinLengthValidator() {
		scenario(new MinLengthValidator(1), "文字列の長さが1以上");
	}

	public void testMinValidator() {
		scenario(new MinValidator(1), "数値が1以上");
	}

	public void testNotValidator() {
		scenario(new NotValidator(new MessageValidator("message0")),
				"以下の評価を否定する。<div>メッセージ\"message0\"を出力する。</div>");
	}

	public void testParseValidator() {
		scenario(new ParseValidator(new SimpleDateFormat()),
				"パターン\"yy/MM/dd H:mm\"の日付フォーマットによって文字列を変換する。");
	}

	public void testRegExpIdValidator() {
		scenario(new RegExpIdValidator(".*"), "リクエスト ID が正規表現\".*\"に合致");
	}

	public void testRegExpValidator() {
		scenario(new RegExpValidator(".*"), "値が正規表現\".*\"に合致");
	}

	public void testRetainNamesValidator() {
		scenario(
				new RetainNamesValidator(Arrays.asList("message0", "message1")),
				"以下に挙げる変数名以外を取り除く<div>message0, message1</div>");
	}

	public void testSerialValidator() {
		scenario(
				new SerialValidator(new MessageValidator("message0"),
						new MessageValidator("message1")),
				"以下の処理を順次実行し、論理積で全体の検証結果を判定する。<ol><li>メッセージ\"message0\"を出力する。</li><li>メッセージ\"message1\"を出力する。</li></ol>");
	}

	public void testTmpIndexValidator() {
		scenario(new TmpIndexValidator(1, new MessageValidator("message0")),
				"取得先インデックスを1に設定して以下を実行する。<div>メッセージ\"message0\"を出力する。</div>");
	}

	public void testTmpKeyValidator() {
		scenario(new TmpKeyValidator("key0", new MessageValidator("message0")),
				"取得先変数名を\"key0\"に設定して以下を実行する。<div>メッセージ\"message0\"を出力する。</div>");
	}

	public void testTrueValidator() {
		scenario(ValidatorConstants.TRUE, "なにもしない。");
	}

	public void testFalseValidator() {
		scenario(ValidatorConstants.FALSE, "値検証を失敗とする。");
	}

	public void testRequiredValidator() {
		scenario(ValidatorConstants.REQUIRED, "値が入力されている状態");
	}

	public void testOrValidatorIterable() {
		scenario(ValidatorConstants.OR, "論理和(全部評価する)");
	}

	public void testOrOrValidatorIterable() {
		scenario(ValidatorConstants.OROR, "論理和");
	}

	public void testAndValidatorIterable() {
		scenario(ValidatorConstants.AND, "論理積(全部評価する)");
	}

	public void testAndAndValidatorIterable() {
		scenario(ValidatorConstants.ANDAND, "論理積");
	}

	public void testEqValidatorIterable() {
		scenario(ValidatorConstants.EQ, "同値(全部評価する)");
	}

	public void testEqEqValidatorIterable() {
		scenario(ValidatorConstants.EQEQ, "同値");
	}

	public void testValidNamesValidator() {
		scenario(
				new ValidNamesValidator(Arrays.asList("message0", "message1")),
				"以下にあげる変数名のみ含まれている<div>message0, message1</div>");
	}

	public void testValidValuesValidator() {
		scenario(
				new ValidValuesValidator(Arrays.asList("message0", "message1")),
				"以下にあげる値のいずれかである<div>message0, message1</div>");
	}

	public void testValueLoopValidator() {
		scenario(
				new ValueLoopValidator(new MessageValidator("message0")),
				"変数一覧に対し以下の処理を順次実行し、論理積(全部評価する)で全体の検証結果を判定する。<div>メッセージ\"message0\"を出力する。</div>");
	}

	public void testBranchByLocaleValidator1() {
		scenario(
				new BranchByLocaleValidator(
						new SwitchBuilder<Locale, ValidatorExpression>().put(
								Locale.JAPANESE,
								new MessageValidator("message0")).put(
								Locale.ENGLISH,
								new MessageValidator("message1")).get(
								new MessageValidator("message2")),
						new ThreadLocal<Locale>()),
				"ロケールによって以下分岐する。<dl><dt>ja</dt><dd>メッセージ\"message0\"を出力する。</dd><dt>en</dt><dd>メッセージ\"message1\"を出力する。</dd><dt>デフォルト</dt><dd>メッセージ\"message2\"を出力する。</dd></dl>");
	}

	public void testBranchByLocaleValidator2() {
		scenario(
				new BranchByLocaleValidator(
						new SwitchBuilder<Locale, ValidatorExpression>().put(
								Locale.JAPANESE,
								new MessageValidator("message0")).put(
								Locale.ENGLISH,
								new MessageValidator("message1")).get(),
						new ThreadLocal<Locale>()),
				"ロケールによって以下分岐する。<dl><dt>ja</dt><dd>メッセージ\"message0\"を出力する。</dd><dt>en</dt><dd>メッセージ\"message1\"を出力する。</dd></dl>");
	}
}
