// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Windows.Win32.System.Com;

/// <summary>
///  An interface that provides a COM callable wrapper for the implementing class. The implementing class should not
///  be public and unsealed as it can be derived from and COM interfaces can be added. This is meant to be a fixed
///  set of interfaces.
/// </summary>
/// <remarks>
///  <para>
///   NET CCWs generated by built-in COM interop always support IMarshal, ISupportErrorInfo, IDispatchEx,
///   IProvideClassInfo, and IConnectionPointContainer. They also usually expose IAgileObject. On Exception objects
///   the CCW also supports IErrorInfo. These must explicitly be provided with this mechanism.
///  </para>
///  <para>
///   .NET Framework also supported the following interfaces, which are not implemented on .NET Core:
///  </para>
///  <list type="bullet">
///   <item><description>IManagedObject          - used .NET Remoting (not available on .NET Core)</description></item>
///   <item><description>IObjectSafety           - for Code Access Security (not available on .NET Core)</description></item>
///   <item><description>IWeakReferenceSource    - for WinRT</description></item>
///   <item><description>ICustomPropertyProvider - for WinRT XAML (Jupiter)</description></item>
///   <item><description>IReferenceTrackerTarget - for WinRT</description></item>
///   <item><description>IStringable             - for WinRT</description></item>
///  </list>
/// </remarks>
internal unsafe interface IManagedWrapper
{
    ComInterfaceTable GetComInterfaceTable();
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given <typeparamref name="TComInterface"/>. The class
///  must also derive from the given COM wrapper <see langword="struct"/>'s nested Interface.
/// </summary>
internal unsafe interface IManagedWrapper<TComInterface> : IManagedWrapper
    where TComInterface : unmanaged, IVTable, IComIID
{
    private static ComInterfaceTable InterfaceTable { get; set; } = ComInterfaceTable.Create<TComInterface>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given <typeparamref name="TComInterface1"/> and
///  <typeparamref name="TComInterface2"/>. The class must also derive from both of the given COM wrapper
///  <see langword="struct"/>'s nested Interface.
/// </summary>
internal unsafe interface IManagedWrapper<TComInterface1, TComInterface2> : IManagedWrapper
    where TComInterface1 : unmanaged, IVTable, IComIID
    where TComInterface2 : unmanaged, IVTable, IComIID
{
    private static ComInterfaceTable InterfaceTable { get; set; } = ComInterfaceTable.Create<TComInterface1, TComInterface2>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given interfaces. The class must also derive from the
///  given COM wrapper structs' nested Interfaces.
/// </summary>
internal interface IManagedWrapper<TComInterface1, TComInterface2, TComInterface3> : IManagedWrapper
    where TComInterface1 : unmanaged, IComIID, IVTable
    where TComInterface2 : unmanaged, IComIID, IVTable
    where TComInterface3 : unmanaged, IComIID, IVTable
{
    private static ComInterfaceTable InterfaceTable { get; }
        = ComInterfaceTable.Create<TComInterface1, TComInterface2, TComInterface3>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given interfaces. The class must also derive from the
///  given COM wrapper structs' nested Interfaces.
/// </summary>
internal interface IManagedWrapper<TComInterface1, TComInterface2, TComInterface3, TComInterface4> : IManagedWrapper
    where TComInterface1 : unmanaged, IComIID, IVTable
    where TComInterface2 : unmanaged, IComIID, IVTable
    where TComInterface3 : unmanaged, IComIID, IVTable
    where TComInterface4 : unmanaged, IComIID, IVTable
{
    private static ComInterfaceTable InterfaceTable { get; }
        = ComInterfaceTable.Create<TComInterface1, TComInterface2, TComInterface3, TComInterface4>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given interfaces. The class must also derive from the
///  given COM wrapper structs' nested Interfaces.
/// </summary>
internal interface IManagedWrapper<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5> : IManagedWrapper
    where TComInterface1 : unmanaged, IComIID, IVTable
    where TComInterface2 : unmanaged, IComIID, IVTable
    where TComInterface3 : unmanaged, IComIID, IVTable
    where TComInterface4 : unmanaged, IComIID, IVTable
    where TComInterface5 : unmanaged, IComIID, IVTable
{
    private static ComInterfaceTable InterfaceTable { get; }
        = ComInterfaceTable.Create<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given interfaces. The class must also derive from the
///  given COM wrapper structs' nested Interfaces.
/// </summary>
internal interface IManagedWrapper<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5, TComInterface6> : IManagedWrapper
    where TComInterface1 : unmanaged, IComIID, IVTable
    where TComInterface2 : unmanaged, IComIID, IVTable
    where TComInterface3 : unmanaged, IComIID, IVTable
    where TComInterface4 : unmanaged, IComIID, IVTable
    where TComInterface5 : unmanaged, IComIID, IVTable
    where TComInterface6 : unmanaged, IComIID, IVTable
{
    private static ComInterfaceTable InterfaceTable { get; }
        = ComInterfaceTable.Create<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5, TComInterface6>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given interfaces. The class must also derive from the
///  given COM wrapper structs' nested Interfaces.
/// </summary>
internal interface IManagedWrapper<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5, TComInterface6, TComInterface7, TComInterface8, TComInterface9, TComInterface10> : IManagedWrapper
    where TComInterface1 : unmanaged, IComIID, IVTable
    where TComInterface2 : unmanaged, IComIID, IVTable
    where TComInterface3 : unmanaged, IComIID, IVTable
    where TComInterface4 : unmanaged, IComIID, IVTable
    where TComInterface5 : unmanaged, IComIID, IVTable
    where TComInterface6 : unmanaged, IComIID, IVTable
    where TComInterface7 : unmanaged, IComIID, IVTable
    where TComInterface8 : unmanaged, IComIID, IVTable
    where TComInterface9 : unmanaged, IComIID, IVTable
    where TComInterface10 : unmanaged, IComIID, IVTable
{
    private static ComInterfaceTable InterfaceTable { get; }
        = ComInterfaceTable.Create<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5, TComInterface6, TComInterface7, TComInterface8, TComInterface9, TComInterface10>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}

/// <summary>
///  Apply to a class to apply a COM callable wrapper of the given interfaces. The class must also derive from the
///  given COM wrapper structs' nested Interfaces.
/// </summary>
internal interface IManagedWrapper<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5, TComInterface6, TComInterface7, TComInterface8, TComInterface9, TComInterface10,
    TComInterface11, TComInterface12, TComInterface13, TComInterface14, TComInterface15, TComInterface16, TComInterface17, TComInterface18, TComInterface19, TComInterface20,
    TComInterface21, TComInterface22, TComInterface23, TComInterface24, TComInterface25, TComInterface26, TComInterface27> : IManagedWrapper
    where TComInterface1 : unmanaged, IComIID, IVTable
    where TComInterface2 : unmanaged, IComIID, IVTable
    where TComInterface3 : unmanaged, IComIID, IVTable
    where TComInterface4 : unmanaged, IComIID, IVTable
    where TComInterface5 : unmanaged, IComIID, IVTable
    where TComInterface6 : unmanaged, IComIID, IVTable
    where TComInterface7 : unmanaged, IComIID, IVTable
    where TComInterface8 : unmanaged, IComIID, IVTable
    where TComInterface9 : unmanaged, IComIID, IVTable
    where TComInterface10 : unmanaged, IComIID, IVTable
    where TComInterface11 : unmanaged, IComIID, IVTable
    where TComInterface12 : unmanaged, IComIID, IVTable
    where TComInterface13 : unmanaged, IComIID, IVTable
    where TComInterface14 : unmanaged, IComIID, IVTable
    where TComInterface15 : unmanaged, IComIID, IVTable
    where TComInterface16 : unmanaged, IComIID, IVTable
    where TComInterface17 : unmanaged, IComIID, IVTable
    where TComInterface18 : unmanaged, IComIID, IVTable
    where TComInterface19 : unmanaged, IComIID, IVTable
    where TComInterface20 : unmanaged, IComIID, IVTable
    where TComInterface21 : unmanaged, IComIID, IVTable
    where TComInterface22 : unmanaged, IComIID, IVTable
    where TComInterface23 : unmanaged, IComIID, IVTable
    where TComInterface24 : unmanaged, IComIID, IVTable
    where TComInterface25 : unmanaged, IComIID, IVTable
    where TComInterface26 : unmanaged, IComIID, IVTable
    where TComInterface27 : unmanaged, IComIID, IVTable
{
    private static ComInterfaceTable InterfaceTable { get; }
        = ComInterfaceTable.Create<TComInterface1, TComInterface2, TComInterface3, TComInterface4, TComInterface5, TComInterface6, TComInterface7, TComInterface8, TComInterface9, TComInterface10,
            TComInterface11, TComInterface12, TComInterface13, TComInterface14, TComInterface15, TComInterface16, TComInterface17, TComInterface18, TComInterface19, TComInterface20,
            TComInterface21, TComInterface22, TComInterface23, TComInterface24, TComInterface25, TComInterface26, TComInterface27>();

    ComInterfaceTable IManagedWrapper.GetComInterfaceTable() => InterfaceTable;
}
