syntax = "proto3";

package gosdn.networkelement;

import "google/api/annotations.proto";
import "google/protobuf/descriptor.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "github.com/openconfig/gnmi/proto/gnmi/gnmi.proto";

import "gosdn/conflict/conflict.proto";
import "gosdn/transport/transport.proto";
import "gosdn/southbound/southbound.proto";
import "gosdn/pnd/pnd.proto";

option go_package = "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement";

service NetworkElementService {
    rpc Add(AddNetworkElementRequest) returns (AddNetworkElementResponse) {
        option (google.api.http) = {
            post: "/network-element/create"
            body: "*"
        };
    }

    rpc Get(GetNetworkElementRequest) returns (GetNetworkElementResponse) {
        option (google.api.http) = {
            get: "/network-element"
        };
    }

    rpc GetAll(GetAllNetworkElementRequest) returns (GetAllNetworkElementResponse) {
        option (google.api.http) = {
            get: "/network-element/all"
        };
    }

    rpc Update(UpdateNetworkElementRequest) returns (UpdateNetworkElementResponse) {
        option (google.api.http) = {
            post: "/network-element/update"
            body: "*"
        };
    }

    // TODO: not implemented yet!
    // rpc Delete(DeleteNetworkElementRequest) returns (DeleteNetworkElementRequest) {
    //     option (google.api.http) = {
    //         delete: "/network-element"
    //     };
    // }

  // Allows to request all Managed Network Elements (MNE) which are
  // managed by a specific Principal Network Domain.
  // Full MNEs are provided, which also includes the MNE config as gNMI
  // notification.
  rpc GetMneList(GetMneListRequest) returns (GetMneListResponse);

  // Allows to request all Managed Network Elements (MNE) which are
  // managed by a specific Principal Network Domain.
  // Flattened MNEs are provided, which does not include the MNE config as gNMI
  // notification.
  rpc GetFlattenedMneList(GetFlattenedMneListRequest) returns (GetFlattenedMneListResponse) {
    option (google.api.http) = {
      get: "/pnds/{pid}/mnes"
    };
  }
  // Allows to request a specific Managed Network Element which is managed by a
  // specific Principal Network Domain.
  rpc GetMne(GetMneRequest) returns (GetMneResponse) {
    option (google.api.http) = {
      get: "/pnds/{pid}/mne/{mneid}"
    };
  }
  // TODO: add own getrequest message and http option
  // Allows to request a specific Managed Network Element which is managed by a
  // specific Principal Network Domain. A flattened version of a Managed
  // Network Element is provided.
  rpc GetFlattenedMne(GetMneRequest) returns (GetFlattenedMneResponse);
  // Allows to add multiple Managed Network Elements to be managed by a
  // specific Principal Network Domain.
  rpc SetMneList(SetMneListRequest) returns (SetMneListResponse) {
    option (google.api.http) = {
      post: "/pnds/{pid}/mnes"
      body: "*"
    };
  }
  // Allows to request a specific Path of a Managed Network Element
  // managed by a specific Principal Network Domain.
  // Note: This returns the actual state of the network element.
  // For the inteded state call "GetIntendedPath" instead.
  rpc GetPath(GetPathRequest) returns (GetPathResponse) {
    option (google.api.http) = {
      get: "/pnds/{pid}/mnes/{mneid}/paths/{path}"
    };
  }
  // Allows to request a specific intended Path of a Managed Network Element
  // managed by a specific Principal Network Domain.
  // Note: This returns the state how it is stored the storage.
  // For the actual state of the network element call "GetPath" instead.
  rpc GetIntendedPath(GetIntendedPathRequest) returns (GetIntendedPathResponse) {
      option (google.api.http) = {
          get: "/pnds/{pid}/mnes/{mneid}/intendedpaths/{intended_path}"
      };
  }
  // Allows to set a specific Path of a Managed Network Element,
  // managed by a specific Principal Network Domain.
  rpc SetPathList(SetPathListRequest) returns (SetPathListResponse) {
    option (google.api.http) = {
      post: "/pnds/{pid}/mnes/paths"
      body: "*"
    };
  }
  // Allows to delete a specific Managed Network Element which is managed by a
  // specific Principal Network Domain.
  rpc DeleteMne(DeleteMneRequest) returns (DeleteMneResponse) {
    option (google.api.http) = {
      delete: "/pnds/{pid}/mnes/{mneid}"
    };
  }
   // Allows to request all Changes registered for a specific Principal Network Domain.
   rpc GetChangeList(GetChangeListRequest) returns (GetChangeListResponse) {
    option (google.api.http) = {
      get: "/pnds/{pid}/changes"
    };
  }
  // Allows to request a specific Change registered for a specific Principal Network Domain.
  rpc GetChange(GetChangeRequest) returns (GetChangeResponse) {
    option (google.api.http) = {
      get: "/pnds/{pid}/changes/{cuid}"
    };
  }
  // Allows to operate on multiple Changes registered for a specific Principal Network Domain.
  rpc SetChangeList(SetChangeListRequest) returns (SetChangeListResponse) {
    option (google.api.http) = {
      post: "/pnds/{pid}/changes"
      body: "*"
    };
  }
  // Allows to subscribe to multiple paths of a Managed Network Element which is
  // managed by a specific Principal Network Domain and streams data depending on the subscribe
  // method.
  rpc SubscribePath(SubscribePathRequest) returns (stream SubscribePathResponse) {};
}

enum Status {
    STATUS_UNSPECIFIED = 0;
    STATUS_OK = 1;
    STATUS_ERROR = 2;
}

message AddNetworkElementConfiguration {
    string address = 1;
    .gosdn.southbound.SouthboundInterface sbi = 2;
    string network_element_name = 3;
    .gosdn.transport.TransportOption transport_option = 4;
}

message AddNetworkElementRequest {
    int64 timestamp = 1;
    AddNetworkElementConfiguration network_element = 2;
    string pid = 3;
}

message AddNetworkElementResponse {
    int64 timestamp = 1;
    Status status = 2;
    string network_element_id = 3;
}

message GetNetworkElementRequest {
    int64 timestamp = 1;
    string network_element_id = 2;
}

message GetNetworkElementResponse {
    int64 timestamp = 1;
    Status status = 2;
    ManagedNetworkElement network_element = 3;
}

message GetAllNetworkElementRequest {
    int64 timestamp = 1;
}

message GetAllNetworkElementResponse {
    int64 timestamp = 1;
    Status status = 2;
    repeated ManagedNetworkElement network_element = 3;
}

message UpdateNetworkElementRequest {
    int64 timestamp = 1;
    ManagedNetworkElement network_element = 2;
}

message UpdateNetworkElementResponse {
    int64 timestamp = 1;
    Status status = 2;
}

message DeleteNetworkElementRequest {
    int64 timestamp = 1;
    string network_element_id = 2;
}

message DeleteNetworkElementResponse {
    int64 timestamp = 1;
    Status status = 2;
}

message ManagedNetworkElement {
    string id = 1;
    string name = 2;
    string model = 3;
    repeated gnmi.Notification mne_notification = 4;
    string transport_address = 5;
    .gosdn.transport.TransportOption transport_option = 6;
    conflict.Metadata metadata = 7;
    string associated_pnd = 8;
 }

message FlattenedManagedNetworkElement {
    string id = 1;
    string name = 2;
    string pid = 3;
    string pluginid = 4;
}

message GetMneListRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string pid = 2;
}

message GetMneListResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    // TODO: Check if this is really needed. Perhaps a reference to the PND's ID
    // is also sufficient.
    pnd.PrincipalNetworkDomain pnd = 2;
    repeated ManagedNetworkElement mne = 3;
}

message GetFlattenedMneListRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string pid = 2;
}

message GetFlattenedMneListResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    // TODO: Check if this is really needed. Perhaps a reference to the PND's ID
    // is also sufficient.
    pnd.PrincipalNetworkDomain pnd = 2;
    repeated FlattenedManagedNetworkElement mne = 3;
}

message GetMneRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string mneid = 2;
    string pid = 3;
}

message GetMneResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    // TODO: Check if this is really needed. Perhaps a reference to the PND's ID
    // is also sufficient.
    pnd.PrincipalNetworkDomain pnd = 2;
    ManagedNetworkElement mne = 3;
}
message GetFlattenedMneResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    // TODO: Check if this is really needed. Perhaps a reference to the PND's ID
    // is also sufficient.
    pnd.PrincipalNetworkDomain pnd = 2;
    FlattenedManagedNetworkElement mne = 3;
  }
message SetMne {
    string address = 1;
    string pid = 2;
    string pluginId = 3;
    string mne_name = 4;
    .gosdn.transport.TransportOption transport_option = 5;
}

message SetMneListRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    repeated SetMne mne = 2;
    string pid = 3;
}

message SetMneListResponse{
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    Status status = 2;
    repeated SetResponse responses = 3;
}

message GetPathRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string mneid = 2;
    string path = 3;
    string pid = 4;
}

message GetPathResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    // TODO: Check if this is really needed. Perhaps a reference to the PND's ID
    // is also sufficient.
    pnd.PrincipalNetworkDomain pnd = 2;
    repeated gnmi.Notification mne_notification = 3;
}

message GetIntendedPathRequest {
    int64 timestamp = 1;
    string mneid = 2;
    string intended_path = 3;
    string pid = 4;
}

message GetIntendedPathResponse {
    int64 timestamp = 64;
    pnd.PrincipalNetworkDomain pnd = 2;
    repeated gnmi.Notification mne_notification = 3;
}

message SetResponse{
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string id = 2;
    Status status = 3;
}

message SetPathListRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    repeated ChangeRequest change_request = 2;
    string pid = 3;
}

message SetPathListResponse{
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    Status status = 2;
    repeated SetResponse responses = 3;
}

message DeleteMneRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string pid = 2;
    string mneid = 3;
}

message DeleteMneResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    Status status = 2;
}

enum ChangeState {
    CHANGE_STATE_UNSPECIFIED = 0;
    CHANGE_STATE_PENDING = 1;
    CHANGE_STATE_COMMITTED = 2;
    CHANGE_STATE_CONFIRMED = 3;
    CHANGE_STATE_INCONSISTENT = 4;
}

message Change {
    string id = 1;
    int64 age = 2;
    ChangeState state = 3;
    gnmi.Notification diff = 4;
}

message ChangeRequest {
    string mneid = 1;
    gnmi.Path path = 2;
    gnmi.TypedValue value = 3;
    ApiOperation api_op = 4;
}

enum ApiOperation {
    API_OPERATION_UNSPECIFIED = 0;
    API_OPERATION_UPDATE = 1;
    API_OPERATION_REPLACE = 2;
    API_OPERATION_DELETE = 3;
}

enum Operation {
    OPERATION_UNSPECIFIED = 0;
    OPERATION_CREATE = 1;
    OPERATION_COMMIT = 2;
    OPERATION_CONFIRM = 3;
}

message SetChange {
    string cuid = 1;
    Operation op = 2;
}

message GetChangeListRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string pid = 2;
}

message GetChangeListResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    // TODO: Check if this is really needed. Perhaps a reference to the PND's ID
    // is also sufficient.
    pnd.PrincipalNetworkDomain pnd = 2;
    repeated Change change = 3;
}

message GetChangeRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    repeated string cuid = 2;
    string pid = 3;
}

message GetChangeResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    // TODO: Check if this is really needed. Perhaps a reference to the PND's ID
    // is also sufficient.
    pnd.PrincipalNetworkDomain pnd = 2;
    repeated Change change = 3;
}

message SetChangeListRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    repeated SetChange change = 2;
    string pid = 3;
}

message SetChangeListResponse{
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    Status status = 2;
    repeated SetResponse responses = 3;
}

// The mode determines how the target should trigger updates to be sent.
// Reference: gNMI Specification Section 3.5.1.2
message SubscriptionList {
    repeated Subscription subscription = 1;
    SubscriptionMode mode = 2;
}

enum SubscriptionMode {
    SUBSCRIPTION_MODE_UNSPECIFIED = 0;
    SUBSCRIPTION_MODE_ONCE = 1;
    SUBSCRIPTION_MODE_STREAM = 2;
    SUBSCRIPTION_MODE_POLL = 3;
}

message Subscription {
    string path = 1;
    StreamMode stream_mode = 2;
    uint64 sample_interval = 3;       // time in ns between samples in SAMPLE mode.
}

enum StreamMode {
    STREAM_MODE_UNSPECIFIED = 0;
    STREAM_MODE_TARGET_DEFINED = 1;  // The target selects the relevant mode for each element.
    STREAM_MODE_ON_CHANGE      = 2;  // The target sends an update on element value change.
    STREAM_MODE_SAMPLE         = 3; // The target samples values according to the interval.
}

message SubscribePathRequest {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    string mneid = 2;
    string pid = 3;
    SubscriptionList sublist = 4;
}

message SubscribePathResponse {
    int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
    Status status = 2;
    repeated gnmi.Notification mne_notification = 3;
}
