// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.wiki;
import static fitnesse.wiki.WikiPagePath.Mode.ABSOLUTE;
import static fitnesse.wiki.WikiPagePath.Mode.BACKWARD_SEARCH;
import static fitnesse.wiki.WikiPagePath.Mode.RELATIVE;
import static fitnesse.wiki.WikiPagePath.Mode.SUB_PAGE;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class WikiPagePath implements Comparable<Object> {
public enum Mode {
ABSOLUTE, SUB_PAGE, BACKWARD_SEARCH, RELATIVE
}
private LinkedList<String> names = new LinkedList<>();
private Mode mode = RELATIVE;
public WikiPagePath() {
}
public WikiPagePath(String[] names) {
for (String name : names) {
addNameToEnd(name);
}
}
public WikiPagePath copy() {
WikiPagePath clone = new WikiPagePath();
clone.names = (LinkedList<String>) names.clone();
clone.mode = mode;
return clone;
}
public WikiPagePath(WikiPage page) {
while (!page.isRoot()) {
names.addFirst(page.getName());
page = page.getParent();
}
}
public WikiPagePath(WikiPagePath path) {
mode = path.mode;
for (WikiPagePath p = path; !p.isEmpty(); p = p.getRest())
addNameToEnd(p.getFirst());
}
private WikiPagePath(List<String> names) {
this.names = new LinkedList<>(names);
}
public String getFirst() {
return isEmpty() ? null : names.get(0);
}
public WikiPagePath addNameToEnd(String name) {
names.add(name);
return this;
}
public WikiPagePath addNameToFront(String name) {
names.addFirst(name);
return this;
}
public WikiPagePath getRest() {
int size = names.size();
return (size <= 1) ? new WikiPagePath() : new WikiPagePath(names.subList(1, size));
}
public boolean isEmpty() {
return names.isEmpty();
}
public String last() {
return (names.isEmpty() ? null : names.get(names.size() - 1));
}
public List<String> getNames() {
return names;
}
@Override
public String toString() {
String prefix = "";
if (mode == ABSOLUTE)
prefix = ".";
else if (mode == SUB_PAGE)
prefix = ">";
else if (mode == BACKWARD_SEARCH)
prefix = "<";
return prefix + StringUtils.join(names, ".");
}
public void removeNameFromEnd() {
if (!names.isEmpty())
names.removeLast();
}
public WikiPagePath append(WikiPagePath childPath) {
WikiPagePath newPath = new WikiPagePath(this);
for (WikiPagePath p = childPath; !p.isEmpty(); p = p.getRest())
newPath.addNameToEnd(p.getFirst());
return newPath;
}
public boolean isAbsolute() {
return (mode == ABSOLUTE);
}
public void makeAbsolute() {
mode = ABSOLUTE;
}
@Override
public int hashCode() {
return StringUtils.join(names, "").hashCode();
}
public WikiPagePath relativePath() {
if (isAbsolute() && !isEmpty()) {
WikiPagePath relativePath = new WikiPagePath(this);
relativePath.setPathMode(RELATIVE);
return relativePath;
} else
return this;
}
@Override
public int compareTo(Object o) {
if (o instanceof WikiPagePath) {
WikiPagePath p = (WikiPagePath) o;
String compressedName = StringUtils.join(names, "");
String compressedArgumentName = StringUtils.join(p.names, "");
return compressedName.compareTo(compressedArgumentName);
}
return 1; // we are greater because we are the right type.
}
@Override
public boolean equals(Object o) {
if (o instanceof WikiPagePath) {
WikiPagePath that = (WikiPagePath) o;
return mode == that.mode && this.names.equals(that.names);
}
return false;
}
public WikiPagePath parentPath() {
WikiPagePath parentPath = new WikiPagePath(this);
parentPath.removeNameFromEnd();
return parentPath;
}
public boolean startsWith(WikiPagePath that) {
if (that.names.size() > names.size())
return false;
Iterator<String> thisIterator = names.iterator();
for (String name : that.names) {
Object thisNext = thisIterator.next();
if (!thisNext.equals(name))
return false;
}
return true;
}
public WikiPagePath withNameAdded(String name) {
WikiPagePath path = new WikiPagePath(this);
path.addNameToEnd(name);
return path;
}
public WikiPagePath subtractFromFront(WikiPagePath operand) {
WikiPagePath difference = new WikiPagePath(this);
if (difference.startsWith(operand)) {
difference.setPathMode(Mode.RELATIVE);
for (String name : operand.getNames()) {
if (name.equals(difference.getFirst()))
difference.names.removeFirst();
else
break;
}
}
return difference;
}
public void setPathMode(Mode mode) {
this.mode = mode;
}
public boolean isRelativePath() {
return mode == RELATIVE;
}
public boolean isSubPagePath() {
return mode == SUB_PAGE;
}
public boolean isBackwardSearchPath() {
return mode == BACKWARD_SEARCH;
}
}