package com.atlassian.stash.internal.web.soy.functions;

import com.atlassian.soy.renderer.JsExpression;
import com.atlassian.soy.renderer.SoyClientFunction;
import com.atlassian.soy.renderer.SoyServerFunction;

import java.util.Set;

public class FirstNonNullFunction implements SoyServerFunction<Object>, SoyClientFunction {
    public static final Set<Integer> VALID_ARG_SIZES = SoyArgumentUtils.argCountFromTo(2, 5);

    @Override
    public String getName() {
        return "firstNonNull";
    }

    @Override
    public JsExpression generate(JsExpression... args) {
        /*
         * There is a Soy "wontfix" issue for templates with only optional parameters,
         * where opt_data doesn't actually get defined if none of the optional parameters
         * are passed. We need an additional safety check to make sure we have an
         * opt_data object when we use firstNonNull otherwise we could get unexpected
         * 'undefined' errors
         *
         * https://code.google.com/p/closure-templates/issues/detail?id=50
         */
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < args.length; i++) {
            if (i > 0) {
                sb.append(",");
            }

            String argText = args[i].getText();

            if (argText.startsWith("opt_data.")) {
                sb.append("opt_data ? ");
                sb.append(argText);
                sb.append(" : null");
            } else {
                sb.append(argText);
            }
        }
        sb.append("].filter(function(x){return x != null;})[0]");
        return new JsExpression(sb.toString());
    }

    @Override
    public Object apply(Object... args) {
        for (Object arg : args) {
            if (arg != null) {
                return arg;
            }
        }
        return null;
    }

    @Override
    public Set<Integer> validArgSizes() {
        return VALID_ARG_SIZES;
    }
}
