/*******************************************************************************
* Copyright (c) 2015 Pivotal, 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.properties.editor.yaml.reconcile;
import static org.springframework.ide.eclipse.editor.support.util.StringUtil.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.ide.eclipse.boot.properties.editor.FuzzyMap;
import org.springframework.ide.eclipse.boot.properties.editor.FuzzyMap.Match;
import org.springframework.ide.eclipse.boot.properties.editor.metadata.PropertyInfo;
import org.springframework.ide.eclipse.editor.support.util.StringUtil;
/**
* An index navigator allows selecting subset of a property index as if
* navigating the index by selecting on a property
*
* @author Kris De Volder
*/
public class IndexNavigator {
//Possible opitmization: we could cache prefix match candidate and extended match candidate
// since it is assumed that the index is immutable for the lifetime of
// the index navigator.
private static final char NAV_CHAR = '.';
/**
* Property access in this navigator are interpreted relative
* to this prefix
*/
private String prefix = null;
private FuzzyMap<PropertyInfo> index;
private IndexNavigator(FuzzyMap<PropertyInfo> index) {
this.index = index;
}
private IndexNavigator(FuzzyMap<PropertyInfo> index, String prefix) {
this.index = index;
this.prefix = prefix;
}
public static IndexNavigator with(FuzzyMap<PropertyInfo> index) {
return new IndexNavigator(index);
}
public IndexNavigator selectSubProperty(String name) {
return new IndexNavigator(index, join(prefix, name));
}
protected String join(String prefix, String postfix) {
if (!hasText(prefix)) {
return postfix;
} else {
return prefix + NAV_CHAR + postfix;
}
}
/**
* @return property info that is an exact match with the current prefix or
* null if there's no exact match
*/
public PropertyInfo getExactMatch() {
if (prefix!=null) {
PropertyInfo candidate = index.findLongestCommonPrefixEntry(prefix);
if (candidate.getId().equals(prefix)) {
return candidate;
}
}
return null;
}
/**
* Get a property that has the current prefix as a 'true' prefix. A true prefix
* is a String that has the current prefix as a prefix and continues onward with
* a navigation operation.
*/
public PropertyInfo getExtensionCandidate() {
//If current prefix is null then all entries in the index are candidates since
// the index is at the 'root' of the tree and we don't need a '.' to navigate
String extendedPrefix = prefix==null?"":prefix + NAV_CHAR;
PropertyInfo candidate = index.findLongestCommonPrefixEntry(extendedPrefix);
if (candidate.getId().startsWith(extendedPrefix)) {
return candidate;
}
return null;
}
public String getPrefix() {
return prefix;
}
public List<Match<PropertyInfo>> findMatching(String query) {
if (!StringUtil.hasText(prefix)) {
return index.find(query);
} else {
String dottedPrefix = prefix +".";
List<Match<PropertyInfo>> candidates = index.find(dottedPrefix + query);
if (!candidates.isEmpty()) {
//TODO: we can do better than this using treemap to narrow based on
// prefix
List<Match<PropertyInfo>> matches = new ArrayList<Match<PropertyInfo>>(candidates.size());
for (Match<PropertyInfo> match : candidates) {
if (match.data.getId().startsWith(dottedPrefix)){
matches.add(match);
}
}
return matches;
}
}
return Collections.emptyList();
}
@Override
public String toString() {
return "IndexNavigator("+prefix+")";
}
public boolean isEmpty() {
return getExactMatch()==null && getExtensionCandidate()==null;
}
}