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

import woolpack.fn.Fn;

public class TryLocales<R, E extends Exception> implements Fn<String, R, E> {
	private Fn<? super String, ? extends R, ? extends Exception> fn;
	private Fn<? super Exception, ?, ? extends E> errorFn;
	private Fn<? super Exception, ? extends R, ? extends E> finalFn;
	private ThreadLocal<Locale> threadLocal;

	public TryLocales(
			final Fn<? super String, ? extends R, ? extends Exception> fn,
			final ThreadLocal<Locale> threadLocal,
			final Fn<? super Exception, ?, ? extends E> errorFn,
			final Fn<? super Exception, ? extends R, ? extends E> finalFn) {
		this.fn = fn;
		this.threadLocal = threadLocal;
		this.errorFn = errorFn;
		this.finalFn = finalFn;
	}
	
	private static String removeRight(final String s, final int i) {
		return s.substring(0, s.length() - i);
	}

	public R exec(final String id) throws E {
		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;
		}
		Exception 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 Exception e) {
				e0 = e;
				errorFn.exec(e0);
			}
		}
		return finalFn.exec(e0);
	}

	public Fn<? super String, ? extends R, ? extends Exception> getFn() {
		return fn;
	}
	public void setFn(final Fn<? super String, ? extends R, ? extends Exception> fn) {
		this.fn = fn;
	}
	public ThreadLocal<Locale> getThreadLocal() {
		return threadLocal;
	}
	public void setThreadLocal(final ThreadLocal<Locale> threadLocal) {
		this.threadLocal = threadLocal;
	}
	public Fn<? super Exception, ?, ? extends E> getErrorFn() {
		return errorFn;
	}
	public void setErrorFn(final Fn<? super Exception, ?, ? extends E> errorFn) {
		this.errorFn = errorFn;
	}
	public Fn<? super Exception, ? extends R, ? extends E> getFinalFn() {
		return finalFn;
	}
	public void setFinalFn(final Fn<? super Exception, ? extends R, ? extends E> finalFn) {
		this.finalFn = finalFn;
	}
}
