// This file was auto-generated by the veyron vdl tool.
// Source: wire.vdl

package server

import (
	"veyron.io/veyron/veyron2/security"

	"veyron.io/veyron/veyron2/security/wire"

	// The non-user imports are prefixed with "_gen_" to prevent collisions.
	_gen_veyron2 "veyron.io/veyron/veyron2"
	_gen_context "veyron.io/veyron/veyron2/context"
	_gen_ipc "veyron.io/veyron/veyron2/ipc"
	_gen_naming "veyron.io/veyron/veyron2/naming"
	_gen_vdlutil "veyron.io/veyron/veyron2/vdl/vdlutil"
	_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)

// TODO(bprosnitz) Remove this line once signatures are updated to use typevals.
// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid

// Agent is the interface the client binds and uses.
// Agent_ExcludingUniversal is the interface without internal framework-added methods
// to enable embedding without method collisions.  Not to be used directly by clients.
type Agent_ExcludingUniversal interface {
	Sign(ctx _gen_context.T, message []byte, opts ..._gen_ipc.CallOpt) (reply security.Signature, err error)
	PublicKey(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply wire.PublicKey, err error)
}
type Agent interface {
	_gen_ipc.UniversalServiceMethods
	Agent_ExcludingUniversal
}

// AgentService is the interface the server implements.
type AgentService interface {
	Sign(context _gen_ipc.ServerContext, message []byte) (reply security.Signature, err error)
	PublicKey(context _gen_ipc.ServerContext) (reply wire.PublicKey, err error)
}

// BindAgent returns the client stub implementing the Agent
// interface.
//
// If no _gen_ipc.Client is specified, the default _gen_ipc.Client in the
// global Runtime is used.
func BindAgent(name string, opts ..._gen_ipc.BindOpt) (Agent, error) {
	var client _gen_ipc.Client
	switch len(opts) {
	case 0:
		// Do nothing.
	case 1:
		if clientOpt, ok := opts[0].(_gen_ipc.Client); opts[0] == nil || ok {
			client = clientOpt
		} else {
			return nil, _gen_vdlutil.ErrUnrecognizedOption
		}
	default:
		return nil, _gen_vdlutil.ErrTooManyOptionsToBind
	}
	stub := &clientStubAgent{defaultClient: client, name: name}

	return stub, nil
}

// NewServerAgent creates a new server stub.
//
// It takes a regular server implementing the AgentService
// interface, and returns a new server stub.
func NewServerAgent(server AgentService) interface{} {
	return &ServerStubAgent{
		service: server,
	}
}

// clientStubAgent implements Agent.
type clientStubAgent struct {
	defaultClient _gen_ipc.Client
	name          string
}

func (__gen_c *clientStubAgent) client(ctx _gen_context.T) _gen_ipc.Client {
	if __gen_c.defaultClient != nil {
		return __gen_c.defaultClient
	}
	return _gen_veyron2.RuntimeFromContext(ctx).Client()
}

func (__gen_c *clientStubAgent) Sign(ctx _gen_context.T, message []byte, opts ..._gen_ipc.CallOpt) (reply security.Signature, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Sign", []interface{}{message}, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubAgent) PublicKey(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply wire.PublicKey, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "PublicKey", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubAgent) UnresolveStep(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply []string, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "UnresolveStep", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubAgent) Signature(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply _gen_ipc.ServiceSignature, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Signature", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubAgent) GetMethodTags(ctx _gen_context.T, method string, opts ..._gen_ipc.CallOpt) (reply []interface{}, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "GetMethodTags", []interface{}{method}, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

// ServerStubAgent wraps a server that implements
// AgentService and provides an object that satisfies
// the requirements of veyron2/ipc.ReflectInvoker.
type ServerStubAgent struct {
	service AgentService
}

func (__gen_s *ServerStubAgent) GetMethodTags(call _gen_ipc.ServerCall, method string) ([]interface{}, error) {
	// TODO(bprosnitz) GetMethodTags() will be replaces with Signature().
	// Note: This exhibits some weird behavior like returning a nil error if the method isn't found.
	// This will change when it is replaced with Signature().
	switch method {
	case "Sign":
		return []interface{}{}, nil
	case "PublicKey":
		return []interface{}{}, nil
	default:
		return nil, nil
	}
}

func (__gen_s *ServerStubAgent) Signature(call _gen_ipc.ServerCall) (_gen_ipc.ServiceSignature, error) {
	result := _gen_ipc.ServiceSignature{Methods: make(map[string]_gen_ipc.MethodSignature)}
	result.Methods["PublicKey"] = _gen_ipc.MethodSignature{
		InArgs: []_gen_ipc.MethodArgument{},
		OutArgs: []_gen_ipc.MethodArgument{
			{Name: "", Type: 71},
			{Name: "", Type: 69},
		},
	}
	result.Methods["Sign"] = _gen_ipc.MethodSignature{
		InArgs: []_gen_ipc.MethodArgument{
			{Name: "message", Type: 66},
		},
		OutArgs: []_gen_ipc.MethodArgument{
			{Name: "", Type: 68},
			{Name: "", Type: 69},
		},
	}

	result.TypeDefs = []_gen_vdlutil.Any{
		_gen_wiretype.NamedPrimitiveType{Type: 0x32, Name: "byte", Tags: []string(nil)}, _gen_wiretype.SliceType{Elem: 0x41, Name: "", Tags: []string(nil)}, _gen_wiretype.NamedPrimitiveType{Type: 0x3, Name: "veyron.io/veyron/veyron2/security.Hash", Tags: []string(nil)}, _gen_wiretype.StructType{
			[]_gen_wiretype.FieldType{
				_gen_wiretype.FieldType{Type: 0x42, Name: "Purpose"},
				_gen_wiretype.FieldType{Type: 0x43, Name: "Hash"},
				_gen_wiretype.FieldType{Type: 0x42, Name: "R"},
				_gen_wiretype.FieldType{Type: 0x42, Name: "S"},
			},
			"veyron.io/veyron/veyron2/security.Signature", []string(nil)},
		_gen_wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}, _gen_wiretype.NamedPrimitiveType{Type: 0x32, Name: "veyron.io/veyron/veyron2/security/wire.KeyCurve", Tags: []string(nil)}, _gen_wiretype.StructType{
			[]_gen_wiretype.FieldType{
				_gen_wiretype.FieldType{Type: 0x46, Name: "Curve"},
				_gen_wiretype.FieldType{Type: 0x42, Name: "XY"},
			},
			"veyron.io/veyron/veyron2/security/wire.PublicKey", []string(nil)},
	}

	return result, nil
}

func (__gen_s *ServerStubAgent) UnresolveStep(call _gen_ipc.ServerCall) (reply []string, err error) {
	if unresolver, ok := __gen_s.service.(_gen_ipc.Unresolver); ok {
		return unresolver.UnresolveStep(call)
	}
	if call.Server() == nil {
		return
	}
	var published []string
	if published, err = call.Server().Published(); err != nil || published == nil {
		return
	}
	reply = make([]string, len(published))
	for i, p := range published {
		reply[i] = _gen_naming.Join(p, call.Name())
	}
	return
}

func (__gen_s *ServerStubAgent) Sign(call _gen_ipc.ServerCall, message []byte) (reply security.Signature, err error) {
	reply, err = __gen_s.service.Sign(call, message)
	return
}

func (__gen_s *ServerStubAgent) PublicKey(call _gen_ipc.ServerCall) (reply wire.PublicKey, err error) {
	reply, err = __gen_s.service.PublicKey(call)
	return
}
