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

import java.io.Serializable;
import java.util.EmptyStackException;
import java.util.List;
import java.util.Stack;

import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.deltaspike.core.api.scope.ConversationGroup;
import org.apache.deltaspike.core.api.scope.GroupedConversationScoped;

import de.ivu.elect.jee.faces.FacesContextUtil;


import static java.util.Collections.unmodifiableList;

@Named
@GroupedConversationScoped
@ConversationGroup(ViewStack.class)
public class ViewStack implements Serializable {

  private static final long serialVersionUID = 1L;

  Stack<String> viewIds;

  @Inject
  private transient Event<ViewStackResetEvent> viewStackResetEvent;

  @PostConstruct
  public void init() {
    viewIds = new Stack<>();
  }

  /**
   * Fügt die aktuelle View zum View-Stack hinzu, falls sie noch nicht auf dem Stack liegt; andernfalls werden die
   * Views, die nach der aktuellen View hinzugefügt wurden, entfernt.
   */
  public void enter() {
    leave();
    viewIds.push(getCurrentViewId());
  }

  /**
   * Entfernt die aktuelle View und alle Views, die nach ihr kamen, vom View-Stack.
   */
  public void leave() {
    String currentViewId = getCurrentViewId();

    try {
      while (contains(currentViewId) && !viewIds.isEmpty() && !currentViewId.equals(viewIds.pop())) {
        // Iteriere, bis die aktuelle View vom Stack entfernt wird.
        //
      }
    } catch (EmptyStackException e){
      // ignorieren...cannot happen...
    }
  }

  /**
   * Finde die Stelle des aktuellen View im Stack und liefere den Eintrag davor zurück (oder null, falls leer)
   * 
   * @return Eintrag vor dem aktuellen View oder null
   */
  @Nullable
  public String back() {
    String currentViewId = getCurrentViewId();

    if (contains(currentViewId)) {
      while (!isEmpty()) {
        if (currentViewId.equals(viewIds.pop())) {
          return popOrNull();
        }
      }
    }
    return popOrNull();
  }

  @Nullable
  private String popOrNull() {
    if (viewIds.isEmpty()) {
      return null;
    }
    return viewIds.pop();
  }

  String getCurrentViewId() {
    return FacesContextUtil.getCurrentViewId();
  }

  public boolean contains(String currentViewId) {
    return viewIds.contains(currentViewId);
  }

  public void reset() {
    viewIds.clear();
    viewStackResetEvent.fire(new ViewStackResetEvent());
  }

  public boolean isEmpty() {
    return viewIds.isEmpty();
  }

  public boolean containsOnly(String viewId) {
    return viewIds.size() == 1 && viewIds.contains(viewId);
  }

  public List<String> getViewIdsBottomToTop() {
    return unmodifiableList(viewIds);
  }
}
