// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import "Windows.Foundation.idl";
import "dualapipartitionattribute.idl";

#include <sdkddkver.h>

#ifdef BUILD_INBOX
import "Windows.AI.MachineLearning.idl";
#define ROOT_NS Windows
#define INBOX_ONLY(x) x
#define OTB_ONLY(x)
#else
import "Microsoft.AI.MachineLearning.idl";
#define INBOX_ONLY(x)
#define OTB_ONLY(x) x
#endif

#ifndef ROOT_NS
#define ROOT_NS Microsoft
#endif

namespace ROOT_NS.AI.MachineLearning.Experimental {
  runtimeclass LearningModelBuilder;

  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelSessionOptionsExperimental {
    LearningModelSessionOptionsExperimental(ROOT_NS.AI.MachineLearning.LearningModelSessionOptions options);

    //! The GetNamedDimensionOverrides method retrieves the named dimension overrides configured on the session options.
    Windows.Foundation.Collections.IMapView<String, UINT32> GetNamedDimensionOverrides();

    //! The RegisterCustomOpsLibrary method registers an onnxruntime custom operator library into session creation.
    void RegisterCustomOpsLibrary(String path);
  }

  [threading(both)]
  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelSessionExperimental {
    LearningModelSessionExperimental(ROOT_NS.AI.MachineLearning.LearningModelSession session);
    LearningModelSessionOptionsExperimental Options { get; };
  }

  [threading(both)]
  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelOperator {
    LearningModelOperator(String type);
    LearningModelOperator(String type, String domain);

    LearningModelOperator SetName(String name);
    LearningModelOperator SetInput(String operator_input_name, String input_name);
    LearningModelOperator SetConstant(String operator_input_name, IInspectable default_value);
    LearningModelOperator SetOutput(String operator_output_name, String output_name);
    LearningModelOperator SetAttribute(String name, IInspectable value);

    String Name { get; };
    String Type { get; };
    String Domain { get; };
  }

  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelOperatorSet {
    LearningModelBuilder Add(LearningModelOperator op);
  }

  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelInputs {
    LearningModelBuilder Add(ROOT_NS.AI.MachineLearning.ILearningModelFeatureDescriptor input);
    LearningModelBuilder Add(String input_name, String input_description, IInspectable default_value);
    LearningModelBuilder AddConstant(String input_name, IInspectable value);
  }

  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelOutputs {
    LearningModelBuilder Add(ROOT_NS.AI.MachineLearning.ILearningModelFeatureDescriptor output);
  }

  //! \interface LearningModelBuilder
  //! \brief Represents a trained machine learning model.
  //! \details This is the main object you use to interact with Windows Machine Learning.  You use
  //! it to load, bind, and evaluate trained ONNX models.   To load the model you use
  //! one of the Load constructors.  You can then enumerate the InputFeatures and
  //! OutputFeatures.   To bind and evaluate you create a LearningModelSession.
  [threading(both)]
  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelBuilder {
    LearningModelInputs Inputs { get; };
    LearningModelOutputs Outputs { get; };
    LearningModelOperatorSet Operators { get; };

    //! Create a builder.
    static LearningModelBuilder Create(Int32 opset);

    //! Creates a TensorFeatureDescriptor.. this should be a constructor on the TFD
    //TensorFeatureDescriptor(String name, String description, TensorKind kind, Int64[] shape);
    static ROOT_NS.AI.MachineLearning.TensorFeatureDescriptor CreateTensorFeatureDescriptor(String name, String description, ROOT_NS.AI.MachineLearning.TensorKind kind, Int64[] shape);
    static ROOT_NS.AI.MachineLearning.TensorFeatureDescriptor CreateTensorFeatureDescriptor(String name, ROOT_NS.AI.MachineLearning.TensorKind kind, Int64[] shape);

    ROOT_NS.AI.MachineLearning.LearningModel CreateModel();

    void Save(String file_name);
  }

  //! \class LearningModelJoinOptions
  //! \brief This class defines Join Options to be used with the JoinModels method
  [dualapipartition(1)]
  runtimeclass LearningModelJoinOptions
  {
      // default constructor
      LearningModelJoinOptions();

      //! The PromoteUnlinkedOutputsToFusedOutputs option allows callers to toggle whether unlinked outputs of the first model,
      //! remain as outputs in the fused model.
      //! The default value for PromoteUnlinkedOutputsToFusedOutputs is true.
      Boolean PromoteUnlinkedOutputsToFusedOutputs{ get; set; };

      //! The CloseModelOnJoin option allows callers to close the second model when the JoinModels method is made.
      //! By enabling this, the engine can reuse the second models protobuf memory rather than copy it.
      //! The default value for CloseModelOnJoin is false.
      Boolean CloseModelOnJoin { get; set; };

      //! The JoinedNodePrefix property specifies whether the nodes of the second model should have a specific prefixed in the joined model.
      //! Node names must be unique or empty. By enabling this, the engine can specify the prefix, or eliminate it entirely in cases
      //! where the model is known to contain no duplicate node names.
      //! The default value for CloseModelOnJoin is a new random GUID.
      String JoinedNodePrefix { get; set; };

      //! The Link method joins outputs from the first model to inputs of the second model.
      void Link(String firstModelOutput, String secondModelInput);
  }

  [marshaling_behavior(agile)]
  [dualapipartition(1)]
  runtimeclass LearningModelExperimental {
    LearningModelExperimental(ROOT_NS.AI.MachineLearning.LearningModel model);

    //! The Save method serializes the model as an ONNX model to a specified path.
    void Save(String file_name);

    //! The JoinModel fuses two models by linking outputs from the first model, to inupts of the second.
    ROOT_NS.AI.MachineLearning.LearningModel JoinModel(ROOT_NS.AI.MachineLearning.LearningModel other, LearningModelJoinOptions options);

    //! The SetName function changes the model name to the specified string
    void SetName(String model_name);
  }

}  // namespace Microsoft.AI.MachineLearning.Experimental
