import ballerina/grpc;
import ballerina/io;
{{#stubObject}}
public type {{connectorId}}{{stubTypeName}}{{stubType}}Stub object {
    {{#stubs}}
    public grpc:Client clientEndpoint;
    public grpc:Stub stub;

    function initStub (grpc:Client ep) {
        grpc:Stub navStub = new;
        navStub.initStub(ep, "{{stubType}}", DESCRIPTOR_KEY, descriptorMap);
        self.stub = navStub;
    }
    {{/stubs}}{{#blockingFunctions}}
    function {{operationId}} ({{inputDataType}}{{&space}}{{inputAttributeName}}{{inputComma}}{{&space}}grpc:Headers? headers = ()) returns (({{outputDataType}}{{outputComma}} grpc:Headers)|error) {
        {{&initEmptyStub}}
        var unionResp = self.stub.blockingExecute("{{methodId}}", req, headers = headers);
        match unionResp {
            error payloadError => {
                return payloadError;
            }
            (any, grpc:Headers) payload => {
                any result;
                grpc:Headers resHeaders;
                ({{resultCast}}, resHeaders) = payload;
                return {{&openBracket}}{{&checkOp}}{{&castSymbolOpen}}{{outputDataType}}{{&castSymbolClose}}{{resultOut}}{{outputComma}}{{&space}}resHeaders{{&closeBracket}};
            }
        }
    }
    {{/blockingFunctions}}{{#nonBlockingFunctions}}
    function {{operationId}} ({{inputDataType}}{{&space}}{{inputAttributeName}}{{inputComma}}{{&space}}typedesc listener, grpc:Headers? headers = ()) returns (error?) {
        return self.stub.nonBlockingExecute("{{methodId}}", req, listener, headers = headers);
    }
    {{/nonBlockingFunctions}}{{#streamingFunctions}}
    function {{operationId}} (typedesc listener, grpc:Headers? headers = ()) returns (grpc:Client| error)  {
        var res = self.stub.streamingExecute("{{methodId}}", listener, headers = headers);
        match res {
            error err => {
                return err;
            }
            grpc:Client con => {
                return con;
            }
        }
    }
    {{/streamingFunctions}}
};
{{/stubObject}}
{{#client}}
public type {{connectorId}}{{stubTypeName}}{{stubType}}Client object {
    {{#stubObjects}}
    public grpc:Client client;
    public {{connectorId}}{{stubTypeName}}Stub stub;

    public function init (grpc:ClientEndpointConfig config) {
        // initialize client endpoint.
        grpc:Client c = new;
        c.init(config);
        self.client = c;
        // initialize service stub.
        {{connectorId}}{{stubTypeName}}Stub s = new;
        s.initStub(c);
        self.stub = s;
    }

    public function getCallerActions () returns ({{connectorId}}{{stubTypeName}}Stub) {
        return self.stub;
    }{{/stubObjects}}
};
{{/client}}
{{#structs}}
type {{structId}} record {
    {{#attribute}}{{type}}{{label}} {{name}};
    {{/attribute}}
};
{{/structs}}
{{#enums}}
enum {{enumId}} {
{{#enumAttribute}}{{name}}{{eoe}}
{{/enumAttribute}}
}
{{/enums}}
@final string DESCRIPTOR_KEY = "{{rootDescriptorKey}}";
map descriptorMap =
{ {{#descriptors}}
    "{{descriptorKey}}":"{{descriptorData}}"{{eoe}}
  {{/descriptors}}
};