// Copyright 2019 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.android;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.android.resources.ResourceType;
import com.google.devtools.build.android.resources.Visibility;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * Generates an R.txt file (with dummy values) declaring the fields used by a library.
 *
 * <p>The real IDs will be collected by the R.txt file from aapt2 and joined via {@code
 * com.google.devtools.build.android.resources.FieldInitializers}.
 */
final class PlaceholderRTxtWriter extends AndroidResourceSymbolSink {

  private final Path rTxtOut;

  private final Map<ResourceType, Set<String>> innerClasses = new EnumMap<>(ResourceType.class);
  private final Map<String, Set</*attr=*/ String>> styleables = new TreeMap<>();

  static PlaceholderRTxtWriter create(Path rTxtOut) {
    return new PlaceholderRTxtWriter(rTxtOut);
  }

  private PlaceholderRTxtWriter(Path rTxtOut) {
    this.rTxtOut = rTxtOut;
  }

  @Override
  protected void acceptSimpleResourceImpl(
      DependencyInfo dependencyInfo, Visibility visibility, ResourceType type, String name) {
    innerClasses
        .computeIfAbsent(type, t -> new TreeSet<>())
        .add(PlaceholderIdFieldInitializerBuilder.normalizeName(name));
  }

  @Override
  protected void acceptStyleableResourceImpl(
      DependencyInfo dependencyInfo,
      Visibility visibility,
      FullyQualifiedName key,
      Map<FullyQualifiedName, Boolean> attrs) {
    Set<String> attrSet =
        styleables.computeIfAbsent(
            PlaceholderIdFieldInitializerBuilder.normalizeName(key.name()), n -> new TreeSet<>());

    for (FullyQualifiedName attr : attrs.keySet()) {
      attrSet.add(PlaceholderIdFieldInitializerBuilder.normalizeAttrName(attr));
    }
  }

  @Override
  public void flush() throws IOException {
    try (BufferedWriter writer = Files.newBufferedWriter(rTxtOut, UTF_8)) {
      for (Map.Entry<ResourceType, Set<String>> innerClass : innerClasses.entrySet()) {
        ResourceType resourceType = innerClass.getKey();
        for (String fieldName : innerClass.getValue()) {
          writer.write(String.format("int %s %s 0\n", resourceType.getName(), fieldName));
        }
      }

      for (Map.Entry<String, Set<String>> styleable : styleables.entrySet()) {
        // NB: the size of this array is irrelevant, we just need to declare it as one.
        writer.write(String.format("int[] styleable %s { 0 }\n", styleable.getKey()));

        for (String attr : styleable.getValue()) {
          writer.write(String.format("int styleable %s_%s 0\n", styleable.getKey(), attr));
        }
      }
    }
  }
}
