
package de.ivu.elect.jee.faces.messagehelper;

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.faces.context.FacesContext;

public abstract class AbstractResourceBundle extends ResourceBundle {

  private final ResourceBundleMessageSource messageSource;

  protected AbstractResourceBundle() {
    this(new ResourceBundleMessageSource());
  }

  protected AbstractResourceBundle(ResourceBundleMessageSource messageSource) {
    super();

    this.messageSource = messageSource;
    this.messageSource.setBasenames(getBaseNames());
    this.messageSource.setUseCodeAsDefaultMessage(true);
  }

  public String[] getBaseNames() {
    List<String> result = new ArrayList<>(getBaseNamesOrderedBySpecialization());

    return result.toArray(new String[result.size()]);
  }

  public List<ResourceBundle> getBaseResourceBundles() {
    return stream(getBaseNames()).map(this::getResourceBundle).collect(toList());
  }

  /**
   * NOTE: Wird in einer anwendungsspezifischen Resource A der Key einer anderen anwendungsspezifischen Resource B überschrieben, MUSS die Resource A in der zurückgegebenen Liste vor der Resource B
   * stehen! Sprich: Das speziellste ResourceBundle muss zuerst zurueckgegeben werden.
   *
   * @return Gibt eine geordnete Liste aller anwendungsspezifischen (Messages-) Resources zurück.
   */
  protected abstract List<String> getBaseNamesOrderedBySpecialization();

  @Override
  protected Object handleGetObject(String key) {
    return messageSource.getMessage(key, null, getLocale());
  }

  @Override
  public Enumeration<String> getKeys() {
    return Collections.emptyEnumeration();
  }

  @Override
  public boolean containsKey(String key) {
    return super.containsKey(key) || isKeyInBundles(key);
  }

  protected boolean isKeyInBundles(String key) {
    for (String baseName : getBaseNames()) {
      if (getResourceBundle(baseName).containsKey(key)) {
        return true;
      }
    }

    return false;
  }

  private ResourceBundle getResourceBundle(String baseName) {
    ResourceBundle resourceBundle = messageSource.getResourceBundle(baseName, getLocale());

    if (resourceBundle == null) {
      throw new IllegalStateException("Kein Bundle für Namen gefunden: '" + baseName + "'");
    }

    return resourceBundle;
  }

  protected Locale getUserPreferredLocale() {
    // ELECT-3395, ACHTUNG: Potentielle Fehlerquelle!!! Ein Null-Check ist u.U. NICHT ausreichend.
    FacesContext facesContext = FacesContext.getCurrentInstance();

    if (facesContext == null || facesContext.getViewRoot() == null) {
      return null;
    }

    return facesContext.getViewRoot().getLocale();
  }

  @Override
  public Locale getLocale() {
    // ELECT-3395, Per Default die Browsereinstellungen benutzen.
    Locale locale = getUserPreferredLocale();

    if (locale == null) {
      return Locale.getDefault();
    }

    return locale;
  }
}
