/*
 * 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.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;

import woolpack.locale.BranchByLocaleValidator;
import woolpack.text.DelegateDateFormat;
import woolpack.text.DelegateNumberFormat;
import woolpack.text.FormatFactory;
import woolpack.text.LimitedValueFormat;
import woolpack.text.RegExpFormat;
import woolpack.text.ToCharacterFormat;
import woolpack.text.ToStringFormat;
import woolpack.utils.MapBuilder;
import woolpack.utils.Switchable;
import woolpack.validator.CountValidator;
import woolpack.validator.DelegationValidator;
import woolpack.validator.DumpValidator;
import woolpack.validator.IfNotValidator;
import woolpack.validator.IfValidator;
import woolpack.validator.ValidatorConstants;
import woolpack.validator.ValidatorExpression;
import woolpack.visitor.Acceptable;
import woolpack.visitor.JsVisitorConstants;
import woolpack.visitor.Visitor;

/**
 * コンストラクタツリーを JS コンストラクタツリーに変換するための
 * 定数の集まり。
 * @author nakamura
 *
 */
public class JsConstants {
	
	/**
	 * {@link BranchByLocaleValidator}を JS コンストラクタ宣言に変換する{@link Acceptable}。
	 */
	public static final Acceptable<BranchByLocaleValidator> ACCEPT_BranchByLocaleValidator = JsVisitorConstants.classNameAcceptable(new Acceptable<BranchByLocaleValidator>(){
		public void accept(final Visitor visitor, final BranchByLocaleValidator v) {
			visitor.visit(v.getSwitchable());
		}
	});
	
	/**
	 * {@link IfNotValidator}を JS コンストラクタ宣言に変換する{@link Acceptable}。
	 */
	public static final Acceptable<IfNotValidator> ACCEPT_IfNotValidator = new Acceptable<IfNotValidator>(){
		public void accept(final Visitor visitor, final IfNotValidator v) {
			final StringBuilder sb = (StringBuilder)visitor.getContext();
			sb.append("new IfNotValidator(");
			visitor.visit(v.getIfExpression());
			sb.append(',');
			visitor.visit(v.getFalseExpression());
			sb.append(')');
		}
	};
	
	/**
	 * {@link IfValidator}を JS コンストラクタ宣言に変換する{@link Acceptable}。
	 */
	public static final Acceptable<IfValidator> ACCEPT_IfValidator = new Acceptable<IfValidator>(){
		public void accept(final Visitor visitor, final IfValidator v) {
			final StringBuilder sb = (StringBuilder)visitor.getContext();
			sb.append("new IfValidator(");
			visitor.visit(v.getIfExpression());
			sb.append(',');
			visitor.visit(v.getTrueExpression());
			sb.append(',');
			visitor.visit(v.getFalseExpression());
			sb.append(')');
		}
	};
	
	/**
	 * {@link SimpleDateFormat}を JS コンストラクタ宣言に変換する{@link Acceptable}。
	 */
	public static final Acceptable<SimpleDateFormat> ACCEPT_SimpleDateFormat = new Acceptable<SimpleDateFormat>(){
		public void accept(final Visitor visitor, final SimpleDateFormat v) {
			final StringBuilder sb = (StringBuilder)visitor.getContext();
			sb.append("new SimpleDateFormat(");
			visitor.visit(v.toPattern());
			sb.append(')');
		}
	};
	
	/**
	 * {@link wookpack.validator}パッケージで定義されているクラスに関する
	 * コンストラクタツリーを JS コンストラクタツリーに変換するためのに使用する{@link Map}。
	 * {@link Switchable#getDefault()}を無視する。
	 */
	public static final Map<Object,Acceptable> BASE = Collections.unmodifiableMap(MapBuilder.get(new LinkedHashMap<Object,Acceptable>())
			.put(ValidatorConstants.TRUE, JsVisitorConstants.objectAcceptable("new TrueValidator()"))
			.put(ValidatorConstants.FALSE, JsVisitorConstants.objectAcceptable("new FalseValidator()"))
			.put(ValidatorConstants.REQUIRED, JsVisitorConstants.objectAcceptable("new RequiredValidator()"))
			.put(ValidatorConstants.OR, JsVisitorConstants.objectAcceptable("new OrValidatorIterable()"))
			.put(ValidatorConstants.OROR, JsVisitorConstants.objectAcceptable("new OrOrValidatorIterable()"))
			.put(ValidatorConstants.AND, JsVisitorConstants.objectAcceptable("new AndValidatorIterable()"))
			.put(ValidatorConstants.ANDAND, JsVisitorConstants.objectAcceptable("new AndAndValidatorIterable()"))
			.put(ValidatorConstants.EQ, JsVisitorConstants.objectAcceptable("new EqValidatorIterable()"))
			.put(ValidatorConstants.EQEQ, JsVisitorConstants.objectAcceptable("new EqEqValidatorIterable()"))
			.put(CountValidator.class, IgnoreValidatorConstants.IGNORE_CountValidator)
			.put(DumpValidator.class, IgnoreValidatorConstants.IGNORE_DumpValidator)
			.put(BranchByLocaleValidator.class, ACCEPT_BranchByLocaleValidator)
			.put(IfNotValidator.class, ACCEPT_IfNotValidator)
			.put(IfValidator.class, ACCEPT_IfValidator)
			.put(ValidatorExpression.class, JsVisitorConstants.classNameAcceptable(JsVisitorConstants.PARAMS))
			.get());
	
	/**
	 * 値検証/値変換に関する
	 * コンストラクタツリーを JS コンストラクタツリーに変換するためのに使用する{@link Map}。
	 * @see #BASE
	 */
	public static final Map<Object,Acceptable> MAP = Collections.unmodifiableMap(MapBuilder.get(new LinkedHashMap<Object,Acceptable>())
			.putAll(BASE)
			.put(DelegationValidator.class, IgnoreValidatorConstants.IGNORE_DelegationValidator)
			
			.put(Iterable.class, JsVisitorConstants.ITERABLE)
			.put(Switchable.class, JsVisitorConstants.switchableAcceptable(null))
			.put(Map.class, JsVisitorConstants.MAP)
			.put(FormatFactory.class, IgnoreTextConstants.IGNORE_FormatFactory)
			
			.put(LimitedValueFormat.class, JsVisitorConstants.classNameAcceptable(JsVisitorConstants.PARAMS))
			.put(RegExpFormat.class, JsVisitorConstants.classNameAcceptable(JsVisitorConstants.PARAMS))
			.put(ToCharacterFormat.class, JsVisitorConstants.objectAcceptable("new ToCharacterFormat()"))
			.put(ToStringFormat.class, JsVisitorConstants.objectAcceptable("new ToStringFormat()"))
			
			.put(DelegateNumberFormat.class, IgnoreTextConstants.IGNORE_DelegateNumberFormat)
			.put(DecimalFormat.class, JsVisitorConstants.objectAcceptable("new DecimalFormat()"))
			
			.put(DelegateDateFormat.class, IgnoreTextConstants.IGNORE_DelegateDateFormat)
			.put(SimpleDateFormat.class, ACCEPT_SimpleDateFormat)
			.put(DateFormat.class, JsVisitorConstants.objectAcceptable("new SimpleDateFormat(\"yyyyMMdd\")"))
			
			.put(String.class, JsVisitorConstants.escapeStringAcceptable(JsVisitorConstants.OBJECT))
			.put(Locale.class)
			.put(Pattern.class)
			.put(Object.class, JsVisitorConstants.OBJECT)
			.get());
	
	private JsConstants(){}// カバレージがここを通過してはいけない
}
