
package de.ivu.elect.jee.presentation.menu;

import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.primefaces.model.menu.DefaultMenuItem;
import org.primefaces.model.menu.DefaultSeparator;
import org.primefaces.model.menu.DefaultSubMenu;
import org.primefaces.model.menu.MenuElement;
import org.primefaces.model.menu.MenuItem;

import de.ivu.elect.jee.faces.FacesContextUtil;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.Icons;

public abstract class AbstractSubMenuEntry implements MenuEntry {

  private static final long serialVersionUID = 1L;

  private static final String NO_ICON = null;

  @Inject
  protected transient Messages messages;

  @Inject
  protected transient Icons appIcons;

  @Inject
  protected transient SeparatorMenuEntry separator;

  public AbstractSubMenuEntry() {
    super();
  }

  @Override
  public boolean isRendered() {
    return isAtLeastOneSubMenuEntryRendered();
  }

  private boolean isAtLeastOneSubMenuEntryRendered() {
    return getSubMenuEntriesSorted().stream().anyMatch(MenuEntry::isRendered);
  }

  public List<MenuEntry> getSubMenuEntries() {
    return getSubMenuEntriesSorted();
  }

  protected abstract List<MenuEntry> getSubMenuEntriesSorted();

  @Override
  public MenuElement buildComponent() {
    DefaultSubMenu defaultSubMenu = new DefaultSubMenu();
    defaultSubMenu.setRendered(isRendered());

    if (!isRendered()) {
      return defaultSubMenu;
    }

    if (getIcon() != null) {
      defaultSubMenu.setIcon(getIcon());
    }

    defaultSubMenu.setLabel(getLabelFinal());

    List<MenuElement> children = defaultSubMenu.getElements();

    for (MenuEntry menuEntry : getSubMenuEntriesSorted()) {
      children.add(menuEntry.buildComponent());
    }

    if (isTopicActive() || isChildTopicActive(defaultSubMenu)) {
      defaultSubMenu.setStyleClass(trimToEmpty(defaultSubMenu.getStyleClass()) + " " + AbstractBaseMenuItemEntry.TOPIC_ACTIVE_STYLE);
    }

    // führende und schließende Separatoren löschen
    disableFirstSeparatorIfFirst(children);
    List<MenuElement> inverseChildren = new ArrayList<>(children);
    Collections.reverse(inverseChildren);
    disableFirstSeparatorIfFirst(inverseChildren);
    // aufeinanderfolgende Separatoren löschen
    disableMultileSeparators(children);

    // wenn alle Einträge deaktiviert => Menüpunkt selbst deaktivieren
    if (isAlleChildrenDisabled(defaultSubMenu)) {
      DefaultMenuItem defaultMenuItem = new DefaultMenuItem();
      defaultMenuItem.setValue(defaultSubMenu.getLabel());
      defaultMenuItem.setIcon(defaultSubMenu.getIcon());
      defaultMenuItem.setDisabled(true);

      return defaultMenuItem;
    }

    return defaultSubMenu;
  }

  private boolean isChildTopicActive(DefaultSubMenu submenu) {
    return submenu.getElements().stream().filter(uiComponent -> uiComponent instanceof MenuItem).map(uiComponent -> (MenuItem) uiComponent).map(MenuItem::getStyleClass).filter(Objects::nonNull)
        .anyMatch(sc -> sc.contains(AbstractBaseMenuItemEntry.TOPIC_ACTIVE_STYLE));
  }

  @Override
  public boolean isTopicActive() {
    String topic = FacesContextUtil.getCurrentTopic();

    if (StringUtils.isBlank(topic)) {
      return false;
    }

    return getTopics().contains(topic);
  }

  protected List<String> getTopics() {
    return Collections.emptyList();
  }

  private boolean isAlleChildrenDisabled(DefaultSubMenu submenu) {
    return !isOneChildEnabled(submenu);
  }

  private boolean isOneChildEnabled(DefaultSubMenu submenu) {
    return submenu.getElements().stream().filter(uiComponent -> uiComponent instanceof MenuItem).map(uiComponent -> (MenuItem) uiComponent)
        .anyMatch(menuItem -> menuItem.isRendered() && !menuItem.isDisabled());
  }

  private void disableMultileSeparators(List<MenuElement> children) {
    boolean lastWasEnabledSeparator = true;

    for (MenuElement menuElement : children) {
      if (menuElement instanceof DefaultSeparator) {
        DefaultSeparator defaultSeparator = (DefaultSeparator) menuElement;

        if (menuElement.isRendered()) {
          if (lastWasEnabledSeparator) {
            defaultSeparator.setRendered(false);
          }

          lastWasEnabledSeparator = true;
        }
      } else if (menuElement.isRendered()) {
        lastWasEnabledSeparator = false;
      }
    }
  }

  private void disableFirstSeparatorIfFirst(List<MenuElement> children) {
    boolean first = true;

    for (MenuElement menuElement : children) {
      if (menuElement instanceof DefaultSeparator) {
        DefaultSeparator defaultSeparator = (DefaultSeparator) menuElement;

        if (first) {
          defaultSeparator.setRendered(false);
        }
      } else {
        if (menuElement.isRendered()) {
          first = false;
        }
      }
    }
  }

  public String getLabelFinal() {
    return getLabel();
  }

  protected String getLabel() {
    return getMessage(getLabelKey());
  }

  public String getIcon() {
    return NO_ICON;
  }

  protected String getMessage(String key, Object... params) {
    return messages.getMessageForMessageKey(key, params);
  }
}
