<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <UsingTask TaskName="FindBestConfigurations" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.Tasks.dll"/>
  <PropertyGroup>
    <ImportedBuildVerticalTargets>true</ImportedBuildVerticalTargets>
    <_traversalBuildConfigurations>$(BuildConfiguration)</_traversalBuildConfigurations>
    <_traversalBuildConfigurations Condition="'$(AdditionalBuildConfigurations)' != ''">$(_traversalBuildConfigurations);$(AdditionalBuildConfigurations)</_traversalBuildConfigurations>
  </PropertyGroup>

  <!-- Import configuration data model -->
  <Import Project="$(ProjectDir)tools-local/properties.props" />

  <!-- Runs during traversal when BuildAllConfigurations is set to expand each project
       to a seperate instance for each of its BuildConfigurations -->
  <Target Name="ExpandAllBuildConfigurations"
          Condition="'$(BuildAllConfigurations)' == 'true'">
    <MSBuild Targets="GetBuildConfigurations"
             Projects="@(Project)"
             Condition="'$(BuildAllConfigurations)' == 'true'">
      <Output TaskParameter="TargetOutputs"
              ItemName="_projectBuildConfigurations" />
    </MSBuild>

    <ItemGroup>
      <!-- assign configuration as a seperate step to prevent batching during the transform which can reorder the list.
           order or projects matters here since this applies to traversal projects which build projects serially. -->
      <_projectBuildConfigurations>
        <AdditionalProperties>Configuration=%(Identity);%(_projectBuildConfigurations.AdditionalProperties)</AdditionalProperties>
      </_projectBuildConfigurations>

      <!-- we need to ignore placeholder build configurations that start with _ -->
      <_projectBuildConfigurations Remove="@(_projectBuildConfigurations)" Condition="$([System.String]::Copy('%(Identity)').StartsWith('_'))" />

      <!-- transform back to project -->
      <_projectWithConfiguration Include="@(_projectBuildConfigurations->'%(OriginalItemSpec)')" />
    </ItemGroup>

    <ItemGroup>
      <Project Remove="@(Project)" />
      <Project Include="@(_projectWithConfiguration)" />
    </ItemGroup>
  </Target>

  <Target Name="ExpandAllBuildConfigurationsForPkgProj"
          BeforeTargets="ExpandProjectReferences"
          Condition="'$(MSBuildProjectExtension)' == '.pkgproj'">
    <MSBuild Targets="GetPackageConfigurations"
             Projects="@(_NonPkgProjProjectReference)">
      <Output TaskParameter="TargetOutputs"
              ItemName="_NonPkgProjProjectReferenceBuildConfigurations" />
    </MSBuild>

    <ItemGroup>
      <!-- assign configuration as a seperate step to prevent batching during the transform which can reorder the list.
           order or projects matters here since this applies to traversal projects which build projects serially. -->
      <_NonPkgProjProjectReferenceBuildConfigurations>
        <AdditionalProperties>Configuration=%(Identity);%(_NonPkgProjProjectReferenceBuildConfigurations.AdditionalProperties)</AdditionalProperties>
      </_NonPkgProjProjectReferenceBuildConfigurations>

      <!-- we need to ignore placeholder build configurations that start with _ -->
      <_NonPkgProjProjectReferenceBuildConfigurations Remove="@(_NonPkgProjProjectReferenceBuildConfigurations)" Condition="$([System.String]::Copy('%(Identity)').StartsWith('_'))" />

      <!-- transform back to project -->
      <_NonPkgProjProjectReferenceWitnConfiguration Include="@(_NonPkgProjProjectReferenceBuildConfigurations->'%(OriginalItemSpec)')" />
    </ItemGroup>

    <ItemGroup>
      <_NonPkgProjProjectReference Remove="@(_NonPkgProjProjectReference)" />
      <_NonPkgProjProjectReference Include="@(_NonPkgProjProjectReferenceWitnConfiguration)" />
    </ItemGroup>
  </Target>

  <!-- Runs during traversal to select which projects and configurations of those projects to build
       Batches over the projects because we need to treat BuildConfigurations as a Property
       as well as copy the Project based on results of FindBestConfigurations. -->
  <Target Name="FilterBuildConfiguration"
          Condition="'$(BuildAllConfigurations)' != 'true'"
          Inputs="%(Project.Identity)"
          Outputs="unused">

    <MSBuild Targets="GetBuildConfigurations"
             Projects="@(Project)">
      <Output TaskParameter="TargetOutputs"
              PropertyName="_projectBuildConfigurations" />
    </MSBuild>

    <FindBestConfigurations Properties="@(Property)"
                            PropertyValues="@(PropertyValue)"
                            SupportedConfigurations="$(_projectBuildConfigurations)"
                            Configurations="$(_traversalBuildConfigurations)">
      <Output TaskParameter="BestConfigurations" ItemName="_projectBestConfigurations" />
    </FindBestConfigurations>

    <ItemGroup>
      <!-- Apply configuration, this does a catesian product between @(Project) and @(_projectBestConfigurations) -->
      <_projectWithConfiguration Include="@(Project)" Condition="'@(_projectBestConfigurations)' != ''">
        <AdditionalProperties>Configuration=%(_projectBestConfigurations.Identity);%(_projectWithConfiguration.AdditionalProperties)</AdditionalProperties>
      </_projectWithConfiguration>
      <Project Remove="@(Project)"/>
      <Project Include="@(_projectWithConfiguration)"/>
    </ItemGroup>
  </Target>

  <Target Name="FilterProjects"
          Condition="'$(FilterProjectsByBuildConfiguration)' != 'false'"
          DependsOnTargets="ExpandAllBuildConfigurations;FilterBuildConfiguration" />

  <!-- Runs in a leaf project (eg: csproj) to determine all configurations -->
  <Target Name="GetBuildConfigurations"
          Returns="$(_AllBuildConfigurations)">
    <PropertyGroup>
      <_AllBuildConfigurations>$(BuildConfigurations)</_AllBuildConfigurations>
      <_AllBuildConfigurations Condition="'$(BuildConfigurations)' == ''">$(_traversalBuildConfigurations)</_AllBuildConfigurations>
    </PropertyGroup>

    <!-- Filter out configurations for things not in netcoreapp when building only netcoreapp -->
    <PropertyGroup Condition="'$(BuildNETCoreAppOnly)' == 'true' and ('$(MSBuildProjectExtension)' == '.csproj' or '$(MSBuildProjectExtension)' == '.ilproj')">
      <PartOfNETCoreAppBuild Condition="'$(PartOfNETCoreAppBuild)' == ''">$(IsNETCoreApp)</PartOfNETCoreAppBuild>

      <_AllBuildConfigurations Condition="'$(PartOfNETCoreAppBuild)' != 'true'"></_AllBuildConfigurations>
    </PropertyGroup>

  </Target>

  <!-- Runs in a leaf project (eg: csproj) to determine configurations to package -->
  <Target Name="GetPackageConfigurations"
          Returns="$(PackageConfigurations)">
     <ItemGroup Condition="'$(PackageConfigurations)' == ''">
       <_buildConfigurations Include="$(BuildConfigurations)" />
       <_excludeBuildConfigurations Include="mono" />
       <_packageConfigurations Include="@(_buildConfigurations)" Exclude="@(_excludeBuildConfigurations)" />
     </ItemGroup>

     <PropertyGroup Condition="'$(PackageConfigurations)' == ''">
       <PackageConfigurations>@(_packageConfigurations)</PackageConfigurations>
     </PropertyGroup>
  </Target>

  <!-- Runs in a leaf project (csproj) to determine best configuration for ProjectReferences -->
  <Target Name="AnnotateProjectReference"
          BeforeTargets="AssignProjectConfiguration"
          Condition="'@(ProjectReference)' != ''"
          Inputs="%(ProjectReference.Identity)"
          Outputs="unused">

    <MSBuild Targets="GetBuildConfigurations"
             Projects="@(ProjectReference)">
      <Output TaskParameter="TargetOutputs" PropertyName="_projectReferenceBuildConfigurations" />
    </MSBuild>

    <PropertyGroup>
      <!--
        When building in VS or using the solution file Configuration for some projects is set to Debug/Release
        in such cases we should treat it as an empty configuration and set it to be $BuildConfiguration for the
        purposes of annotating project references.
      -->
      <Configuration Condition="'$(Configuration)' == 'Debug' or '$(Configuration)' == 'Release'">$(BuildConfiguration)</Configuration>
    </PropertyGroup>

    <!-- Find the best configuration for the current Project's Configuration -->
    <FindBestConfigurations Properties="@(Property)"
                            PropertyValues="@(PropertyValue)"
                            SupportedConfigurations="$(_ProjectReferenceBuildConfigurations)"
                            Configurations="$(Configuration)">
      <Output TaskParameter="BestConfigurations" PropertyName="_projectReferenceConfiguration" />
    </FindBestConfigurations>

    <Error Condition="'$(_projectReferenceConfiguration)' == ''" Text="Could not find a configuration for ProjectReference '@(ProjectReference)' from configurations '$(_projectReferenceBuildConfigurations)' when building '$(MSBuildProjectName)' for configuration '$(Configuration)' ." />

    <ItemGroup>
      <ProjectReference>
        <AdditionalProperties>Configuration=$(_projectReferenceConfiguration);%(ProjectReference.AdditionalProperties)</AdditionalProperties>
      </ProjectReference>

      <!-- Project references for non-test assemblies should never be copied to the output. -->
      <ProjectReference Condition="'$(IsTestProject)' != 'true'">
        <Private>false</Private>
      </ProjectReference>
    </ItemGroup>
  </Target>

  <Target Name="_getAllBuildConfigurations">
    <ItemGroup>
      <_buildConfigurations Include="$(BuildConfigurations)" />
      <!-- For BuildAllConfigurations we need to ignore any placeholder build configuration that starts with _ -->
      <_buildConfigurations Remove="@(_buildConfigurations)" Condition="$([System.String]::Copy('%(Identity)').StartsWith('_'))" />
      <_buildConfigurations Condition="'@(_buildConfigurations)' == ''" Include="$(_traversalBuildConfigurations)" />
    </ItemGroup>
  </Target>

  <Target Name="BuildAllConfigurations" DependsOnTargets="_getAllBuildConfigurations">
    <MSBuild Projects="$(MSBuildProjectFullPath)"
             Properties="Configuration=%(_buildConfigurations.Identity);BuildAllConfigurations=true" />
  </Target>
  <Target Name="BuildAll" DependsOnTargets="BuildAllConfigurations" />
  
  <Target Name="RebuildAllConfigurations" DependsOnTargets="_getAllBuildConfigurations">
    <MSBuild Projects="$(MSBuildProjectFullPath)"
             Targets="Rebuild"
             Properties="Configuration=%(_buildConfigurations.Identity);BuildAllConfigurations=true" />
  </Target>
  <Target Name="RebuildAll" DependsOnTargets="RebuildAllConfigurations" />

  <Target Name="CleanAllConfigurations" DependsOnTargets="_getAllBuildConfigurations">
    <MSBuild Projects="$(MSBuildProjectFullPath)"
             Targets="Clean"
             Properties="Configuration=%(_buildConfigurations.Identity);BuildAllConfigurations=true" />
  </Target>
  <Target Name="CleanAll" DependsOnTargets="CleanAllConfigurations" />
  
</Project>