/*
* Copyright (c) 2014 Oculus Info Inc. http://www.oculusinfo.com/
*
* Released under the MIT License.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oculusinfo.binning.metadata;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Simple class to encapsulate a json Mutation, for use by the versioning code.
* JsonMutators mutate the passed-in JSON object, in place.
*/
public abstract class JsonMutator {
abstract public void mutateJson (JSONObject json) throws JSONException;
protected static class LocationInformation {
List<JSONObject> _tree;
List<List<String>> _matches;
LocationInformation () {
_tree = new ArrayList<>();
_matches = new ArrayList<>();
}
public int size () {
return _tree.size();
}
public JSONObject get (int index) {
return _tree.get(index);
}
public String getFullMatch (int i) {
return _matches.get(i).get(0);
}
}
private static Pattern GROUP_PATTERN= Pattern.compile("\\\\([0-9]+)\\.([0-9]+)");
protected static String substitute (String text, List<List<String>> matchGroups) {
Matcher matcher = GROUP_PATTERN.matcher(text);
if (matcher.find()) {
int start = matcher.start(0);
int end = matcher.end(0);
int index1 = Integer.parseInt(matcher.group(1));
int index2 = Integer.parseInt(matcher.group(2));
text = text.substring(0, start)+matchGroups.get(index1).get(index2)+text.substring(end);
text = substitute(text, matchGroups);
}
return text;
}
/**
* Search for the given path in the given JSON object. If createPath is
* false, then the path can contain regular expressions; if true, it can
* not, but may contain group indicators (in the form "\\a.b", where a is
* the index in the outer list of matchGroups, and b, the index in the
* inner)
*
* @param root The JSON object to search
* @param path The path elements to search for a given node
* @param matchGroups Match elements to substitute into the path if
* createPath is true
* @param pathIndex The current index being searched in the path array
* @param createPath if the path sought should be created if not there (in
* which case group substitutions will be allowed)
*/
protected List<LocationInformation> getTree (JSONObject root, String[] path, List<List<String>> matchGroups,
int pathIndex, boolean createPath) throws JSONException {
List<LocationInformation> infos = new ArrayList<>();
boolean last = (pathIndex == path.length-1);
if (!last && createPath) {
String pathElt = substitute(path[pathIndex], matchGroups);
if (!root.has(pathElt)) {
root.put(pathElt, new JSONObject());
}
}
String[] branches = JSONObject.getNames(root);
String pathElt = substitute(path[pathIndex], matchGroups);
if (null != branches) {
Pattern pathPattern = Pattern.compile(pathElt);
for (String branch: branches) {
Matcher matcher = pathPattern.matcher(branch);
if (matcher.matches()) {
List<String> groups = new ArrayList<>();
for (int i=0; i<=matcher.groupCount(); ++i) {
groups.add(matcher.group(i));
}
if (last) {
LocationInformation info = new LocationInformation();
info._tree.add(root);
info._matches.add(groups);
infos.add(info);
} else {
JSONObject branchObject = root.getJSONObject(pathElt);
List<LocationInformation> subInfos = getTree(branchObject, path, matchGroups, pathIndex+1, createPath);
for (LocationInformation info: subInfos) {
info._tree.add(0, root);
info._matches.add(0, groups);
infos.add(info);
}
}
}
}
}
if (last && infos.isEmpty() && createPath) {
LocationInformation info = new LocationInformation();
info._tree.add(root);
List<String> matches = new ArrayList<>();
matches.add(pathElt);
info._matches.add(matches);
infos.add(info);
}
return infos;
}
/*
if (pathIndex == path.length - 1) {
infos = new ArrayList<>();
String[] branches = JSONObject.getNames(root);
if (null != branches) {
Pattern pathPattern = Pattern.compile(path[pathIndex]);
for (String branch: branches) {
Matcher matcher = pathPattern.matcher(branch);
if (matcher.matches()) {
List<String> groups = new ArrayList<>();
for (int i=0; i<=matcher.groupCount(); ++i) {
groups.add(matcher.group(i));
}
LocationInformation info = new LocationInformation();
info._tree.add(root);
info._matches.add(groups);
infos.add(info);
}
}
if (infos.isEmpty() && createPath) {
LocationInformation info = new LocationInformation();
info._tree.add(root);
info._matches.add(new ArrayList<String>());
infos.add(info);
}
}
} else {
if (createPath) {
String pathElt = substitute(path[pathIndex], matchGroups);
if (!root.has(pathElt)) {
root.put(pathElt, new JSONObject());
}
}
String[] branches = JSONObject.getNames(root);
if (null != branches) {
Pattern pathPattern = Pattern.compile(path[pathIndex]);
for (String branch: branches) {
Matcher matcher = pathPattern.matcher(branch);
if (matcher.matches()) {
List<String> groups = new ArrayList<>();
for (int i=0; i<=matcher.groupCount(); ++i) {
groups.add(matcher.group(i));
}
JSONObject branchObject = root.getJSONObject(path[pathIndex]);
infos = getTree(branchObject, path, matchGroups, pathIndex+1, createPath);
for (LocationInformation info: infos) {
info._tree.add(0, root);
info._matches.add(0, groups);
}
}
}
}
}
return infos;
}
*/
protected void cleanTree (LocationInformation tree, String[] path) {
int size = tree.size();
if (size == path.length) {
for (int i=size-1; i>0 && 0 == tree.get(i).length(); --i) {
tree.get(i-1).remove(path[i-1]);
}
}
}
}