package org.glassfish.pfl.basic.algorithm ;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List ;
import java.util.Map ;
import java.util.ArrayList ;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.pfl.basic.contain.Pair;
import org.glassfish.pfl.basic.func.BinaryFunction;
import org.glassfish.pfl.basic.func.UnaryFunction;
import org.glassfish.pfl.basic.func.UnaryPredicate;
public final class Algorithms {
private Algorithms() {}
public static <T> List<T> list( T... arg ) {
List<T> result = new ArrayList<T>() ;
for (T obj : arg) {
result.add( obj ) ;
}
return result ;
}
public static <S,T> Pair<S,T> pair( S first, T second ) {
return new Pair<S,T>( first, second ) ;
}
public static <K,V> Map<K,V> map( Pair<K,V>... pairs ) {
Map<K,V> result = new HashMap<K,V>() ;
for (Pair<K,V> pair : pairs ) {
result.put( pair.first(), pair.second() ) ;
}
return result ;
}
public static <A,R> UnaryFunction<A,R> mapToFunction( final Map<A,R> map ) {
return new UnaryFunction<A,R>() {
@Override
public R evaluate( A arg ) {
return map.get( arg ) ;
}
} ;
}
public static <A,R> void map( final Collection<A> arg,
final Collection<R> result,
final UnaryFunction<A,R> func ) {
for (A a : arg) {
final R newArg = func.evaluate( a ) ;
if (newArg != null) {
result.add( newArg ) ;
}
}
}
public static <K,A,R> Map<K,R> map( final Map<K,A> arg,
final UnaryFunction<A,R> func ) {
Map<K,R> result = new HashMap<K,R>() ;
for (Map.Entry<K,A> entry : arg.entrySet()) {
result.put( entry.getKey(),
func.evaluate( entry.getValue())) ;
}
return result ;
}
public static <A,R> List<R> map( final List<A> arg,
final UnaryFunction<A,R> func ) {
final List<R> result = new ArrayList<R>() ;
map( arg, result, func ) ;
return result ;
}
public static <A> UnaryPredicate<A> and(
final UnaryPredicate<A> arg1,
final UnaryPredicate<A> arg2 ) {
return new UnaryPredicate<A>() {
@Override
public boolean evaluate( A arg ) {
return arg1.evaluate( arg ) && arg2.evaluate( arg ) ;
}
} ;
}
public static <A> UnaryPredicate<A> or(
final UnaryPredicate<A> arg1,
final UnaryPredicate<A> arg2 ) {
return new UnaryPredicate<A>() {
@Override
public boolean evaluate( A arg ) {
return arg1.evaluate( arg ) || arg2.evaluate( arg ) ;
}
} ;
}
public static <T> UnaryPredicate<T> FALSE( Class<T> cls
) {
return new UnaryPredicate<T>() {
@Override
public boolean evaluate( T arg ) {
return false ;
}
} ;
} ;
public static <T> UnaryPredicate<T> TRUE( Class<T> cls
) {
return new UnaryPredicate<T>() {
@Override
public boolean evaluate( T arg ) {
return true ;
}
} ;
} ;
public static <A> UnaryPredicate<A> not(
final UnaryPredicate<A> arg1 ) {
return new UnaryPredicate<A>() {
@Override
public boolean evaluate( A arg ) {
return !arg1.evaluate( arg ) ;
}
} ;
}
public static <A> void filter( final List<A> arg, final List<A> result,
final UnaryPredicate<A> predicate ) {
final UnaryFunction<A,A> filter = new UnaryFunction<A,A>() {
@Override
public A evaluate( A arg ) {
return predicate.evaluate( arg ) ? arg : null ; } } ;
map( arg, result, filter ) ;
}
public static <A> List<A> filter( List<A> arg, UnaryPredicate<A> predicate ) {
List<A> result = new ArrayList<A>() ;
filter( arg, result, predicate ) ;
return result ;
}
public static <A> A find( List<A> arg, UnaryPredicate<A> predicate ) {
for (A a : arg) {
if (predicate.evaluate( a )) {
return a ;
}
}
return null ;
}
public static <A,R> R fold( List<A> list, R initial, BinaryFunction<R,A,R> func ) {
R result = initial ;
for (A elem : list) {
result = func.evaluate( result, elem ) ;
}
return result ;
}
public static <S,T> List<T> flatten( final List<S> list,
final UnaryFunction<S,List<T>> map ) {
return fold( list, new ArrayList<T>(),
new BinaryFunction<List<T>,S,List<T>>() {
@Override
public List<T> evaluate( List<T> arg1, S arg2 ) {
arg1.addAll( map.evaluate( arg2 ) ) ;
return arg1 ;
}
} ) ;
}
public static <T> T getFirst( Collection<T> list, Runnable handleEmptyList ) {
for (T element : list) {
return element ;
}
handleEmptyList.run();
return null ;
}
@SuppressWarnings({"unchecked"})
public static List convertToList( Object arg ) {
List result = new ArrayList() ;
if (arg != null) {
Class<?> cls = arg.getClass() ;
if (cls.isArray()) {
Class cclass = cls.getComponentType() ;
if (cclass.equals( int.class )) {
for (int elem : (int[])arg) {
result.add( elem ) ;
}
} else if (cclass.equals( byte.class )) {
for (byte elem : (byte[])arg) {
result.add( elem ) ;
}
} else if (cclass.equals( boolean.class )) {
for (boolean elem : (boolean[])arg) {
result.add( elem ) ;
}
} else if (cclass.equals( char.class )) {
for (char elem : (char[])arg) {
result.add( elem ) ;
}
} else if (cclass.equals( short.class )) {
for (short elem : (short[])arg) {
result.add( elem ) ;
}
} else if (cclass.equals( long.class )) {
for (long elem : (long[])arg) {
result.add( elem ) ;
}
} else if (cclass.equals( float.class )) {
for (float elem : (float[])arg) {
result.add( elem ) ;
}
} else if (cclass.equals( double.class )) {
for (double elem : (double[])arg) {
result.add( elem ) ;
}
} else {
return Arrays.asList( (Object[])arg ) ;
}
} else {
result.add( arg ) ;
return result ;
}
}
return result ;
}
public static String convertToString( Object arg ) {
if (arg == null) {
return "<NULL>";
}
Class<?> cls = arg.getClass() ;
if (cls.isArray()) {
Class<?> cclass = cls.getComponentType() ;
if (cclass.equals( int.class )) {
return Arrays.toString((int[]) arg);
}
if (cclass.equals( byte.class )) {
return Arrays.toString((byte[]) arg);
}
if (cclass.equals( boolean.class )) {
return Arrays.toString((boolean[]) arg);
}
if (cclass.equals( char.class )) {
return Arrays.toString((char[]) arg);
}
if (cclass.equals( short.class )) {
return Arrays.toString((short[]) arg);
}
if (cclass.equals( long.class )) {
return Arrays.toString((long[]) arg);
}
if (cclass.equals( float.class )) {
return Arrays.toString((float[]) arg);
}
if (cclass.equals( double.class )) {
return Arrays.toString((double[]) arg);
}
return Arrays.toString( (Object[])arg ) ;
} else {
return arg.toString() ;
}
}
private static List<Method> getDeclaredMethods( final Class<?> cls ) {
SecurityManager sman = System.getSecurityManager() ;
if (sman == null) {
return Arrays.asList( cls.getDeclaredMethods() ) ;
} else {
return AccessController.doPrivileged(
new PrivilegedAction<List<Method>>() {
@Override
public List<Method> run() {
return Arrays.asList( cls.getDeclaredMethods() ) ;
}
}
) ;
}
}
private static Set<String> annotationMethods ;
static {
annotationMethods = new HashSet<String>() ;
for (Method m : getDeclaredMethods( Annotation.class )) {
annotationMethods.add( m.getName()) ;
}
}
public static Map<String,Object> getAnnotationValues( Annotation ann,
boolean convertArraysToLists ) {
Map<String,Object> result = new HashMap<String,Object>() ;
for (Method m : getDeclaredMethods( ann.getClass() )) {
String name = m.getName() ;
if (!annotationMethods.contains( name ) ) {
Object value = null ;
try {
value = m.invoke(ann);
} catch (Exception ex) {
Logger.getLogger(Algorithms.class.getName()).log(Level.SEVERE, null, ex);
}
if (value != null) {
Class<?> valueClass = value.getClass() ;
if (valueClass.isAnnotation()) {
value = getAnnotationValues( (Annotation)value,
convertArraysToLists ) ;
} else if (convertArraysToLists && valueClass.isArray()) {
value = convertToList(value) ;
}
}
result.put( name, value ) ;
}
}
return result ;
}
public static interface Action<T> {
T run() throws Exception ;
}
private static <T> PrivilegedAction<T> makePrivilegedAction(
final Action<T> act ) {
return new PrivilegedAction<T>() {
@Override
public T run() {
try {
return act.run() ;
} catch (RuntimeException exc) {
throw exc ;
} catch (Exception ex) {
throw new RuntimeException( ex ) ;
}
}
} ;
}
public static <T> T doPrivileged( Action<T> func ) {
SecurityManager sman = System.getSecurityManager() ;
try {
if (sman == null) {
return func.run() ;
} else {
return AccessController.doPrivileged( makePrivilegedAction(
func ) ) ;
}
} catch (RuntimeException rex) {
throw rex ;
} catch (Exception ex) {
throw new RuntimeException( ex ) ;
}
}
}