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

import java.io.IOException;
import java.util.Locale;

import woolpack.fn.Fn;

/**
 * {@link Locale}を元に id に接尾辞を付加し、DOM ノードの生成を委譲する{@link Fn}です。
 * このクラスは LSP(The Liskov Substitution Principle) を満たしません。
 * 
 * @author nakamura
 * 
 * @param <R>
 */
public class TryLocales<R> implements Fn<String, R> {
	private Fn<? super String, ? extends R> fn;
	private ThreadLocal<Locale> threadLocal;

	/**
	 * @param fn DOM ノードを生成し加工する委譲先。
	 * @param threadLocal 現在のスレッドの{@link Locale}を保持する
	 */
	public TryLocales(
			final Fn<? super String, ? extends R> fn,
			final ThreadLocal<Locale> threadLocal) {
		this.fn = fn;
		this.threadLocal = threadLocal;
	}
	
	private static String removeRight(final String s, final int i) {
		return s.substring(0, s.length() - i);
	}

	public R exec(final String id) {
		final Locale l = threadLocal.get();
		final Locale d = Locale.getDefault();

		final String[] idArray;
		if (l == null) {
			idArray = new String[4];
			idArray[0] = id + '_' + d.getLanguage() + '_' + d.getCountry() + '_' + d.getVariant();
			idArray[1] = removeRight(idArray[0], d.getVariant().length() + 1);
			idArray[2] = removeRight(idArray[1], d.getCountry().length() + 1);
			idArray[3] = id;
		} else {
			idArray = new String[7];
			idArray[0] = id + '_' + l.getLanguage() + '_' + l.getCountry() + '_' + l.getVariant();
			idArray[1] = removeRight(idArray[0], l.getVariant().length() + 1);
			idArray[2] = removeRight(idArray[1], l.getCountry().length() + 1);
			idArray[3] = id + '_' + d.getLanguage() + '_' + d.getCountry() + '_' + d.getVariant();
			idArray[4] = removeRight(idArray[3], d.getVariant().length() + 1);
			idArray[5] = removeRight(idArray[4], d.getCountry().length() + 1);
			idArray[6] = id;
		}
		RuntimeException e0 = null;
		for (int i = 0; i < idArray.length; i++) {
			try {
				final R r = fn.exec(idArray[i]);
				if (r != null) {
					return r;
				}
			} catch (final RuntimeException e) {
				if (e.getCause() instanceof IOException) {
					e0 = e;
				} else {
					throw e;
				}
			}
		}
		if (e0 != null) {
			throw e0;
		} else {
			throw new IllegalStateException();
		}
	}

	public Fn<? super String, ? extends R> getFn() {
		return fn;
	}
	public void setFn(final Fn<? super String, ? extends R> fn) {
		this.fn = fn;
	}
	public ThreadLocal<Locale> getThreadLocal() {
		return threadLocal;
	}
	public void setThreadLocal(final ThreadLocal<Locale> threadLocal) {
		this.threadLocal = threadLocal;
	}
}
