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

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;

import java.util.Arrays;
import java.util.Set;

public final class SoyArgumentUtils {

    private SoyArgumentUtils() {
        throw new UnsupportedOperationException("Static utility class, do not instantiate.");
    }

    public static void ensureArgumentTypeIsOneOf(Object[] args, int index, Class<?>... classes) {
        Object arg = args[index];
        for (Class<?> klass : classes) {
            if (klass.isAssignableFrom(arg.getClass())) {
                return;
            }
        }
        throw new IllegalArgumentException(String.format("Expected arg %d to be one of %s, but was %s", index, Arrays.asList(classes).toString(), arg.getClass().getSimpleName()));
    }

    public static String getStringArgument(Object[] args, int index) {
        return getArgument(args, index, String.class);
    }

    public static <T> T getArgument(Object[] args, int index, Class<T> klass) {
        if (args.length < index) {
            throw new IllegalArgumentException(String.format("Expected arg %d to be %s, but there are only %d args.",
                    index, klass.getSimpleName(), args.length));
        }
        Object arg = args[index];
        if (klass.isAssignableFrom(arg.getClass())) {
            return klass.cast(arg);
        } else {
            throw new IllegalArgumentException(String.format("Expected arg %d to be %s, but was %s",
                    index, klass.getSimpleName(), arg.getClass().getSimpleName()));
        }
    }

    public static Set<Integer> argCountOf(int count) {
        return ImmutableSet.of(count);
    }

    public static Set<Integer> argCountFromTo(int from, int to) {
        Preconditions.checkArgument(from >= 0, "from >= 0");
        Preconditions.checkArgument(from <= to, "from <= to");

        ImmutableSet.Builder<Integer> builder = ImmutableSet.builder();
        for (int i = from; i <= to; i++) {
            builder.add(i);
        }
        return builder.build();
    }

    public static <T> T checkType(Object[] args, Class<T> clazz, int argIndex) {
        return checkType(args, clazz, argIndex, String.format("Arg[%s] should be of type %s", argIndex, clazz.getSimpleName()));
    }

    public static <T> T checkType(Object[] args, Class<T> clazz, int argIndex, String message) {
        Object arg = args[argIndex];
        if (arg == null || !clazz.isAssignableFrom(arg.getClass())) {
            throw new IllegalArgumentException(message);
        }
        return (T) arg;
    }
}
