/*
 * 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.config;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import woolpack.utils.CheckUtils;

/**
 * 値一覧とラベル一覧をマージして、値とラベルの{@link LinkedHashMap}を生成する{@link ConfigExpression}。
 * 静的な選択肢(ラジオボタン・チェックボックス・セレクト)を生成するために使用する。
 * 静的な選択肢は冗長性があっても静的であるほうが見える化が維持されるため、 入力値を確認する画面を生成するのでなければ
 * 静的な選択肢を生成する目的では本機能を使用しないことを推奨する。
 * 
 * @author nakamura
 * 
 */
public class ToLinkedHashMap implements ConfigExpression {
	private final String newMapListPosition;

	private final String valueSourcePosition;

	private final String labelSourcePosition;

	private final String separator;

	/**
	 * コンストラクタ。
	 * 
	 * @param newMapListPosition
	 *            変換後の{@link LinkedHashMap}を格納する
	 *            {@link ConfigContext#getMap()}上の位置。
	 * @param valueSourcePosition
	 *            値一覧を取得する{@link ConfigContext#getMap()}上の位置。
	 * @param labelSourcePosition
	 *            ラベル一覧を取得する{@link ConfigContext#getMap()}上の位置。
	 * @param separator
	 *            一覧(値・ラベル)それぞれ値・ラベルに分解するためのセパレータ。
	 * @throws NullPointerException
	 *             引数のいずれかが null の場合。
	 * @throws StringIndexOutOfBoundsException
	 *             引数のいずれかが空の場合。
	 */
	public ToLinkedHashMap(final String newMapListPosition,
			final String valueSourcePosition, final String labelSourcePosition,
			final String separator) {
		CheckUtils.checkNotEmpty(newMapListPosition);
		CheckUtils.checkNotEmpty(valueSourcePosition);
		CheckUtils.checkNotEmpty(labelSourcePosition);
		CheckUtils.checkNotEmpty(separator);

		this.newMapListPosition = newMapListPosition;
		this.valueSourcePosition = valueSourcePosition;
		this.labelSourcePosition = labelSourcePosition;
		this.separator = separator;
	}

	/**
	 * @throws NullPointerExcpeption
	 *             引数または{@link ConfigContext#getMap()}が null
	 *             であるか一覧(値・ラベル)のいずれかが存在しない場合。
	 * @throws ClassCastExcpeption
	 *             一覧(値・ラベル)のいずれかが文字列でない場合。
	 * @throws ArrayIndexOutOfBoundsException
	 *             一覧(値・ラベル)の分割後の要素数が一致しない場合。
	 * @throws UnsupportedOperationException
	 *             生成した値とラベルの{@link LinkedHashMap}の設定に失敗した場合。
	 */
	public void interpret(final ConfigContext context) {
		final String[] valueArray = ((String) context.getMap().get(
				valueSourcePosition)).split(separator);
		final String[] labelArray = ((String) context.getMap().get(
				labelSourcePosition)).split(separator);
		if (valueArray.length != labelArray.length) {
			throw new ArrayIndexOutOfBoundsException("length unmatch : "
					+ valueSourcePosition + " and " + labelSourcePosition);
		}
		final Map<String, String> map = new LinkedHashMap<String, String>();
		for (int i = 0; i < valueArray.length; i++) {
			map.put(valueArray[i], labelArray[i]);
		}
		context.getMap().put(newMapListPosition,
				Collections.unmodifiableMap(map));
	}
}
