package de.siphalor.was.content.lang;

import de.siphalor.was.content.ContentManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

/**
 * A singleton class handling all of the translation actions and the currently active language with a fallback language
 */
public class I18n extends ResourceBundle {
	/**
	 * The language code of the fallback language
	 */
	public static final String DEFAULT = "en_us";

	/**
	 * The fallback language
	 */
	private final Lang DEFAULT_LANG = new Lang(DEFAULT);

	/**
	 * The class' instance
	 */
	private static final I18n INSTANCE = new I18n();

	/**
	 * Gets the singleton instance
	 * @return the singleton instance
	 */
	public static I18n getInstance() {
		return INSTANCE;
	}

	/**
	 * the current language
	 */
	@Nullable
	private Lang lang;

	/**
	 * Returns the current language
	 * @return the currently selected language or the fallback
	 */
	public Lang getLang() {
		if (lang != null)
			return lang;
		return DEFAULT_LANG;
	}

	/**
	 * Sets the current language to the language identified by <code>code</code>. It loads the language using the given {@link ContentManager}
	 * @param code The language's identification code
	 * @param contentManager The content manager to use
	 * @return Returns whether the language was updated
	 */
	public boolean setLang(@NotNull String code, @NotNull ContentManager contentManager) {
		if (lang == null || !lang.getCode().equals(code)) {
			Lang l = new Lang(code);
			if (l.load(contentManager)) {
				lang = l;
				return true;
			}
		}
		return false;
	}

	/**
	 * Reloads the current and the fallback language language using the given content manager.
	 * @param contentManager The content manager to use
	 */
	public void reload(@NotNull ContentManager contentManager) {
		DEFAULT_LANG.load(contentManager);
		if (lang != null) {
			lang.load(contentManager);
		}
	}

	/**
	 * Translates and formats with the translation string.
	 * @param key The translation key
	 * @param args The arguments to use for formatting
	 * @return The formatted string
	 */
	@NotNull
	public String format(@NotNull String key, @Nullable Object... args) {
		return String.format(getString(key), args);
	}

	/**
	 * Loads the given data by the translation key.
	 * @param key The translation key
	 * @return The associated data or <code>null</code> if none
	 */
	@Override
	@NotNull
	protected Object handleGetObject(@NotNull String key) {
		String val;
		if (lang != null) {
			val = lang.get(key);
			if (val == null) {
				val = DEFAULT_LANG.get(key);
			}
		} else {
			val = DEFAULT_LANG.get(key);
		}

		if (val == null) {
			return key;
		}
		return val;
	}

	/**
	 * Returns all valid keys existing in the current language or the fallback language.
	 * @return An enumeration of all of these keys
	 */
	@NotNull
	@Override
	public Enumeration<String> getKeys() {
		if (lang == null)
			return DEFAULT_LANG.getKeys();
		Set<String> keys = new HashSet<>(Collections.list(lang.getKeys()));
		keys.addAll(Collections.list(DEFAULT_LANG.getKeys()));
		return Collections.enumeration(keys);
	}
}
