/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.sync;

import java.util.Arrays;

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;

/**
 * Utilities for converting patch paths to/from SpEL expressions.
 * 
 * For example, "/foo/bars/1/baz" becomes "foo.bars[1].baz".
 * 
 * @author Craig Walls
 */
public class PathToSpEL {

	private static final SpelExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser();

	/**
	 * Converts a patch path to an {@link Expression}.
	 * @param path the patch path to convert.
	 * @return an {@link Expression}
	 */
	public static Expression pathToExpression(String path) {
		return SPEL_EXPRESSION_PARSER.parseExpression(pathToSpEL(path));
	}
	
	/**
	 * Convenience method to convert a SpEL String to an {@link Expression}.
	 * @param spel the SpEL expression as a String
	 * @return an {@link Expression}
	 */
	public static Expression spelToExpression(String spel) {
		return SPEL_EXPRESSION_PARSER.parseExpression(spel);
	}	
	
	/**
	 * Produces an expression targeting the parent of the object that the given path targets. 
	 * @param path the path to find a parent expression for.
	 * @return an {@link Expression} targeting the parent of the object specifed by path.
	 */
	public static Expression pathToParentExpression(String path) {
		return spelToExpression(pathNodesToSpEL(Arrays.copyOf(path.split("\\/"), path.split("\\/").length - 1)));
	}

	// private helpers
	
	private static String pathToSpEL(String path) {
		return pathNodesToSpEL(path.split("\\/"));
	}
	
	private static String pathNodesToSpEL(String[] pathNodes) {
		StringBuilder spelBuilder = new StringBuilder();
		
		for(int i=0; i < pathNodes.length; i++) {
			String pathNode = pathNodes[i];
			if (pathNode.length() == 0) {
				continue;
			}
			
			if ("~".equals(pathNode)) {
				spelBuilder.append("[size() - 1]");
				continue;
			}
			
			try {
				int index = Integer.parseInt(pathNode);
				spelBuilder.append('[').append(index).append(']');
			} catch (NumberFormatException e) {
				if (spelBuilder.length() > 0) {
					spelBuilder.append('.');	
				}
				spelBuilder.append(pathNode);
			}
		}
		
		String spel = spelBuilder.toString();
		if (spel.length() == 0) {
			spel = "#this";
		}
		return spel;		
	}

}

@@ -660,19 +660,26 @@
 ava.
-util
+lang.reflect
 .Array
-s
 ;%0A%0Ai
@@ -2003,15 +2003,8 @@
 pEL(
-Arrays.
 copy
@@ -2884,16 +2884,16 @@
 s%22;%0A%09%09%7D%0A
-
 %09%09return
@@ -2905,10 +2905,634 @@
 ;%09%09%0A%09%7D%0A%0A
+%09@SuppressWarnings(%22unchecked%22)%0A%09private static %3CT%3E T%5B%5D copyOf(T%5B%5D original, int newLength) %7B%0A%09%09return (T%5B%5D) copyOf(original, newLength, original.getClass());%0A%09%7D%0A%0A%09// reproduces Arrays.copyOf because that API is missing on Android 2.2%0A%09private static %3CT, U%3E T%5B%5D copyOf(U%5B%5D original, int newLength,%0A%09%09%09Class%3C? extends T%5B%5D%3E newType) %7B%0A%09%09@SuppressWarnings(%22unchecked%22)%0A%09%09T%5B%5D copy = ((Object) newType == (Object) Object%5B%5D.class) ? (T%5B%5D) new Object%5BnewLength%5D%0A%09%09%09%09: (T%5B%5D) Array.newInstance(newType.getComponentType(), newLength);%0A%09%09System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));%0A%09%09return copy;%0A%09%7D%0A%0A
 %7D%0A

Update PathToSpEL to support Android 2.2