/*
 * Copyright 2015-present Facebook, Inc.
 *
 * 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.facebook.buck.cxx;

import com.facebook.buck.rules.RuleKeyBuilder;
import com.facebook.buck.rules.args.RuleKeyAppendableFunction;
import com.facebook.buck.rules.coercer.PatternMatchedCollection;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;

import java.nio.file.Path;
import java.util.Map;
import java.util.SortedMap;

public class CxxFlags {

  private CxxFlags() {}

  public static RuleKeyAppendableFunction<String, String> getTranslateMacrosFn(
      final CxxPlatform cxxPlatform) {

    final ImmutableSortedMap<String, String> flagMacros =
        ImmutableSortedMap.copyOf(cxxPlatform.getFlagMacros());

    return new RuleKeyAppendableFunction<String, String>() {

      @Override
      public RuleKeyBuilder appendToRuleKey(RuleKeyBuilder builder) {
        SortedMap<String, String> sanitizedMap = Maps.transformValues(
            flagMacros,
            cxxPlatform.getDebugPathSanitizer().sanitize(Optional.<Path>absent()));
        return builder.setReflectively("flagMacros", sanitizedMap);
      }

      @Override
      public String apply(String flag) {
        // TODO(agallager): We're currently tied to `$VARIABLE` style of macros as much of the apple
        // support relies on this.  Long-term though, we should make this consistent with the
        // `$(macro ...)` style we use in the rest of the codebase.
        for (Map.Entry<String, String> entry : flagMacros.entrySet()) {
          flag = flag.replace("$" + entry.getKey(), entry.getValue());
        }
        return flag;
      }
    };
  }

  public static ImmutableList<String> getFlags(
      Optional<ImmutableList<String>> flags,
      Optional<PatternMatchedCollection<ImmutableList<String>>> platformFlags,
      CxxPlatform platform) {
    return FluentIterable
        .from(flags.or(ImmutableList.<String>of()))
        .append(
            Iterables.concat(
                platformFlags
                    .or(PatternMatchedCollection.<ImmutableList<String>>of())
                    .getMatchingValues(platform.getFlavor().toString())))
        .transform(getTranslateMacrosFn(platform))
        .toList();
  }

  private static ImmutableMultimap<CxxSource.Type, String> toLanguageFlags(
      ImmutableList<String> flags) {

    ImmutableMultimap.Builder<CxxSource.Type, String> result = ImmutableMultimap.builder();

    for (CxxSource.Type type : CxxSource.Type.values()) {
      result.putAll(type, flags);
    }

    return result.build();
  }

  public static ImmutableMultimap<CxxSource.Type, String> getLanguageFlags(
      Optional<ImmutableList<String>> flags,
      Optional<PatternMatchedCollection<ImmutableList<String>>> platformFlags,
      Optional<ImmutableMap<CxxSource.Type, ImmutableList<String>>> languageFlags,
      CxxPlatform platform) {

    ImmutableMultimap.Builder<CxxSource.Type, String> langFlags = ImmutableMultimap.builder();

    langFlags.putAll(toLanguageFlags(getFlags(flags, platformFlags, platform)));

    for (ImmutableMap.Entry<CxxSource.Type, ImmutableList<String>> entry :
         languageFlags.or(ImmutableMap.<CxxSource.Type, ImmutableList<String>>of()).entrySet()) {
      langFlags.putAll(
          entry.getKey(),
          Iterables.transform(entry.getValue(), getTranslateMacrosFn(platform)));
    }

    return langFlags.build();
  }

}

@@ -986,17 +986,26 @@
 mmutable
-M
+ListMultim
 ap;%0Aimpo
@@ -1043,21 +1043,16 @@
 mutableM
-ultim
 ap;%0Aimpo
@@ -3075,32 +3075,36 @@
 static Immutable
+List
 Multimap%3CCxxSour
@@ -3180,32 +3180,36 @@
 %7B%0A%0A    Immutable
+List
 Multimap.Builder
@@ -3243,32 +3243,36 @@
 sult = Immutable
+List
 Multimap.builder
@@ -3424,32 +3424,36 @@
 static Immutable
+List
 Multimap%3CCxxSour
@@ -3730,32 +3730,36 @@
 %7B%0A%0A    Immutable
+List
 Multimap.Builder
@@ -3794,16 +3794,24 @@
 gFlags =
+%0A       
  Immutab
@@ -3812,16 +3812,20 @@
 mmutable
+List
 Multimap

Use ImmutableListMultimap instead of ImmutableMultimap in CxxFlags