{{$name := .Metadata.Name -}}
// Client for UPnP Device Control Protocol {{.Metadata.OfficialName}}.
// {{if .DocURLs}}
// This DCP is documented in detail at: {{range .DocURLs}}
// - {{.}}{{end}}{{end}}
//
// Typically, use one of the New* functions to create clients for services.
package {{$name | base}}

// ***********************************************************
// GENERATED FILE - DO NOT EDIT BY HAND. See README.md
// ***********************************************************

import (
	"context"
	"net/url"
	"time"

	"git.cyrilix.bzh/cyrilix/goupnp"
	"git.cyrilix.bzh/cyrilix/goupnp/soap"
)

// Hack to avoid Go complaining if time isn't used.
var _ time.Time

// Device URNs:
const ({{range .OrderedDeviceTypes}}
	{{.Const}} = "{{.URN}}"{{end}}
)

// Service URNs:
const ({{range .OrderedServiceTypes}}
	{{.Const}} = "{{.URN}}"{{end}}
)

{{range .OrderedServices}}
{{$srv := .}}
{{$srvIdent := printf "%s%s" .Name .Version}}

// {{$srvIdent}} is a client for UPnP SOAP service with URN "{{.URN}}". See
// goupnp.ServiceClient, which contains RootDevice and Service attributes which
// are provided for informational value.
type {{$srvIdent}} struct {
	goupnp.ServiceClient
}

// New{{$srvIdent}}ClientsCtx discovers instances of the service on the network,
// and returns clients to any that are found. errors will contain an error for
// any devices that replied but which could not be queried, and err will be set
// if the discovery process failed outright.
//
// This is a typical entry calling point into this package.
func New{{$srvIdent}}ClientsCtx(ctx context.Context) (clients []*{{$srvIdent}}, errors []error, err error) {
	var genericClients []goupnp.ServiceClient
	if genericClients, errors, err = goupnp.NewServiceClientsCtx(ctx, {{$srv.Const}}); err != nil {
		return
	}
	clients = new{{$srvIdent}}ClientsFromGenericClients(genericClients)
	return
}

// New{{$srvIdent}}Clients is the legacy version of New{{$srvIdent}}ClientsCtx, but uses
// context.Background() as the context.
func New{{$srvIdent}}Clients() (clients []*{{$srvIdent}}, errors []error, err error) {
	return New{{$srvIdent}}ClientsCtx(context.Background())
}

// New{{$srvIdent}}ClientsByURLCtx discovers instances of the service at the given
// URL, and returns clients to any that are found. An error is returned if
// there was an error probing the service.
//
// This is a typical entry calling point into this package when reusing an
// previously discovered service URL.
func New{{$srvIdent}}ClientsByURLCtx(ctx context.Context, loc *url.URL) ([]*{{$srvIdent}}, error) {
	genericClients, err := goupnp.NewServiceClientsByURLCtx(ctx, loc, {{$srv.Const}})
	if err != nil {
		return nil, err
	}
	return new{{$srvIdent}}ClientsFromGenericClients(genericClients), nil
}

// New{{$srvIdent}}ClientsByURL is the legacy version of New{{$srvIdent}}ClientsByURLCtx, but uses
// context.Background() as the context.
func New{{$srvIdent}}ClientsByURL(loc *url.URL) ([]*{{$srvIdent}}, error) {
	return New{{$srvIdent}}ClientsByURLCtx(context.Background(), loc)
}

// New{{$srvIdent}}ClientsFromRootDevice discovers instances of the service in
// a given root device, and returns clients to any that are found. An error is
// returned if there was not at least one instance of the service within the
// device. The location parameter is simply assigned to the Location attribute
// of the wrapped ServiceClient(s).
//
// This is a typical entry calling point into this package when reusing an
// previously discovered root device.
func New{{$srvIdent}}ClientsFromRootDevice(rootDevice *goupnp.RootDevice, loc *url.URL) ([]*{{$srvIdent}}, error) {
	genericClients, err := goupnp.NewServiceClientsFromRootDevice(rootDevice, loc, {{$srv.Const}})
	if err != nil {
		return nil, err
	}
	return new{{$srvIdent}}ClientsFromGenericClients(genericClients), nil
}

func new{{$srvIdent}}ClientsFromGenericClients(genericClients []goupnp.ServiceClient) []*{{$srvIdent}} {
	clients := make([]*{{$srvIdent}}, len(genericClients))
	for i := range genericClients {
		clients[i] = &{{$srvIdent}}{genericClients[i]}
	}
	return clients
}

{{range .SCPD.OrderedActions}}{{/* loops over *SCPDWithURN values */}}

{{$winargs := $srv.WrapArguments .InputArguments}}
{{$woutargs := $srv.WrapArguments .OutputArguments}}
{{if $winargs.HasDoc}}
//
// Arguments:{{range $winargs}}{{if .HasDoc}}
//
// * {{.Name}}: {{.Document}}{{end}}{{end}}{{end}}
{{if $woutargs.HasDoc}}
//
// Return values:{{range $woutargs}}{{if .HasDoc}}
//
// * {{.Name}}: {{.Document}}{{end}}{{end}}{{end}}
func (client *{{$srvIdent}}) {{.Name}}Ctx(
	ctx context.Context,
{{range $winargs }}	{{.AsParameter}},
{{end -}}
) ({{range $woutargs -}}
{{.AsParameter}}, {{end}} err error) {
	// Request structure.
	request := {{if $winargs}}&{{template "argstruct" $winargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}}
	// BEGIN Marshal arguments into request.
{{range $winargs}}
	if request.{{.Name}}, err = {{.MarshalV1}}; err != nil {
		return
	}{{end}}
	// END Marshal arguments into request.

	// Response structure.
	response := {{if $woutargs}}&{{template "argstruct" $woutargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}}

	// Perform the SOAP call.
	if err = client.SOAPClient.PerformActionCtx(ctx, {{$srv.URNParts.Const}}, "{{.Name}}", request, response); err != nil {
		return
	}

	// BEGIN Unmarshal arguments from response.
{{range $woutargs}}
	if {{.Name}}, err = {{.UnmarshalV1 "response"}}; err != nil {
		return
	}{{end}}
	// END Unmarshal arguments from response.
	return
}

// {{.Name}} is the legacy version of {{.Name}}Ctx, but uses
// context.Background() as the context.
func (client *{{$srvIdent}}) {{.Name}}({{range $winargs -}}
	{{.AsParameter}}, {{end -}}
	) ({{range $woutargs -}}
	{{.AsParameter}}, {{end}} err error) {
	return client.{{.Name}}Ctx(context.Background(),
	{{range $winargs }}{{.Name}},
	{{end}}
	)
}

{{end}}
{{end}}

{{define "argstruct"}}struct {{"{"}}
{{range .}}{{.Name}} string
{{end}}{{"}"}}{{end}}