
/*
 * Copyright (C) 2014 Archie L. Cobbs. All rights reserved.
 *
 * $Id$
 */

package org.jsimpledb.parse.func;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

import java.util.Map;

import org.jsimpledb.parse.ParseSession;
import org.jsimpledb.parse.expr.AbstractValue;
import org.jsimpledb.parse.expr.ConstValue;
import org.jsimpledb.parse.expr.EvalException;
import org.jsimpledb.parse.expr.Value;

@Function
public class FilterFunction extends ApplyExprFunction {

    public FilterFunction() {
        super("filter");
    }

    @Override
    public String getHelpSummary() {
        return "filters a collection";
    }

    @Override
    public String getUsage() {
        return "filters(items, variable, expression)";
    }

    @Override
    public String getHelpDetail() {
        return "Creates a filtered view of an Iterable, where items are included only if when the item is assigned to the"
          + " specified variable the specified expression evaluates to true. Maps are also supported, in which case the map's"
          + " entrySet() is filtered.";
    }

    @Override
    protected Value apply(ParseSession session, final ParamInfo params) {
        return new AbstractValue() {
            @Override
            public Object get(final ParseSession session) {

                // Evaluate items
                Object items = params.getItems().evaluate(session).checkNotNull(session, "filter()");
                if (items instanceof Map)
                    items = ((Map<?, ?>)items).entrySet();
                if (!(items instanceof Iterable)) {
                    throw new EvalException("invalid filter() operation on non-Iterable object of type "
                      + items.getClass().getName());
                }

                // Return filtered view
                return Iterables.filter((Iterable<?>)items, new Predicate<Object>() {
                    @Override
                    public boolean apply(Object item) {
                        return FilterFunction.this.evaluate(session, params.getVariable(),
                          new ConstValue(item), params.getExpr()).checkBoolean(session, "filter()");
                    }
                });
            }
        };
    }
}


@@ -197,29 +197,121 @@
 es;%0A
-%0Aimport java.util.Map
+import com.google.common.collect.Sets;%0A%0Aimport java.util.Map;%0Aimport java.util.NavigableSet;%0Aimport java.util.Set
 ;%0A%0Ai
@@ -1412,24 +1412,457 @@
 session) %7B%0A%0A
+                // Build predicate%0A                final Predicate%3CObject%3E predicate = new Predicate%3CObject%3E() %7B%0A                    @Override%0A                    public boolean apply(Object item) %7B%0A                        return FilterFunction.this.evaluate(session, params.getVariable(),%0A                          new ConstValue(item), params.getExpr()).checkBoolean(session, %22filter()%22);%0A                    %7D%0A                %7D;%0A%0A
             
@@ -2086,16 +2086,17 @@
 ySet();%0A
+%0A
         
@@ -2107,202 +2107,172 @@
     
-if (!(items instanceof Iterable)) %7B%0A                    throw new EvalException(%22invalid filter() operation on non-Iterable object of type %22%0A                      + items.getClass().getName()
+// Preserve NavigableSet if possible%0A                if (items instanceof NavigableSet)%0A                    return Sets.filter((NavigableSet%3C?%3E)items, predicate
 );%0A
+%0A
     
@@ -2287,51 +2287,81 @@
     
-%7D%0A%0A                // Return filtered view%0A
+// Preserve Set if possible%0A                if (items instanceof Set)%0A   
     
@@ -2376,23 +2376,19 @@
     
+ 
 return 
-Iterable
+Set
 s.fi
@@ -2393,24 +2393,19 @@
 filter((
-Iterable
+Set
 %3C?%3E)item
@@ -2407,29 +2407,25 @@
 )items, 
-new P
+p
 redicate
 %3CObject%3E
@@ -2412,36 +2412,27 @@
 s, predicate
-%3CObject%3E() %7B
+);%0A
 %0A           
@@ -2440,309 +2440,315 @@
     
-    @Override%0A                    public boolean apply(Object item) %7B%0A                        return FilterFunction.this.evaluate(session, params.getVariable(),%0A                          new ConstValue(item), params.getExpr()).checkBoolean(session, %22filter()%22);%0A                    %7D%0A                %7D
+// Return Iterable view%0A                if (items instanceof Iterable)%0A                    return Iterables.filter((Iterable%3C?%3E)items, predicate);%0A%0A                // Wrong type%0A                throw new EvalException(%22invalid filter() operation on non-Iterable object of type %22 + items.getClass().getName()
 );%0A 

Make filter() function preserve NavigableSet or Set nature if possible.