/* Copyright 2017 Google 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.google.api.codegen.transformer.ruby;

import com.google.api.codegen.InterfaceView;
import com.google.api.codegen.ProtoFileView;
import com.google.api.codegen.config.GapicInterfaceConfig;
import com.google.api.codegen.config.GapicProductConfig;
import com.google.api.codegen.config.PackageMetadataConfig;
import com.google.api.codegen.gapic.GapicCodePathMapper;
import com.google.api.codegen.transformer.FileHeaderTransformer;
import com.google.api.codegen.transformer.GrpcElementDocTransformer;
import com.google.api.codegen.transformer.ModelToViewTransformer;
import com.google.api.codegen.transformer.ModelTypeTable;
import com.google.api.codegen.transformer.SurfaceNamer;
import com.google.api.codegen.util.ruby.RubyTypeTable;
import com.google.api.codegen.viewmodel.GrpcDocView;
import com.google.api.codegen.viewmodel.ImportSectionView;
import com.google.api.codegen.viewmodel.ViewModel;
import com.google.api.codegen.viewmodel.metadata.ModuleView;
import com.google.api.codegen.viewmodel.metadata.SimpleModuleView;
import com.google.api.codegen.viewmodel.metadata.TocContentView;
import com.google.api.codegen.viewmodel.metadata.TocModuleView;
import com.google.api.tools.framework.model.Interface;
import com.google.api.tools.framework.model.Model;
import com.google.api.tools.framework.model.ProtoFile;
import com.google.common.collect.ImmutableList;
import java.util.List;

public class RubyGapicSurfaceDocTransformer implements ModelToViewTransformer {
  private static final String DOC_TEMPLATE_FILENAME = "ruby/message.snip";

  private final GapicCodePathMapper pathMapper;
  private final PackageMetadataConfig packageConfig;
  private final FileHeaderTransformer fileHeaderTransformer = new FileHeaderTransformer(null);
  private final GrpcElementDocTransformer elementDocTransformer = new GrpcElementDocTransformer();

  public RubyGapicSurfaceDocTransformer(
      GapicCodePathMapper pathMapper, PackageMetadataConfig packageConfig) {
    this.pathMapper = pathMapper;
    this.packageConfig = packageConfig;
  }

  @Override
  public List<String> getTemplateFileNames() {
    return ImmutableList.of(DOC_TEMPLATE_FILENAME);
  }

  @Override
  public List<ViewModel> transform(Model model, GapicProductConfig productConfig) {
    ImmutableList.Builder<ViewModel> surfaceDocs = ImmutableList.builder();
    for (ProtoFile file : new ProtoFileView().getElementIterable(model)) {
      surfaceDocs.add(generateDoc(file, productConfig));
    }
    return surfaceDocs.build();
  }

  private ViewModel generateDoc(ProtoFile file, GapicProductConfig productConfig) {
    ModelTypeTable typeTable =
        new ModelTypeTable(
            new RubyTypeTable(productConfig.getPackageName()),
            new RubyModelTypeNameConverter(productConfig.getPackageName()));
    // Use file path for package name to get file-specific package instead of package for the API.
    SurfaceNamer namer = new RubySurfaceNamer(typeTable.getFullNameFor(file));
    String subPath = pathMapper.getOutputPath(file, productConfig);
    String baseFilename = namer.getProtoFileName(file);
    GrpcDocView.Builder doc = GrpcDocView.newBuilder();
    doc.templateFileName(DOC_TEMPLATE_FILENAME);
    doc.outputPath(subPath + "/doc/" + baseFilename);
    doc.fileHeader(
        fileHeaderTransformer.generateFileHeader(
            productConfig, ImportSectionView.newBuilder().build(), namer));
    doc.elementDocs(elementDocTransformer.generateElementDocs(typeTable, namer, file));
    doc.modules(generateModuleViews(file.getModel(), productConfig, namer, file.isSource()));
    return doc.build();
  }

  private List<ModuleView> generateModuleViews(
      Model model, GapicProductConfig productConfig, SurfaceNamer namer, boolean hasToc) {
    ImmutableList.Builder<ModuleView> moduleViews = ImmutableList.builder();
    for (String moduleName : namer.getApiModules()) {
      if (hasToc && moduleName.equals(namer.getModuleVersionName())) {
        moduleViews.add(generateTocModuleView(model, productConfig, namer, moduleName));
      } else {
        moduleViews.add(SimpleModuleView.newBuilder().moduleName(moduleName).build());
      }
    }
    return moduleViews.build();
  }

  private TocModuleView generateTocModuleView(
      Model model, GapicProductConfig productConfig, SurfaceNamer namer, String moduleName) {
    RubyPackageMetadataTransformer metadataTransformer =
        new RubyPackageMetadataTransformer(packageConfig);
    RubyPackageMetadataNamer packageNamer =
        new RubyPackageMetadataNamer(productConfig.getPackageName());
    String version = packageConfig.apiVersion();
    ImmutableList.Builder<TocContentView> tocContents = ImmutableList.builder();
    for (Interface apiInterface : new InterfaceView().getElementIterable(model)) {
      GapicInterfaceConfig interfaceConfig = productConfig.getInterfaceConfig(apiInterface);
      tocContents.add(
          metadataTransformer.generateTocContent(
              model, packageNamer, version, namer.getApiWrapperClassName(interfaceConfig)));
    }

    tocContents.add(
        metadataTransformer.generateDataTypeTocContent(
            productConfig.getPackageName(), packageNamer, version));

    return TocModuleView.newBuilder()
        .moduleName(moduleName)
        .fullName(model.getServiceConfig().getTitle())
        .contents(tocContents.build())
        .build();
  }
}

@@ -1956,16 +1956,48 @@
 leList;%0A
+import com.google.protobuf.Api;%0A
 import j
@@ -4118,16 +4118,25 @@
 modules(
+%0A        
 generate
@@ -4190,21 +4190,16 @@
 er, 
-file.
 isSource
 ()))
@@ -4194,17 +4194,37 @@
 isSource
-(
+ApiInterfaceFile(file
 )));%0A   
@@ -4241,32 +4241,394 @@
 c.build();%0A  %7D%0A%0A
+  private boolean isSourceApiInterfaceFile(ProtoFile file) %7B%0A    List%3CApi%3E apis = file.getModel().getServiceConfig().getApisList();%0A    for (Interface apiInterface : file.getReachableInterfaces()) %7B%0A      for (Api api : apis) %7B%0A        if (api.getName().equals(apiInterface.getFullName())) %7B%0A          return true;%0A        %7D%0A      %7D%0A    %7D%0A    return false;%0A  %7D%0A%0A
   private List%3CM

Fix isSource check in gRPC doc generation (#1550)