content: /**
   * Copyright (C) 2012 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 co.jirm.core.util;
  
  import static co.jirm.core.util.JirmPrecondition.check;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.Calendar;
  import java.util.List;
  import java.util.Map;
  
  import org.joda.time.DateTime;
  
  import co.jirm.core.JirmIllegalArgumentException;
  
  import com.google.common.collect.Maps;
  import com.google.common.primitives.Ints;
  
  
  public class ObjectMapUtils {
  	
  	public static StringBuilder toStringList(StringBuilder sb, List<?> objects, int length) {
  		sb.append("[");
  		boolean first = true;
  		for(Object o : objects) {
  			if (first) {
  				first = false;
  			}
  			else {
  				sb.append(", ");
  			}
  			final String s;
  			if (o instanceof Calendar) {
  				s = new DateTime(o).toString();
  			}
  			else {
  				s = o.toString();
  			}
  			if (length < s.length())
  				sb.append(s, 0, length).append("...");
  			else
  				sb.append(s);
  		}
  		sb.append("]");
  		return sb;
  	}
  	
  	//TODO cache
  	private static Enum<?>[] _enumValues(Class<?> enumClass) throws SecurityException, NoSuchMethodException, 
  		IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  		Method m = enumClass.getMethod("values");
  		return (Enum<?>[]) m.invoke((Object) null);
  	}
  	
  	public static Enum<?>[] enumValues(Class<?> enumClass) {
  		try {
  			return _enumValues(enumClass);
  		} catch (Exception e) {
  			throw new JirmIllegalArgumentException("Cannot dynamically resolve enum values for:" + enumClass, e);
  		}
  	}
  	
  	public static Enum<?> enumFrom(Class<?> enumClass, int oridinal) {
  		return enumValues(enumClass)[oridinal];
  	}
  	public static Enum<?> enumFrom(Class<?> enumClass, String name) {
  		Enum<?>[] enums = enumValues(enumClass);
  		for (Enum<?> e : enums) {
  			if (e.name().equals(name)) {
  				return e;
  			}
  		}
  		throw check.argumentInvalid("name: {} is not valid for: {}", name, enumClass);
  	}
  	
  	@SuppressWarnings("unchecked")
  	public static void pushPath(final Map<String, Object> m, List<String> names, Object value) {
  		Map<String,Object> current = m;
  		int j = 0;
  		for (String n : names) {
  			j++;
  			if (j == names.size()) {
  				current.put(n, value);
  				break;
  			}
  			Object o = current.get(n);
  			if (o == null) {
  				Map<String, Object> sub = Maps.newLinkedHashMap();
  				current.put(n, sub);
  				current = sub;
  			}
  			else if (o instanceof Map) {
  				current = (Map<String,Object>) o;
  			}
  			else {
  				throw new IllegalArgumentException("Cannot set value to " + names);
  			}
  		}
  	}
  	
  	public static <T> NestedKeyValue<T> getNestedKeyValue(Map<?,?> m, Object... keys) {
  		return _getNestedKeyValue(m, null, null, keys);
  	}
  	
  	@SuppressWarnings("unchecked")
  	private static <T> NestedKeyValue<T> _getNestedKeyValue(final Map<?,?> m, final List<?> l, final Class<T> c, Object... keys) {
  		Object t = null;
  		check.argument(m == null || l == null, "Either m or l should be null");
  		Map<?,?> tm = m;
  		List<?> tl = l;
  		
  		int i = 0;
  		for(Object k : keys) {
  			if (tm != null && tm.containsKey(k)) {
  				t =  tm.get(k);
  			}
  			else if (tl != null && k instanceof Number) {
  				t = tl.get(((Number) k).intValue());
  			}
  			else if ( tl != null && k instanceof String 
  					&& ! ((String) k).isEmpty() 
  					&&  Ints.tryParse((String)k) != null) {
  				t = tl.get(Integer.parseInt(k.toString()));
  			}
  			else {
  				t = null;
  				break;
  			}
  			
  			if (t instanceof Map) {
  				tm = (Map<?,?>) t;
  				tl = null;
  			}
  			else if (t instanceof List) {
  				tl = (List<?>) t;
  				tm = null;
  			}
  			else if ( t == null ) {
  				break;
  			}
  			i++;
  		}
  		boolean conflict = t != null && c != null && ! c.isInstance(t);
  		T object = conflict ? null : (T) t;
  		
  		
  		return new NestedKeyValue<T>(object, keys, i, conflict);
  		
  	}
  	
  	public static class NestedKeyValue<T> {
  		public final T object;
  		public final int depthStopped;
  		public final Object[] keys;
  		public final boolean conflict;
  		
  		private NestedKeyValue(T object, Object[] keys, int depthStopped, boolean conflict) {
  			super();
  			this.object = object;
  			this.keys = keys;
  			this.depthStopped = depthStopped;
  			this.conflict = conflict;
  		}
  		
  		public boolean isPresent() {
  			return depthStopped == keys.length;
  		}
  	}
  
  }
  