//
// ERXNavigationState.java
// ERExtensions
//
// Created by Max Muller on Wed Oct 30 2002.
//
package er.extensions.appserver.navigation;
import java.io.Serializable;
import java.util.Enumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSKeyValueCodingAdditions;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSRange;
import er.extensions.foundation.ERXValueUtilities;
/** Please read "Documentation/Navigation.html" to fnd out how to use the navigation components.*/
public class ERXNavigationState implements Serializable {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ERXNavigationState.class);
protected NSArray _additionalState;
protected NSArray _state;
protected boolean isDisabled;
public ERXNavigationState() {
super();
}
public NSArray state() {
NSArray state = _state == null ? NSArray.EmptyArray : _state;
if (_additionalState != null) {
NSMutableArray combinedState = new NSMutableArray(state);
combinedState.addObjectsFromArray(_additionalState);
state = combinedState;
}
return state;
}
public void setAdditionalState(NSArray value) {
log.debug("Setting additional navigation state: {}", value);
_additionalState = value;
}
public NSArray navigationItemsToBeShownForLevel(int currentNavigationLevel) {
NSArray itmesToBeShown = null;
int navCount = state() != null ? state().count() : 0;
if (currentNavigationLevel == 0) {
itmesToBeShown = state();
} else if (navCount != 0 && navCount <= currentNavigationLevel) {
itmesToBeShown = new NSArray(state().lastObject());
} else if (navCount != 0 && currentNavigationLevel < navCount) {
int index = currentNavigationLevel - 1;
int length = navCount - currentNavigationLevel + 1;
NSRange range = new NSRange(index, length);
log.debug("Range: {} current: {} navCount: {}", range, currentNavigationLevel, navCount);
itmesToBeShown = state().subarrayWithRange(range);
}
log.debug("Nav state: {} current nav level: {} items: {}", state(), currentNavigationLevel, itmesToBeShown);
return itmesToBeShown != null ? itmesToBeShown : NSArray.EmptyArray;
}
// Anytime we are setting the absolute we reset the relative.
public void setState(NSArray navigationState) {
log.debug("Setting Navigation State: {}", navigationState);
_state = navigationState;
_additionalState = null;
}
public void setStateWithString(String navigationStateString) {
if (navigationStateString != null) {
setState(NSArray.componentsSeparatedByString(navigationStateString, "."));
}
}
public String stateAsString() {
if (state() != null) {
return state().componentsJoinedByString(".");
}
return null;
}
public boolean isDisabled() { return isDisabled; }
public void setIsDisabled(boolean newIsDisabled) { isDisabled = newIsDisabled; }
public void setStateForLevel(String state, int level) {
if (level > 0) {
NSMutableArray navState = new NSMutableArray(state());
if (navState.count() >= level)
navState.replaceObjectAtIndex(state, level - 1);
else
navState.addObject(state);
setState(navState);
} else {
log.error("Attempting to set the state: {} for a negative level: {}", state, level);
}
}
public String level(int i) {
return state() != null && i < state().count() ? (String)state().objectAtIndex(i) : "";
}
public NSArray navigationItemsForLevel(int level, NSKeyValueCodingAdditions context) {
ERXNavigationItem levelRoot = null;
if (level == 1) {
levelRoot = ERXNavigationManager.manager().rootNavigationItem();
} else if (state().count() > level - 2) {
levelRoot = ERXNavigationManager.manager().navigationItemForName(level(level - 2));
log.debug("Root name for level: {} state: {} root: {}", level - 2, state(),
(levelRoot != null ? levelRoot.name() : "<NULL>"));
}
NSArray children = null;
if (levelRoot != null) {
boolean hasChildrenConditions = levelRoot.childrenConditions().count() != 0;
boolean meetsChildrenConditions = true;
if (hasChildrenConditions) {
for (Enumeration e = levelRoot.childrenConditions().objectEnumerator(); e.hasMoreElements();) {
String aCondition = (String)e.nextElement();
meetsChildrenConditions = ERXValueUtilities.booleanValue(context.valueForKeyPath(aCondition));
if (!meetsChildrenConditions)
break;
}
}
if (meetsChildrenConditions) {// only want to do this if childrenConditions are met, or if there aren't any children conditions
if (levelRoot.children() != null)
children = levelRoot.children();
else if (levelRoot.childrenBinding() != null) {
Object o = context.valueForKeyPath(levelRoot.childrenBinding());
if (o != null && o instanceof NSArray)
children = (NSArray)o;
else if (o != null && o instanceof String) {
children = (NSArray)levelRoot.childrenChoices().objectForKey(o);
if (children == null)
log.warn("For nav core object: {} and child binding: {} couldn't find children for choice key: {}",
levelRoot, levelRoot.childrenBinding(), o);
} else if (o instanceof Boolean) {
String s = Boolean.toString((Boolean)o);
children = (NSArray)levelRoot.childrenChoices().objectForKey(s);
} else {
log.warn("For nav core object: {} and child binding: {} recieved binding object: {}",
levelRoot, levelRoot.childrenBinding(), o);
}
}
}
}
if (children == null)
children = NSArray.EmptyArray;
if (children.count() > 0) {
NSMutableArray childNavItems = new NSMutableArray();
for (Enumeration e = children.objectEnumerator(); e.hasMoreElements();) {
String childName = (String)e.nextElement();
ERXNavigationItem item = ERXNavigationManager.manager().navigationItemForName(childName);
if (item != null)
childNavItems.addObject(item);
else
log.warn("Unable to find navigation item for name: {}", childName);
}
children = childNavItems;
}
return children;
}
@Override
public String toString() {
return "\"" + stateAsString() + "\"";
}
}