/*
 * 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;
import woolpack.visitor.impl.DocValidatorConstants;

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>");
	}
}
