// Path: src/joquery/GroupQuery.java
// public interface GroupQuery<Key,U> extends Query<Grouping<Key,U>,GroupQuery<Key,U>>
// {
//     Collection<Grouping<Key,U>> list() throws QueryException;
// 
//     GroupQuery<Key,U> groupBy(Function<U,?> by);
// 
//     GroupQuery<Key,U> groupBy(String by);
// }
// 
// Path: src/joquery/Grouping.java
// public class Grouping<T,U>
// {
//     private T key;
//     private Collection<U> values;
// 
//     public Grouping(T key)
//     {
//         this.key = key;
//         values = new ArrayList<>();
//     }
// 
//     public void Add(U u)
//     {
//         values.add(u);
//     }
// 
//     public T getKey()
//     {
//         return key;
//     }
// 
//     public Collection<U> getValues()
//     {
//         return values;
//     }
// }
// 
// Path: src/joquery/core/QueryException.java
// public class QueryException extends Exception
// {
//     public QueryException(String message)
//     {
//         super(message);
//     }
// 
//     public QueryException(String message, Throwable cause)
//     {
//         super(message, cause);
//     }
// }
// 
// Path: src/joquery/core/collection/expr/FunctionExpr.java
// public class FunctionExpr<T> implements IExpr<T>
// {
//     private Function<T,?> function;
// 
//     public FunctionExpr(Function<T,?> function)
//     {
//         this.function = function;
//     }
// 
//     @Override
//     public boolean supportsMode(QueryMode mode)
//     {
//         return mode == QueryMode.SELECT
//                 || mode == QueryMode.WHERE
//                 || mode == QueryMode.SORT;
//     }
// 
//     @Override
//     public boolean add(IExpr<T> expr)
//     {
//         return false;
//     }
// 
//     @Override
//     public Object evaluate(T t) throws QueryException
//     {
// 	    try
// 	    {
// 		    return function.apply(t);
// 	    }
// 	    catch (Exception ex)
// 	    {
// 		    throw new QueryException(String.format("Unable retrieve value for %s",function));
// 	    }
// 
//     }
// }
// 
// Path: src/joquery/core/collection/expr/IExpr.java
// public interface IExpr<T>
// {
//     boolean supportsMode(QueryMode mode);
// 
//     boolean add(IExpr<T> expr);
// 
//     Object evaluate(T t) throws QueryException;
// }
// 
// Path: src/joquery/core/collection/expr/ReflectionExpr.java
// public class ReflectionExpr<T> implements IExpr<T>
// {
//     private String property;
//     private Method method;
//     private Field field;
// 
//     public ReflectionExpr(String property)
//     {
//         this.property = property;
//     }
// 
//     @Override
//     public boolean supportsMode(QueryMode mode)
//     {
//         return mode == QueryMode.SELECT
//                 || mode == QueryMode.WHERE
//                 || mode == QueryMode.SORT;
//     }
// 
//     @Override
//     public boolean add(IExpr<T> expr)
//     {
//         return false;
//     }
// 
//     @Override
//     public Object evaluate(T t) throws QueryException
//     {
//         init(t);
//         return getValue(t);
//     }
// 
//     private void init(T t) throws QueryException
//     {
//         if (field != null || method != null)
//             return;
// 
//         try
//         {
//             initFieldIfNot(t);
//         }
//         catch (Exception ignored)
//         {
//         }
// 
//         try
//         {
//             initMethodIfNot(t);
//         }
//         catch (Exception ignored)
//         {
//         }
// 
//         if (!setAccessibleIfNeeded())
//         {
//             throw new QueryException(String.format("No property or getters can't be found for property %s",property));
//         }
//     }
// 
//     private boolean setAccessibleIfNeeded()
//     {
//         if (field != null
//                 && method == null
//                 && !field.isAccessible())
//         {
//             field.setAccessible(true);
//             return true;
//         }
//         else if (method != null
//                 && !method.isAccessible())
//         {
//             method.setAccessible(true);
//             return true;
//         }
//         return false;
//     }
// 
//     private void initFieldIfNot(T t) throws Exception
//     {
//         field = t.getClass().getDeclaredField(property);
//     }
// 
//     private void initMethodIfNot(T t) throws Exception
//     {
//         String camelCase = property.substring(0,1).toUpperCase() + property.substring(1);
//         try
//         {
//             method = t.getClass().getMethod("get" + camelCase);
//         }
//         catch (NoSuchMethodException e)
//         {
//             method = t.getClass().getMethod("is" + camelCase);
//         }
//     }
// 
//     private Object getValue(T t) throws QueryException
//     {
//         try
//         {
//             if (method != null)
//                 return method.invoke(t);
//             else if (field != null)
//                 return field.get(t);
//             return null;
//         }
//         catch (Exception ex)
//         {
//             throw new QueryException(String.format("Unable retrieve value for %s",property));
//         }
//     }
// }


import joquery.GroupQuery;
import joquery.Grouping;
import joquery.core.QueryException;
import joquery.core.collection.expr.FunctionExpr;
import joquery.core.collection.expr.IExpr;
import joquery.core.collection.expr.ReflectionExpr;
import java.util.*;
import java.util.function.Function;
package joquery.core.collection;



/**
 * User: Adipa
 * Date: 11/10/12
 * Time: 7:05 PM
 */
public class GroupQueryImpl<Key,U>
        extends QueryImpl<Grouping<Key,U>,GroupQuery<Key,U>>
        implements GroupQuery<Key,U>
{
    private Collection<U> itemsToGroup;
    private List<IExpr<U>> groupExpressions;

    public GroupQueryImpl(Collection<U> itemsToGroup)
    {
        this.itemsToGroup = itemsToGroup;
        groupExpressions = new ArrayList<>();
    }

	@Override
	public GroupQuery<Key, U> groupBy(Function<U, ?> by)
	{
// Path: src/joquery/GroupQuery.java
// public interface GroupQuery<Key,U> extends Query<Grouping<Key,U>,GroupQuery<Key,U>>
// {
//     Collection<Grouping<Key,U>> list() throws QueryException;
// 
//     GroupQuery<Key,U> groupBy(Function<U,?> by);
// 
//     GroupQuery<Key,U> groupBy(String by);
// }
// 
// Path: src/joquery/Grouping.java
// public class Grouping<T,U>
// {
//     private T key;
//     private Collection<U> values;
// 
//     public Grouping(T key)
//     {
//         this.key = key;
//         values = new ArrayList<>();
//     }
// 
//     public void Add(U u)
//     {
//         values.add(u);
//     }
// 
//     public T getKey()
//     {
//         return key;
//     }
// 
//     public Collection<U> getValues()
//     {
//         return values;
//     }
// }
// 
// Path: src/joquery/core/QueryException.java
// public class QueryException extends Exception
// {
//     public QueryException(String message)
//     {
//         super(message);
//     }
// 
//     public QueryException(String message, Throwable cause)
//     {
//         super(message, cause);
//     }
// }
// 
// Path: src/joquery/core/collection/expr/FunctionExpr.java
// public class FunctionExpr<T> implements IExpr<T>
// {
//     private Function<T,?> function;
// 
//     public FunctionExpr(Function<T,?> function)
//     {
//         this.function = function;
//     }
// 
//     @Override
//     public boolean supportsMode(QueryMode mode)
//     {
//         return mode == QueryMode.SELECT
//                 || mode == QueryMode.WHERE
//                 || mode == QueryMode.SORT;
//     }
// 
//     @Override
//     public boolean add(IExpr<T> expr)
//     {
//         return false;
//     }
// 
//     @Override
//     public Object evaluate(T t) throws QueryException
//     {
// 	    try
// 	    {
// 		    return function.apply(t);
// 	    }
// 	    catch (Exception ex)
// 	    {
// 		    throw new QueryException(String.format("Unable retrieve value for %s",function));
// 	    }
// 
//     }
// }
// 
// Path: src/joquery/core/collection/expr/IExpr.java
// public interface IExpr<T>
// {
//     boolean supportsMode(QueryMode mode);
// 
//     boolean add(IExpr<T> expr);
// 
//     Object evaluate(T t) throws QueryException;
// }
// 
// Path: src/joquery/core/collection/expr/ReflectionExpr.java
// public class ReflectionExpr<T> implements IExpr<T>
// {
//     private String property;
//     private Method method;
//     private Field field;
// 
//     public ReflectionExpr(String property)
//     {
//         this.property = property;
//     }
// 
//     @Override
//     public boolean supportsMode(QueryMode mode)
//     {
//         return mode == QueryMode.SELECT
//                 || mode == QueryMode.WHERE
//                 || mode == QueryMode.SORT;
//     }
// 
//     @Override
//     public boolean add(IExpr<T> expr)
//     {
//         return false;
//     }
// 
//     @Override
//     public Object evaluate(T t) throws QueryException
//     {
//         init(t);
//         return getValue(t);
//     }
// 
//     private void init(T t) throws QueryException
//     {
//         if (field != null || method != null)
//             return;
// 
//         try
//         {
//             initFieldIfNot(t);
//         }
//         catch (Exception ignored)
//         {
//         }
// 
//         try
//         {
//             initMethodIfNot(t);
//         }
//         catch (Exception ignored)
//         {
//         }
// 
//         if (!setAccessibleIfNeeded())
//         {
//             throw new QueryException(String.format("No property or getters can't be found for property %s",property));
//         }
//     }
// 
//     private boolean setAccessibleIfNeeded()
//     {
//         if (field != null
//                 && method == null
//                 && !field.isAccessible())
//         {
//             field.setAccessible(true);
//             return true;
//         }
//         else if (method != null
//                 && !method.isAccessible())
//         {
//             method.setAccessible(true);
//             return true;
//         }
//         return false;
//     }
// 
//     private void initFieldIfNot(T t) throws Exception
//     {
//         field = t.getClass().getDeclaredField(property);
//     }
// 
//     private void initMethodIfNot(T t) throws Exception
//     {
//         String camelCase = property.substring(0,1).toUpperCase() + property.substring(1);
//         try
//         {
//             method = t.getClass().getMethod("get" + camelCase);
//         }
//         catch (NoSuchMethodException e)
//         {
//             method = t.getClass().getMethod("is" + camelCase);
//         }
//     }
// 
//     private Object getValue(T t) throws QueryException
//     {
//         try
//         {
//             if (method != null)
//                 return method.invoke(t);
//             else if (field != null)
//                 return field.get(t);
//             return null;
//         }
//         catch (Exception ex)
//         {
//             throw new QueryException(String.format("Unable retrieve value for %s",property));
//         }
//     }
// }


// Path: src/joquery/core/collection/GroupQueryImpl.java
import joquery.GroupQuery;
import joquery.Grouping;
import joquery.core.QueryException;
import joquery.core.collection.expr.FunctionExpr;
import joquery.core.collection.expr.IExpr;
import joquery.core.collection.expr.ReflectionExpr;
import java.util.*;
import java.util.function.Function;

package joquery.core.collection;



/**
 * User: Adipa
 * Date: 11/10/12
 * Time: 7:05 PM
 */
public class GroupQueryImpl<Key,U>
        extends QueryImpl<Grouping<Key,U>,GroupQuery<Key,U>>
        implements GroupQuery<Key,U>
{
    private Collection<U> itemsToGroup;
    private List<IExpr<U>> groupExpressions;

    public GroupQueryImpl(Collection<U> itemsToGroup)
    {
        this.itemsToGroup = itemsToGroup;
        groupExpressions = new ArrayList<>();
    }

	@Override
	public GroupQuery<Key, U> groupBy(Function<U, ?> by)
	{
		groupExpressions.add(new FunctionExpr<>(by));