// Copyright 2014 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.lib.rules.cpp;

import com.google.common.base.Function;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;

/**
 * Runfiles provider for C++ targets.
 *
 * <p>Contains two {@link Runfiles} objects: one for the eventual statically linked binary and one
 * for the one that uses shared libraries. Data dependencies are present in both.
 */
@Immutable
@AutoCodec
public final class CcRunfiles {

  private final Runfiles staticRunfiles;
  private final Runfiles sharedRunfiles;

  @AutoCodec.Instantiator
  public CcRunfiles(Runfiles staticRunfiles, Runfiles sharedRunfiles) {
    this.staticRunfiles = staticRunfiles;
    this.sharedRunfiles = sharedRunfiles;
  }

  public Runfiles getStaticRunfiles() {
    return staticRunfiles;
  }

  public Runfiles getSharedRunfiles() {
    return sharedRunfiles;
  }

  /**
   * Returns a function that gets the static C++ runfiles from a {@link TransitiveInfoCollection} or
   * the empty runfiles instance if it does not contain that provider.
   */
  public static final Function<TransitiveInfoCollection, Runfiles> STATIC_RUNFILES =
      input -> {
        CcLinkingInfo provider = input.get(CcLinkingInfo.PROVIDER);
        CcRunfiles ccRunfiles = provider == null ? null : provider.getCcRunfiles();
        return ccRunfiles == null ? Runfiles.EMPTY : ccRunfiles.getStaticRunfiles();
      };

  /**
   * Returns a function that gets the shared C++ runfiles from a {@link TransitiveInfoCollection} or
   * the empty runfiles instance if it does not contain that provider.
   */
  public static final Function<TransitiveInfoCollection, Runfiles> SHARED_RUNFILES =
      input -> {
        CcLinkingInfo provider = input.get(CcLinkingInfo.PROVIDER);
        CcRunfiles ccRunfiles = provider == null ? null : provider.getCcRunfiles();
        return ccRunfiles == null ? Runfiles.EMPTY : ccRunfiles.getSharedRunfiles();
      };

  /**
   * Returns a function that gets the C++ runfiles from a {@link TransitiveInfoCollection} or
   * the empty runfiles instance if it does not contain that provider.
   */
  public static final Function<TransitiveInfoCollection, Runfiles> runfilesFunction(
      boolean linkingStatically) {
    return linkingStatically ? STATIC_RUNFILES : SHARED_RUNFILES;
  }
}

@@ -1295,63 +1295,108 @@
 les 
-staticRunfiles;%0A  private final Runfiles sharedRunfiles
+dynamicLibrariesForLinkingStatically;%0A  private final Runfiles dynamicLibrariesForLinkingDynamically
 ;%0A%0A 
@@ -1440,16 +1440,23 @@
 unfiles(
+%0A      
 Runfiles
@@ -1460,277 +1460,508 @@
 les 
-staticRunfiles, Runfiles sharedRunfiles) %7B%0A    this.staticRunfiles = staticRunfiles;%0A    this.sharedRunfiles = sharedRunfiles;%0A  %7D%0A%0A  public Runfiles getStaticRunfiles() %7B%0A    return staticRunfiles;%0A  %7D%0A%0A  public Runfiles getSharedRunfiles() %7B%0A    return sharedRunfiles
+dynamicLibrariesForLinkingStatically,%0A      Runfiles dynamicLibrariesForLinkingDynamically) %7B%0A    this.dynamicLibrariesForLinkingStatically = dynamicLibrariesForLinkingStatically;%0A    this.dynamicLibrariesForLinkingDynamically = dynamicLibrariesForLinkingDynamically;%0A  %7D%0A%0A  public Runfiles getDynamicLibrariesForLinkingStatically() %7B%0A    return dynamicLibrariesForLinkingStatically;%0A  %7D%0A%0A  public Runfiles getDynamicLibrariesForLinkingDynamically() %7B%0A    return dynamicLibrariesForLinkingDynamically
 ;%0A  
@@ -2217,27 +2217,62 @@
 les%3E
- STATIC_RUNFILES =%0A
+%0A      DYNAMIC_LIBRARIES_FOR_LINKING_STATICALLY =%0A    
     
@@ -2276,32 +2276,36 @@
      input -%3E %7B%0A
+    
         CcLinkin
@@ -2356,32 +2356,36 @@
 VIDER);%0A        
+ 
+   
 CcRunfiles ccRun
@@ -2444,32 +2444,36 @@
 iles();%0A        
+    
 return ccRunfile
@@ -2473,32 +2473,48 @@
 Runfiles == null
+%0A               
  ? Runfiles.EMPT
@@ -2506,32 +2506,48 @@
 ? Runfiles.EMPTY
+%0A               
  : ccRunfiles.ge
@@ -2551,26 +2551,52 @@
 .get
-StaticRunfiles();%0A
+DynamicLibrariesForLinkingStatically();%0A    
     
@@ -2851,32 +2851,64 @@
 unfiles%3E
- SHARED_RUNFILES
+%0A      DYNAMIC_LIBRARIES_FOR_LINKING_DYNAMICALLY
  =%0A     
@@ -2904,24 +2904,28 @@
 LLY =%0A      
+    
 input -%3E %7B%0A 
@@ -2915,32 +2915,36 @@
      input -%3E %7B%0A
+    
         CcLinkin
@@ -2987,32 +2987,36 @@
 Info.PROVIDER);%0A
+    
         CcRunfil
@@ -3083,32 +3083,36 @@
 iles();%0A        
+    
 return ccRunfile
@@ -3120,16 +3120,32 @@
  == null
+%0A               
  ? Runfi
@@ -3153,16 +3153,32 @@
 es.EMPTY
+%0A               
  : ccRun
@@ -3190,26 +3190,53 @@
 .get
-SharedRunfiles();%0A
+DynamicLibrariesForLinkingDynamically();%0A    
     
@@ -3570,44 +3570,111 @@
 ally
- ? STATIC_RUNFILES : SHARED_RUNFILES
+%0A        ? DYNAMIC_LIBRARIES_FOR_LINKING_STATICALLY%0A        : DYNAMIC_LIBRARIES_FOR_LINKING_DYNAMICALLY
 ;%0A  

Rename staticRunfiles and dynamicRunfiles in CcRunfiles