/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dashbuilder.navigation.impl;
import java.util.ArrayList;
import java.util.List;
import org.dashbuilder.navigation.NavDivider;
import org.dashbuilder.navigation.NavFactory;
import org.dashbuilder.navigation.NavGroup;
import org.dashbuilder.navigation.NavItem;
import org.dashbuilder.navigation.NavItemContext;
import org.dashbuilder.navigation.NavTree;
import org.dashbuilder.navigation.NavItemVisitor;
import org.jboss.errai.common.client.api.annotations.Portable;
@Portable
public class NavTreeImpl implements NavTree {
private NavGroup root;
public NavTreeImpl() {
root = NavFactory.get().createNavGroup();
}
public NavTreeImpl(NavGroup root) {
this.root = root;
}
public List<NavItem> getRootItems() {
return root.getChildren();
}
@Override
public NavItem getItemById(String id) {
return getItemById(id, root.getChildren());
}
private NavItem getItemById(String id, List<NavItem> navItemList) {
if (id == null) {
return null;
}
for (NavItem navItem : navItemList) {
if (navItem.getId() != null && navItem.getId().equals(id)) {
return navItem;
}
if (navItem instanceof NavGroup) {
NavItem child = getItemById(id, ((NavGroup) navItem).getChildren());
if (child != null) {
return child;
}
}
}
return null;
}
@Override
public NavTree getItemAsTree(String id) {
NavItem item = getItemById(id);
return id != null ? NavFactory.get().createNavTree(item) : null;
}
@Override
public List<NavItem> searchItems(NavItemContext ctx) {
return searchItems(ctx, getRootItems());
}
public List<NavItem> searchItems(NavItemContext ctx, List<NavItem> navItemList) {
List<NavItem> result = new ArrayList<>();
if (ctx == null) {
return result;
}
NavItemContext niCtx = NavItemContext.create();
for (NavItem navItem : navItemList) {
niCtx.init(navItem.getContext());
if (niCtx.includesPropertiesOf(ctx)) {
result.add(navItem);
}
if (navItem instanceof NavGroup) {
List<NavItem> children = searchItems(ctx, ((NavGroup) navItem).getChildren());
result.addAll(children);
}
}
return result;
}
@Override
public NavGroup addGroup(String id, String name, String description, String parentId, boolean modifiable) {
NavGroup newNavItem = NavFactory.get().createNavGroup();
newNavItem.setId(id);
newNavItem.setName(name);
newNavItem.setDescription(description);
newNavItem.setModifiable(modifiable);
addItem(newNavItem, parentId);
return newNavItem;
}
@Override
public NavItem addItem(String id, String name, String description, String parentId, boolean modifiable, String context) {
NavItem newNavItem = NavFactory.get().createNavItem();
newNavItem.setId(id);
newNavItem.setName(name);
newNavItem.setDescription(description);
newNavItem.setModifiable(modifiable);
newNavItem.setContext(context);
addItem(newNavItem, parentId);
return newNavItem;
}
@Override
public NavDivider addDivider(String parentId, boolean modifiable) {
NavDivider newNavItem = NavFactory.get().createDivider();
newNavItem.setId(Integer.toString(newNavItem.hashCode()));
newNavItem.setModifiable(modifiable);
addItem(newNavItem, parentId);
return newNavItem;
}
private void addItem(NavItem item, String parentId) {
// Ensure the parent exists (if defined)
NavItem parent = getItemById(parentId);
if (parentId != null && parent == null) {
throw new RuntimeException("Parent '" + parentId + "' not found");
}
// Ensure the parent is a group
if (parent != null && !(parent instanceof NavGroup)) {
throw new RuntimeException("Parent '" + parentId + "' is not a group");
}
// Register the item
if (parent == null) {
item.setParent(null);
root.getChildren().add(item);
} else {
((NavGroup) parent).getChildren().add(item);
item.setParent((NavGroup) parent);
}
}
@Override
public NavItem deleteItem(String id) {
NavItem navItem = getItemById(id);
if (navItem != null) {
if (navItem.getParent() == null) {
root.getChildren().remove(navItem);
} else {
navItem.getParent().getChildren().remove(navItem);
navItem.setParent(null);
}
}
return navItem;
}
@Override
public NavItem setItemName(String id, String name) {
NavItem navItem = getItemById(id);
if (navItem == null) {
throw new RuntimeException("Item not found: " + id);
}
navItem.setName(name);
return navItem;
}
@Override
public NavItem setItemDescription(String id, String description) {
NavItem navItem = getItemById(id);
if (navItem == null) {
throw new RuntimeException("Item not found: " + id);
}
navItem.setDescription(description);
return navItem;
}
@Override
public NavItem setItemModifiable(String id, boolean modifiable) {
NavItem navItem = getItemById(id);
if (navItem == null) {
throw new RuntimeException("Item not found: " + id);
}
navItem.setModifiable(modifiable);
return navItem;
}
@Override
public NavItem setItemContext(String id, String context) {
NavItem navItem = getItemById(id);
if (navItem == null) {
throw new RuntimeException("Item not found: " + id);
}
navItem.setContext(context);
return navItem;
}
@Override
public NavItem moveItem(String id, String newParentId) {
NavItem navItem = getItemById(id);
if (navItem == null) {
throw new RuntimeException("Item not found: " + id);
}
// Ensure the new target parent exists
NavItem newParent = getItemById(newParentId);
if (newParent == null && newParentId != null) {
throw new RuntimeException("Parent not found: " + newParentId);
}
// Ensure the parent is a group
if (newParent != null && !(newParent instanceof NavGroup)) {
throw new RuntimeException("Parent '" + newParentId + "' is not a group");
}
// Avoid loops
if (newParentId != null && newParentId.equals(id)) {
throw new RuntimeException("The parent can't be the item itself: " + newParentId);
}
// Do not move if nothing changes
String parentId = navItem.getParent() != null ? navItem.getParent().getId(): null;
if ((parentId == null && newParentId == null) ||
(parentId != null && newParentId != null && parentId.equals(newParentId))) {
return navItem;
}
// Do move
if (navItem.getParent() != null) {
navItem.getParent().getChildren().remove(navItem);
}
navItem.setParent(null);
if (newParent != null) {
((NavGroup) newParent).getChildren().add(navItem);
navItem.setParent((NavGroup) newParent);
}
return navItem;
}
@Override
public void moveItemFirst(String id) {
changePosition(id, true, null);
}
@Override
public void moveItemLast(String id) {
changePosition(id, false, null);
}
@Override
public void moveItemUp(String id) {
changePosition(id, true, 1);
}
@Override
public void moveItemDown(String id) {
changePosition(id, false, 1);
}
public void changePosition(String id, boolean up, Integer npositions) {
NavItem navItem = getItemById(id);
if (navItem == null) {
throw new RuntimeException("Item not found: " + id);
}
NavGroup parent = navItem.getParent();
List<NavItem> itemList = parent != null ? parent.getChildren() : getRootItems();
int idx = itemList.indexOf(navItem);
int newPos = npositions == null ? (up ? 0 : itemList.size()-1) : (up ? idx-npositions: idx+npositions);
if ((up && newPos < 0) || (!up && newPos > itemList.size()-1)) {
throw new RuntimeException("Item '" + id + "' position out of range (old=" + idx + ", new=" + newPos + ")");
}
itemList.remove(idx);
itemList.add(newPos, navItem);
}
@Override
public void accept(NavItemVisitor visitor) {
for (NavItem item : root.getChildren()) {
item.accept(visitor);
}
}
@Override
public NavTree cloneTree() {
NavGroup rootClone = (NavGroup) this.root.cloneItem();
rootClone.getChildren().forEach(e -> e.setParent(null));
return new NavTreeImpl(rootClone);
}
}