/*
 * Copyright 2018 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.netflix.spinnaker.orca.pipelinetemplate.v2schema;

import com.netflix.spinnaker.orca.pipelinetemplate.TemplatedPipelineRequest;
import com.netflix.spinnaker.orca.pipelinetemplate.generator.V2ExecutionGenerator;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.TemplateMerge;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.graph.v2.transform.V2DefaultVariableAssignmentTransform;
import com.netflix.spinnaker.orca.pipelinetemplate.v2schema.model.V2PipelineTemplate;
import com.netflix.spinnaker.orca.pipelinetemplate.v2schema.model.V2TemplateConfiguration;
import java.util.*;

public class V2SchemaExecutionGenerator implements V2ExecutionGenerator {

  @Override
  public Map<String, Object> generate(
      V2PipelineTemplate template,
      V2TemplateConfiguration configuration,
      TemplatedPipelineRequest request) {
    Map<String, Object> pipeline = template.getPipeline();
    pipeline.put(
        "id",
        Optional.ofNullable(request.getId())
            .orElse(Optional.ofNullable(configuration.getPipelineConfigId()).orElse("unknown")));
    pipeline.put("application", configuration.getApplication());
    if (request.getExecutionId() != null) {
      pipeline.put("executionId", request.getExecutionId());
    }
    pipeline.put("name", Optional.ofNullable(configuration.getName()).orElse("Unnamed Execution"));

    if (!pipeline.containsKey("limitConcurrent")) {
      pipeline.put("limitConcurrent", request.isLimitConcurrent());
    }
    if (!pipeline.containsKey("keepWaitingPipelines")) {
      pipeline.put("keepWaitingPipelines", request.isKeepWaitingPipelines());
    }

    addNotifications(pipeline, template, configuration);
    addParameters(pipeline, template, configuration);
    addTriggers(pipeline, template, configuration);
    pipeline.put(
        "templateVariables",
        V2DefaultVariableAssignmentTransform.configurationVariables(
            template.getVariables(), configuration.getVariables()));

    if (request.getTrigger() != null && !request.getTrigger().isEmpty()) {
      pipeline.put("trigger", request.getTrigger());
    }

    return pipeline;
  }

  private void addNotifications(
      Map<String, Object> pipeline,
      V2PipelineTemplate template,
      V2TemplateConfiguration configuration) {
    if (configuration.getExclude().contains("notifications")) {
      pipeline.put(
          "notifications",
          Optional.ofNullable(configuration.getNotifications()).orElse(Collections.emptyList()));
    } else {
      pipeline.put(
          "notifications",
          TemplateMerge.mergeDistinct(
              (List<HashMap<String, Object>>) template.getPipeline().get("notifications"),
              configuration.getNotifications()));
    }
  }

  private void addParameters(
      Map<String, Object> pipeline,
      V2PipelineTemplate template,
      V2TemplateConfiguration configuration) {
    if (configuration.getExclude().contains("parameters")) {
      pipeline.put(
          "parameterConfig",
          Optional.ofNullable(configuration.getParameters()).orElse(Collections.emptyList()));
    } else {
      pipeline.put(
          "parameterConfig",
          TemplateMerge.mergeDistinct(
              (List<HashMap<String, Object>>) template.getPipeline().get("parameterConfig"),
              configuration.getParameters()));
    }
  }

  private void addTriggers(
      Map<String, Object> pipeline,
      V2PipelineTemplate template,
      V2TemplateConfiguration configuration) {
    if (configuration.getExclude().contains("triggers")) {
      pipeline.put(
          "triggers",
          Optional.ofNullable(configuration.getTriggers()).orElse(Collections.emptyList()));
    } else {
      pipeline.put(
          "triggers",
          TemplateMerge.mergeDistinct(
              (List<HashMap<String, Object>>) template.getPipeline().get("triggers"),
              configuration.getTriggers()));
    }
  }
}

@@ -3216,67 +3216,74 @@
     
-(List%3CHashMap%3CString, Object%3E%3E) template.getPipeline().get(
+markTemplateCollectionAsInherited(getTemplateCollection(template, 
 %22not
@@ -3294,16 +3294,17 @@
 ations%22)
+)
 ,%0A      
@@ -3830,67 +3830,74 @@
     
-(List%3CHashMap%3CString, Object%3E%3E) template.getPipeline().get(
+markTemplateCollectionAsInherited(getTemplateCollection(template, 
 %22par
@@ -3910,16 +3910,17 @@
 Config%22)
+)
 ,%0A      
@@ -4423,130 +4423,695 @@
     
-(List%3CHashMap%3CString, Object%3E%3E) template.getPipeline().get(%22triggers%22),
+markTemplateCollectionAsInherited(getTemplateCollection(template, %22triggers%22)),%0A              configuration.getTriggers()));%0A    %7D%0A  %7D%0A%0A  private static List%3CHashMap%3CString, Object%3E%3E markTemplateCollectionAsInherited(%0A      List%3CHashMap%3CString, Object%3E%3E templateCollection) %7B%0A    for (HashMap%3CString, Object%3E templateItem : templateCollection) %7B%0A      templateItem.put(%22inherited%22, true);
 %0A    
+%7D%0A
     
-      configuration.getTriggers()
+return templateCollection;%0A  %7D%0A%0A  private static List%3CHashMap%3CString, Object%3E%3E getTemplateCollection(%0A      V2PipelineTemplate template, String key) %7B%0A    return Optional.ofNullable((List%3CHashMap%3CString, Object%3E%3E) template.getPipeline().get(key
 ))
-;
 %0A    
-%7D
+    .orElse(Collections.emptyList());
 %0A  %7D

Mark mptv2 items as inherited (#2971)