/*
 * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
 * license agreements.  See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.  Crate licenses
 * this file to you 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.
 *
 * However, if you have executed another commercial license agreement
 * with Crate these terms will supersede the license and you may use the
 * software solely pursuant to the terms of the relevant commercial agreement.
 */

package io.crate.metadata;

import io.crate.analyze.symbol.Function;
import io.crate.analyze.symbol.Literal;
import io.crate.analyze.symbol.Symbol;
import io.crate.data.Input;

import java.util.Collection;
import java.util.List;

/**
 * evaluable function implementation
 *
 * @param <ReturnType> the class of the returned value
 */
public abstract class Scalar<ReturnType, InputType> implements FunctionImplementation {

    public abstract ReturnType evaluate(Input<InputType>... args);

    /**
     * Returns a optional compiled version of the scalar implementation.
     */
    public Scalar<ReturnType, InputType> compile(List<Symbol> arguments) {
        return this;
    }

    @Override
    public Symbol normalizeSymbol(Function symbol, TransactionContext transactionContext) {
        try {
            return evaluateIfLiterals(this, symbol);
        } catch (Throwable t) {
            return symbol;
        }
    }

    protected static boolean anyNonLiterals(Collection<? extends Symbol> arguments) {
        for (Symbol symbol : arguments) {
            if (!symbol.symbolType().isValueSymbol()) {
                return true;
            }
        }
        return false;
    }

    /**
     * This method will evaluate the function using the given scalar if all arguments are literals.
     * Otherwise it will return the function as is or NULL in case it contains a null literal
     */
    private static <ReturnType, InputType> Symbol evaluateIfLiterals(Scalar<ReturnType, InputType> scalar, Function function) {
        List<Symbol> arguments = function.arguments();
        for (Symbol argument : arguments) {
            if (!(argument instanceof Input)) {
                return function;
            }
        }
        Input[] inputs = new Input[arguments.size()];
        int idx = 0;
        for (Symbol arg : arguments) {
            inputs[idx] = (Input) arg;
            idx++;
        }
        //noinspection unchecked
        return Literal.of(function.info().returnType(), scalar.evaluate(inputs));
    }
}

@@ -1254,41 +1254,775 @@
 %0A * 
-evaluable function implementation
+Base class for Scalar functions in crate.%0A * A Scalar function is a function which has zero or more arguments and returns a value. (not rows).%0A * %3Cp%3E%0A * Argument types and return types are restricted to the types supported by Crate (see %7B@link io.crate.types.DataType%7D)%0A * %3C/p%3E%0A *%0A * %3Cp%3E%0A *     Usually functions are registered as deterministic (See %7B@link io.crate.metadata.FunctionInfo.Feature%7D.%0A *     If this is the case the function must be a pure function. Meaning that given the same input it must always produce%0A *     the same output.%0A *%0A *     Functions also MUST NOT have any internal state that influences the result of future calls.%0A *     Functions are used as singletons.%0A *     An exception is if %7B@link #compile(List)%7D returns a NEW instance.%0A * %3C/p%3E
 %0A *%0A
@@ -2169,16 +2169,90 @@
 tion %7B%0A%0A
+    /**%0A     * Evaluate the function using the provided arguments%0A     */%0A
     publ
@@ -2330,73 +2330,503 @@
   * 
-R
+Called to r
 eturn
-s
  a 
+%22
 opti
-onal co
+mized%22 version of a scalar i
 mp
-i
 le
-d version of the scalar implement
+mentation.%0A     *%0A     * The returned instance will only be used in the context of a single query%0A     * (or rather, a subset of a single query if executed distributed).%0A     *%0A     * @param arguments arguments in symbol form. If any symbols are literals, any arguments passed to%0A     *                  %7B@link #evaluate(Input%5B%5D)%7D will have the same value as those literals.%0A     *                  (Within the scope of a single oper
 ation
-.
+)
 %0A   

Add javadocs to Scalar