/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.xml;
import java.util.LinkedList;
/**
* Helps to add new tree elements in specified places
*
* @author Eugene Voevodin
*/
public class XMLTreeLocation {
/**
* Location which indicates position after element with given name
*/
public static XMLTreeLocation after(String name) {
return new XMLTreeLocation(LocationType.AFTER, name);
}
/**
* Location which indicates position before element with given name
*/
public static XMLTreeLocation before(String name) {
return new XMLTreeLocation(LocationType.BEFORE, name);
}
/**
* Location which indicates after last element position
*/
public static XMLTreeLocation inTheEnd() {
return new XMLTreeLocation(LocationType.END, "");
}
/**
* Location which indicates before first element position
*/
public static XMLTreeLocation inTheBegin() {
return new XMLTreeLocation(LocationType.BEGIN, "");
}
/**
* Indicates position after any of elements with given names
*/
public static XMLTreeLocation afterAnyOf(String... names) {
if (names.length == 0) {
throw new IllegalArgumentException("Required not empty elements names");
}
return disjunctionChain(LocationType.AFTER, names);
}
/**
* Indicates position before any of elements with given names
*/
public static XMLTreeLocation beforeAnyOf(String... names) {
if (names.length == 0) {
throw new IllegalArgumentException("Required not empty elements names");
}
return disjunctionChain(LocationType.BEFORE, names);
}
/**
* Connects locations with same type by {@link #or} connector
*/
private static XMLTreeLocation disjunctionChain(LocationType location, String[] names) {
final XMLTreeLocation treeLocation = new XMLTreeLocation(location, names[0]);
for (int i = 1; i < names.length; i++) {
treeLocation.or(new XMLTreeLocation(location, names[i]));
}
return treeLocation;
}
private LinkedList<XMLTreeLocation> locations;
private LocationType location;
private String name;
private XMLTreeLocation(LocationType location, String name) {
this.location = location;
this.name = name;
}
public XMLTreeLocation or(XMLTreeLocation location) {
locations().add(location);
return this;
}
void evalInsert(Element parent, NewElement newElement) {
locations().addFirst(this);
for (XMLTreeLocation location : locations) {
switch (location.location) {
case AFTER:
if (parent.hasSingleChild(location.name)) {
parent.getSingleChild(location.name)
.insertAfter(newElement);
return;
}
break;
case BEFORE:
if (parent.hasSingleChild(location.name)) {
parent.getSingleChild(location.name)
.insertBefore(newElement);
return;
}
break;
case BEGIN:
final Element first = parent.getFirstChild();
if (first != null) {
first.insertBefore(newElement);
} else {
parent.appendChild(newElement);
}
return;
case END:
parent.appendChild(newElement);
return;
}
}
throw new XMLTreeException("It is not possible to insert element in specified location");
}
private LinkedList<XMLTreeLocation> locations() {
return locations == null ? locations = new LinkedList<>() : locations;
}
private enum LocationType {
AFTER,
BEFORE,
BEGIN,
END
}
}