/*
 * Licensed to 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.expression.scalar.arithmetic;

import io.crate.data.Input;
import io.crate.metadata.BaseFunctionResolver;
import io.crate.metadata.functions.params.FuncParams;
import io.crate.metadata.FunctionIdent;
import io.crate.metadata.FunctionImplementation;
import io.crate.metadata.FunctionInfo;
import io.crate.metadata.FunctionResolver;
import io.crate.metadata.Scalar;
import io.crate.metadata.functions.params.Param;
import io.crate.expression.scalar.ScalarFunctionModule;
import io.crate.types.DataType;
import io.crate.types.DataTypes;
import org.elasticsearch.common.lucene.BytesRefs;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * _map(k, v, [...]) -> object
 *
 * args must be a multiple of 2
 *
 * k: must be a string
 *
 * Note that keys will be returned as String while values of type String will be BytesRef
 */
public class MapFunction extends Scalar<Object, Object> {

    public static final String NAME = "_map";

    private static final Param KEY = Param.STRING;
    private static final Param VALUE = Param.ANY;
    private static final FuncParams PARAMS = FuncParams.builder().withIndependentVarArgs(KEY, VALUE).build();

    private static final FunctionResolver RESOLVER = new BaseFunctionResolver(PARAMS) {

        @Override
        public FunctionImplementation getForTypes(List<DataType> dataTypes) throws IllegalArgumentException {
            return new MapFunction(createInfo(dataTypes));
        }
    };

    private final FunctionInfo info;

    private MapFunction(FunctionInfo info) {
        this.info = info;
    }

    public static FunctionInfo createInfo(List<DataType> dataTypes) {
        return new FunctionInfo(new FunctionIdent(NAME, dataTypes), DataTypes.OBJECT);
    }

    @Override
    public FunctionInfo info() {
        return info;
    }

    @SafeVarargs
    @Override
    public final Object evaluate(Input<Object>... args) {
        Map<String, Object> m = new HashMap<>(args.length / 2, 1.0f);
        for (int i = 0; i < args.length; i += 2) {
            m.put(BytesRefs.toBytesRef(args[i].value()).utf8ToString(), args[i + 1].value());
        }
        return m;
    }

    public static void register(ScalarFunctionModule scalarFunctionModule) {
        scalarFunctionModule.register(NAME, RESOLVER);
    }
}

@@ -1088,37 +1088,46 @@
 ate.
-metadata.BaseFunctionResolver
+expression.scalar.ScalarFunctionModule
 ;%0Aim
@@ -1153,35 +1153,28 @@
 ata.
-f
+BaseF
 unction
-s.params.FuncParams
+Resolver
 ;%0Aim
@@ -1417,21 +1417,26 @@
 .params.
+Func
 Param
+s
 ;%0Aimport
@@ -1449,46 +1449,39 @@
 ate.
-expression.scalar.ScalarFunctionModule
+metadata.functions.params.Param
 ;%0Aim
@@ -3024,16 +3024,20 @@
 s.length
+ - 1
 ; i += 2

Fix a array index out of bounds warning