<Project>
<!--
    MSBuild script for automating codegen of Lottie animations and inclusion of the results into an app build.

    Usage:
        1. Include this targets file in your project:

            <Import Project="path/to/LottieGen.Cpp.targets"

        2. Add an ItemGroup to your project with elements like this:

            <LottieAnimation Include="path/to/myAnimation.json" Name="Id to use in JS" />

        The name field is optional and will default to the filename.

        3. In your native React Native Windows setup code, register the native animation provider:

            PackageProviders().Append(winrt::LottieReactNative::ReactPackageProvider(winrt::AnimatedVisuals::LottieCodegenSourceProvider()));

        4. Install the LottieGen.MsBuild nuget package into the app project

-->
    <PropertyGroup>
        <!-- Enable to support codegen of LottieAnimation json files. Required for use on cppwinrt. -->
        <EnableLottieCodegen Condition="'$(EnableLottieCodegen)' == ''">true</EnableLottieCodegen>
        
        <!-- Enable if you want to use LottieVisualSource for dynamic JSON loading. Disable to remove the dependency. -->  
        <LottieGenGenerateColorBindings Condition="'$(LottieGenGenerateColorBindings)' == ''"></LottieGenGenerateColorBindings>

        <LottieOutputFolder Condition="'$(LottieOutputFolder)' == ''">$(IntDir)Generated Files\Animations\</LottieOutputFolder>
        <LottieOutputFolder>$([MSBuild]::NormalizeDirectory('$(LottieOutputFolder)'))</LottieOutputFolder>
        <LottieGenWinUIVersion Condition="'$(LottieGenWinUIVersion)' == ''">2.4</LottieGenWinUIVersion>
        <LottieMinimumUapVersion Condition="'$(LottieMinimumUapVersion)' == ''">0</LottieMinimumUapVersion>
        <LottieTargetUapVersion Condition="'$(LottieTargetUapVersion)' == ''">0</LottieTargetUapVersion>        
        <LottieAnimationNamespace>AnimatedVisuals</LottieAnimationNamespace>
        <LottieVerbosity Condition="'$(LottieVerbosity)' == ''">normal</LottieVerbosity>


        <_LottieProviderIdlFilePath>$(LottieOutputFolder)LottieCodegenSourceProvider.idl</_LottieProviderIdlFilePath>
        <_LottieProviderHeaderFilePath>$(LottieOutputFolder)LottieCodegenSourceProvider.h</_LottieProviderHeaderFilePath>
        <_LottieProviderCppFilePath>$(LottieOutputFolder)LottieCodegenSourceProvider.cpp</_LottieProviderCppFilePath>
    </PropertyGroup>

    <!-- Hook up our targets to run before any CppWinRT/MIDL processing happens -->
    <PropertyGroup>
        <BeforeMidlCompileTargets>LottieGen_IncludeBuiltFiles;$(BeforeMidlCompileTargets)</BeforeMidlCompileTargets>
    </PropertyGroup>

    <!-- 
        Add metadata to LottieAnimation items. The generated name needs to match what LottieGen outputs.
    
        This is a little goofy because we want to use Regex and we can't do that directly with Item Metadata.
        So instead, we use Target batching (via the %() Outputs attribute) with 1 item per run of the task, and use a Property to run the Regex. -->
    <Target Name="LottieGen_UpdateMetadata"
        Outputs="%(LottieAnimation.Identity)">

        <PropertyGroup>
            <_LottieAnimationIdentity>%(LottieAnimation.Identity)</_LottieAnimationIdentity>
            <_LottieAnimationGeneratedName>$([System.Text.RegularExpressions.Regex]::Replace(%(LottieAnimation.Filename), "^\d", "_$0" ).Replace("-", "_"))</_LottieAnimationGeneratedName>
            <_LottieAnimationName>$(_LottieAnimationGeneratedName)</_LottieAnimationName>
            <_LottieAnimationName Condition="'%(LottieAnimation.Name)' != ''">%(LottieAnimation.Name)</_LottieAnimationName>            
        </PropertyGroup>

        <ItemGroup>
            <LottieAnimation Condition="'%(LottieAnimation.Identity)' == '$(_LottieAnimationIdentity)'">
                <Name>$(_LottieAnimationName)</Name>
                <GeneratedName>$(_LottieAnimationGeneratedName)</GeneratedName>
                <GeneratedFileName>$(LottieAnimationNamespace).$(_LottieAnimationGeneratedName)</GeneratedFileName>
            </LottieAnimation>
        </ItemGroup>

        <Message Importance="$(LottieVerbosity)" Text="Processing metadata for %(LottieAnimation.Identity) -> %(LottieAnimation.Name)" />
    </Target>

    <Target Name="LottieGen_CreateOutputPath">        
        <Error Condition="$([System.IO.Path]::IsPathRooted('$(LottieOutputFolder)')) != 'true'" Text="The output folder for Lottie is not rooted: '$(LottieOutputFolder)'" />    
        <MakeDir Directories="$(LottieOutputFolder)" />
    </Target>

    <!-- 
        Create a provider component that maps names to native animation implementations. 
    
        We're not using incremental build here because changes to item metadata (like the Name attribute) wouldn't trigger rebuild.
        Instead, we can use WriteOnlyWhenDifferent to avoid changing the output file if our code is the same.
    -->
    <Target Name="LottieGen_CreateProvider" 
        DependsOnTargets="LottieGen_CreateOutputPath;LottieGen_UpdateMetadata"
        Outputs="$(_LottieProviderIdlFilePath);$(_LottieProviderHeaderFilePath);$(_LottieProviderCppFilePath)">
        <PropertyGroup>
            <_LottieProviderIdlContent>
<![CDATA[
namespace $(LottieAnimationNamespace)
{
    runtimeclass LottieCodegenSourceProvider : [default]LottieReactNative.ILottieSourceProvider
    {
        LottieCodegenSourceProvider()%3B
    }
}
]]>
            </_LottieProviderIdlContent>
            <_LottieProviderHeaderContent>
<![CDATA[
#pragma once
#include "$(LottieAnimationNamespace).LottieCodegenSourceProvider.g.h"

namespace winrt::$(LottieAnimationNamespace)::implementation
{
    struct LottieCodegenSourceProvider : LottieCodegenSourceProviderT<LottieCodegenSourceProvider>
    {
        LottieCodegenSourceProvider() = default%3B

        winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::UI::Xaml::Controls::IAnimatedVisualSource> GetSourceFromName(winrt::hstring name)%3B
        winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::UI::Xaml::Controls::IAnimatedVisualSource> GetSourceFromJson(winrt::hstring json)%3B
    }%3B
}
namespace winrt::$(LottieAnimationNamespace)::factory_implementation
{
    struct LottieCodegenSourceProvider : LottieCodegenSourceProviderT<LottieCodegenSourceProvider, implementation::LottieCodegenSourceProvider> {}%3B
}
]]>
            </_LottieProviderHeaderContent>
            <_LottieProviderCppContent>
<![CDATA[
#include "pch.h"
#include "LottieCodegenSourceProvider.h"
#include "$(LottieAnimationNamespace).LottieCodegenSourceProvider.g.cpp"

namespace winrt::$(LottieAnimationNamespace)::implementation
{
    winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::UI::Xaml::Controls::IAnimatedVisualSource> LottieCodegenSourceProvider::GetSourceFromName(winrt::hstring name) {
        @(LottieAnimation->'
            if(name == L"%(Name)") {
                co_return winrt::$(LottieAnimationNamespace)::%(GeneratedName)()%3B
            }
        ')
        co_return nullptr%3B
    }
    winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::UI::Xaml::Controls::IAnimatedVisualSource> LottieCodegenSourceProvider::GetSourceFromJson(winrt::hstring json) {
        co_return nullptr%3B
    }
}
]]>
            </_LottieProviderCppContent>
        </PropertyGroup>

        <Message Importance="$(LottieVerbosity)" Text="Creating Lottie React Native provider" />
        <WriteLinesToFile
            File="$(_LottieProviderIdlFilePath)"
            Lines="$(_LottieProviderIdlContent)"
            Overwrite="true"
            WriteOnlyWhenDifferent="true" />

        <WriteLinesToFile
            File="$(_LottieProviderHeaderFilePath)"
            Lines="$(_LottieProviderHeaderContent)"
            Overwrite="true"
            WriteOnlyWhenDifferent="true" />

        <WriteLinesToFile
            File="$(_LottieProviderCppFilePath)"
            Lines="$(_LottieProviderCppContent)"
            Overwrite="true"
            WriteOnlyWhenDifferent="true" />
    </Target>

    <!--
        Runs LottieGen on JSON files to generate native animations.

        We use Target batching (via %() in Outputs) to run this target for each animation.
        We specify Inputs and Outputs to support incremental builds. Only changes to the input JSON timestamps will trigger rebuild.
    -->
    <Target Name="LottieGen_Build"
        Condition="'$(EnableLottieCodegen)' == 'true'"
        DependsOnTargets="LottieGen_CreateOutputPath;LottieGen_UpdateMetadata"
        Inputs="@(LottieAnimation)"
        Outputs="$(LottieOutputFolder)%(LottieAnimation.GeneratedFileName).idl">

        <Message Importance="$(LottieVerbosity)" Text="Generating Lottie animation files" />
        <Message Importance="$(LottieVerbosity)" Text="%(LottieAnimation.FullPath)" />
        <Message Importance="$(LottieVerbosity)" Text="$(LottieOutputFolder)" />

        <LottieGen.Task.LottieGen 
            Language="cppwinrt" 
            InputFile="%(LottieAnimation.FullPath)"
            OutputFolder="$(LottieOutputFolder)"
            Namespace="$(LottieAnimationNamespace)"
            MinimumUapVersion="$(LottieMinimumUapVersion)"
            TargetUapVersion="$(LottieTargetUapVersion)"
            AdditionalInterface="LottieReactNative.ILottieMediaSource"
            StandardOutputImportance="$(LottieVerbosity)"
            WinUIVersion="$(LottieGenWinUIVersion)"
            GenerateColorBindings="$(LottieGenGenerateColorBindings)"
        >
            <Output TaskParameter="OutputFiles" ItemName="LotteGenFiles" />
        </LottieGen.Task.LottieGen>
    </Target>

    <!-- 
        Add generated files to the build.
    -->
    <Target Name="LottieGen_IncludeBuiltFiles"
        Condition="'$(EnableLottieCodegen)' == 'true'"
        DependsOnTargets="LottieGen_Build;LottieGen_CreateProvider">
        <ItemGroup>
            <Midl Include="$(LottieOutputFolder)%(LottieAnimation.GeneratedFileName).idl" />
            <ClInclude Include="$(LottieOutputFolder)%(LottieAnimation.GeneratedFileName).h" />
            <ClCompile Include="$(LottieOutputFolder)%(LottieAnimation.GeneratedFileName).cpp" />            

            <Midl Include="$(_LottieProviderIdlFilePath)" />
            <ClInclude Include="$(_LottieProviderHeaderFilePath)" />
            <ClCompile Include="$(_LottieProviderCppFilePath)" />
        </ItemGroup>
    </Target>
</Project>