package flare.util
{    
    /**
     * Utility methods for creating filter functions. The static
     * <code>$()</code> method takes an arbitrary object and generates a
     * corresponding filter function.
     * 
     * <p>Filter functions are functions that take one argument and return a
     * <code>Boolean</code> value. The input argument to a filter function
     * passes the filter if the function returns true and fails the
     * filter if the function returns false.</p>
     */
    public class Filter
    {
        /**
         * Constructor, throws an error if called, as this is an abstract class.
         */
        public function Filter()
        {
            throw new Error("This is an abstract class.");
        }
        
        /**
         * Convenience method that returns a filter function determined by the
         * input object.
         * <ul>
         *  <li>If the input is null or a <code>Function</code>, it is simply
         *      returned.</li>
         *  <li>If the input is an <code>IPredicate</code>, its
         *      <code>predicate</code> function is returned.</li>
         *  <li>If the input is a <code>String</code>, a <code>Property</code>
         *      instance with the string as the property name is generated, and
         *      the <code>predicate</code> function of the property is
         *      returned.</li>
         *  <li>If the input is a <code>Class</code> instance, a function that
         *      performs type-checking for that class type is returned.</li>
         *  <li>In any other case, an error is thrown.</li>
         * </ul>
         * @param f an input object specifying the filter criteria
         * @return the filter function
         */
        public static function $(f:*):Function
        {
            if (f==null || f is Function) {
                return f;
            } else if (f is IPredicate) {
                return IPredicate(f).predicate;
            } else if (f is String) {
                return Property.$(f).predicate;
            } else if (f is Class) {
                return typeChecker(Class(f));
            } else {
                throw new ArgumentError("Unrecognized filter type");
            }
        }
        
        /**
         * Returns a filter function that performs type-checking. 
         * @param type the <code>Class</code> type to check for
         * @return a <code>Boolean</code>-valued type checking filter function
         */
        public static function typeChecker(type:Class):Function
        {
            return function(o:Object):Boolean { return o is type; }
        }

    } // end of class Filter
}