/* * Copyright (C) 2014 The Android Open Source Project * * Licensed 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. */ package com.android.tools.idea.wizard; import com.android.tools.idea.templates.Parameter; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.Set; /** * Function for computing default parameter value based on current values of * other parameters. */ public final class ParameterDefaultValueComputer implements Function<Parameter, Object> { private final Map<Parameter, Object> nonDefaultValues; private final Map<String, Object> myImplicitParameters; @Nullable private final Deduplicator myDeduplicateValueFunction; private final StringEvaluator myStringEvaluator = new StringEvaluator(); private final Map<String, Parameter> myParameterIds; private Map<Parameter, Object> myDefaultsMap; private Set<Parameter> inComputation = Sets.newHashSet(); private ParameterDefaultValueComputer(Set<Parameter> parameterSet, Map<Parameter, Object> nonCurrentValues, Map<String, Object> implicitParameters, @Nullable Deduplicator deduplicateValueFunction) { nonDefaultValues = nonCurrentValues; myImplicitParameters = implicitParameters; myDeduplicateValueFunction = deduplicateValueFunction; myParameterIds = Maps.uniqueIndex(parameterSet, new Function<Parameter, String>() { @Override public String apply(Parameter input) { return input.id; } }); } /** * Return a dynamic map of parameter values. * <p/> * Performing get on the map will return the most current parameter value. * Changes to values map will be immediately reflected on the computed * default values. * * @param parameters list of parameters that need to be present in the map * @param values map of parameters with non-default values. * @param implicitParameters * @return dynamic map */ public static Map<Parameter, Object> newDefaultValuesMap(Iterable<Parameter> parameters, Map<Parameter, Object> values, Map<String, Object> implicitParameters, @Nullable Deduplicator deduplicateValueFunction) { Set<Parameter> parameterSet = FluentIterable.from(parameters).filter(new Predicate<Parameter>() { @Override public boolean apply(Parameter input) { return input != null && !StringUtil.isEmpty(input.name); } }).toSet(); ParameterDefaultValueComputer computer = new ParameterDefaultValueComputer(parameterSet, values, implicitParameters, deduplicateValueFunction); Map<Parameter, Object> defaultsMap = Maps.asMap(parameterSet, computer); computer.setDefaultsMap(defaultsMap); return defaultsMap; } @Nullable private static Object decodeInitialValue(Parameter input, @Nullable String initial) { if (initial != null && input.type == Parameter.Type.BOOLEAN) { return Boolean.valueOf(initial); } else { return initial; } } private synchronized void setDefaultsMap(Map<Parameter, Object> defaultsMap) { myDefaultsMap = defaultsMap; } @Override public Object apply(Parameter parameter) { if (nonDefaultValues.containsKey(parameter)) { return nonDefaultValues.get(parameter); } else { String value = !StringUtil.isEmpty(parameter.suggest) ? deriveValue(parameter) : parameter.initial; if (myDeduplicateValueFunction != null) { value = myDeduplicateValueFunction.deduplicate(parameter, value); } return decodeInitialValue(parameter, value); } } @Nullable private synchronized String deriveValue(Parameter parameter) { if (StringUtil.isEmpty(parameter.suggest)) { return null; } if (inComputation.contains(parameter)) { return ""; } inComputation.add(parameter); try { Function<Parameter, Object> values = Functions.forMap(myDefaultsMap); Function<String, Parameter> name = Functions.forMap(myParameterIds); Function<String, Object> nameToValue = Functions.compose(values, name); Map<String, Object> parameterIdToValue = Maps.newHashMap(); parameterIdToValue.putAll(getExternalValues()); parameterIdToValue.putAll(Maps.asMap(myParameterIds.keySet(), nameToValue)); return myStringEvaluator.evaluate(parameter.suggest, parameterIdToValue); } finally { inComputation.remove(parameter); } } private Map<String, Object> getExternalValues() { return myImplicitParameters; } public interface Deduplicator { @Nullable String deduplicate(@NotNull Parameter parameter, @Nullable String value); } }