/*******************************************************************************
* Copyright (c) 2012 OpenLegacy Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* OpenLegacy Inc. - initial API and implementation
*******************************************************************************/
package org.openlegacy.terminal.modules.menu;
import org.apache.commons.lang.StringUtils;
import org.openlegacy.modules.menu.Menu.MenuEntity;
import org.openlegacy.modules.menu.MenuBuilder;
import org.openlegacy.modules.menu.MenuItem;
import org.openlegacy.modules.support.menu.SimpleMenuItem;
import org.openlegacy.terminal.definitions.FieldAssignDefinition;
import org.openlegacy.terminal.definitions.NavigationDefinition;
import org.openlegacy.terminal.definitions.ScreenEntityDefinition;
import org.openlegacy.terminal.services.ScreenEntitiesRegistry;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
public class DefaultMenuBuilder implements MenuBuilder, Serializable {
private static final long serialVersionUID = 1L;
@Inject
private ScreenEntitiesRegistry screenEntitiesRegistry;
private Map<Class<?>, List<Class<?>>> allMenusOptions = null;
private MenuItemsComparator menuItemsComparator;
public MenuItem getMenuTree(Class<?> menuEntityClass) {
sortToMenus();
return buildMenu(menuEntityClass);
}
public MenuItem getMenuTree() {
sortToMenus();
Class<?> rootClass = findRoot();
return buildMenu(rootClass);
}
private void sortToMenus() {
if (allMenusOptions != null) {
return;
}
allMenusOptions = new HashMap<Class<?>, List<Class<?>>>();
Collection<ScreenEntityDefinition> entitiesDefinitions = screenEntitiesRegistry.getEntitiesDefinitions();
for (ScreenEntityDefinition entityDefinition : entitiesDefinitions) {
NavigationDefinition navigationDefintion = entityDefinition.getNavigationDefinition();
if (navigationDefintion == null) {
continue;
}
Class<?> accessedFrom = navigationDefintion.getAccessedFrom();
Assert.notNull(accessedFrom);
ScreenEntityDefinition accessedFromDefinition = screenEntitiesRegistry.get(accessedFrom);
if (accessedFromDefinition.getType() == MenuEntity.class) {
addMenuOption(accessedFrom, entityDefinition.getEntityClass());
}
}
}
private void addMenuOption(Class<?> accessedFrom, Class<?> screenEntityClass) {
List<Class<?>> menuOptions = allMenusOptions.get(accessedFrom);
if (menuOptions == null) {
menuOptions = new ArrayList<Class<?>>();
allMenusOptions.put(accessedFrom, menuOptions);
}
menuOptions.add(screenEntityClass);
}
private Class<?> findRoot() {
Set<Class<?>> menuEntityClasses = allMenusOptions.keySet();
Class<?> rootMenuClass = null;
for (Class<?> menuEntityClass : menuEntityClasses) {
ScreenEntityDefinition menuDefintion = screenEntitiesRegistry.get(menuEntityClass);
if (menuDefintion.getNavigationDefinition() == null) {
Assert.isNull(rootMenuClass,
MessageFormat.format("Found more then one root menu entries:{0}, {1}", rootMenuClass, menuEntityClass));
rootMenuClass = menuEntityClass;
}
}
return rootMenuClass;
}
private MenuItem buildMenu(Class<?> rootClass) {
if (rootClass == null) {
return null;
}
ScreenEntityDefinition screenEntityDefinition = screenEntitiesRegistry.get(rootClass);
NavigationDefinition navigationDefinition = screenEntityDefinition.getNavigationDefinition();
// don't include in the menu screens which needs parameters to access them
if (navigationDefinition != null && navigationDefinition.isRequiresParameters()) {
return null;
}
String displayName = screenEntityDefinition.getDisplayName();
MenuItem menuItem = new SimpleMenuItem(rootClass, displayName);
if (!allMenusOptions.containsKey(rootClass)) {
return menuItem;
}
List<Class<?>> menuOptions = allMenusOptions.get(rootClass);
Collections.sort(menuOptions, getMenuItemsComparator());
for (Class<?> menuOption : menuOptions) {
MenuItem childMenuItem = buildMenu(menuOption);
menuItem.getMenuItems().add(childMenuItem);
}
return menuItem;
}
private Comparator<Class<?>> getMenuItemsComparator() {
if (menuItemsComparator == null) {
menuItemsComparator = new MenuItemsComparator(screenEntitiesRegistry);
}
return menuItemsComparator;
}
/**
* Compare menu items by comparing the assigned fields value of the navigation definition. For example: <br/>
* Screen A: @ScreenNavigation(... assignedFields = { @AssignedField(field = "selection", value = "1") } ...) <br/>
* Screen B: @ScreenNavigation(... assignedFields = { @AssignedField(field = "selection", value = "2") } ...)
*
* @author RoiM
*
*/
private static class MenuItemsComparator implements Comparator<Class<?>> {
private ScreenEntitiesRegistry screenEntitiesRegistry;
public MenuItemsComparator(ScreenEntitiesRegistry screenEntitiesRegistry) {
this.screenEntitiesRegistry = screenEntitiesRegistry;
}
public int compare(Class<?> o1, Class<?> o2) {
NavigationDefinition menuItem1NavigationDefinition = screenEntitiesRegistry.get(o1).getNavigationDefinition();
NavigationDefinition menuItem2NavigationDefinition = screenEntitiesRegistry.get(o2).getNavigationDefinition();
List<FieldAssignDefinition> assignedFields1 = menuItem1NavigationDefinition.getAssignedFields();
List<FieldAssignDefinition> assignedFields2 = menuItem2NavigationDefinition.getAssignedFields();
if (assignedFields1.size() != 1 || assignedFields2.size() != 1) {
return 0;
}
String assignedField1Value = assignedFields1.get(0).getValue();
String assignedField2Value = assignedFields2.get(0).getValue();
if (StringUtils.isNumeric(assignedField1Value) && StringUtils.isNumeric(assignedField1Value)) {
return Integer.valueOf(assignedField1Value) - Integer.valueOf(assignedField2Value);
}
return assignedField1Value.compareTo(assignedField2Value);
}
}
}