// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build fuchsia

package fidl

import (
	"strconv"
	"syscall/zx"
	"syscall/zx/zxwait"
)

// ServiceRequest is an abstraction over a FIDL interface request which is
// intended to be used as part of service discovery.
type ServiceRequest interface {
	// Name returns the name of the service being requested.
	Name() string

	// ToChannel returns the underlying channel of the ServiceRequest.
	ToChannel() zx.Channel
}

// InterfaceRequest is a wrapper type around a channel and represents the server side
// of a FIDL interface, to be sent to a server as a request.
type InterfaceRequest struct {
	zx.Channel
}

// NewInterfaceRequest generates two sides of a channel with one layer of
// type casts out of the way to minimize the amount of generated code. Semantically,
// the two sides of the channel represent the interface request and the client
// side of the interface (the proxy). It returns an error on failure.
func NewInterfaceRequest() (InterfaceRequest, *ChannelProxy, error) {
	h0, h1, err := zx.NewChannel(0)
	if err != nil {
		return InterfaceRequest{}, nil, err
	}
	return InterfaceRequest{Channel: h0}, &ChannelProxy{Channel: h1}, nil
}

// Proxy represents the client side of a FIDL interface.
type Proxy interface {
	IsValid() bool
	Send(ordinal uint64, req Message) error
	// TODO(FIDL-524): Remove `gen_ordinal` post-ordinal migration.
	Recv(ordinal uint64, resp Message, gen_ordinal ...uint64) error
	Call(ordinal uint64, req Message, resp Message, gen_ordinal ...uint64) error
}

// Stub represents a generated type which wraps the server-side implementation of a
// FIDL interface.
//
// It contains logic which is able to dispatch into the correct implementation given
// the incoming message ordinal and its data.
type Stub interface {
	// DispatchImpl dispatches into the appropriate method implementation for a FIDL
	// interface by using the ordinal.
	//
	// It also takes the data as bytes and transforms it into arguments usable by
	// the method implementation. It then optionally returns a response if the
	// method has a response, in which case, the boolean return value is true.
	DispatchImpl(ordinal uint64, bytes []byte, handles []zx.Handle) (Message, bool, error)
}

// ChannelProxy a Proxy that is backed by a channel.
type ChannelProxy struct {
	// Channel is the underlying channel endpoint for this interface.
	zx.Channel
}

// Assert that ChannelProxy implements the Proxy interface.
var _ Proxy = &ChannelProxy{}

// IsValid returns true if the underlying channel is a valid handle.
func (p *ChannelProxy) IsValid() bool {
	return p.Channel.Handle().IsValid()
}

func withRetry(fn func() error, handle zx.Handle, ready, closed zx.Signals) error {
	signals := ready | closed
	for {
		err := fn()
		if err, ok := err.(*zx.Error); ok && err.Status == zx.ErrShouldWait {
			obs, err := zxwait.Wait(
				handle,
				signals,
				zx.TimensecInfinite,
			)
			if err != nil {
				return err
			}
			if obs&ready != 0 {
				continue
			}
			if obs&closed != 0 {
				return &zx.Error{Status: zx.ErrPeerClosed}
			}
			panic("unexpected signal mask " + strconv.FormatUint(uint64(obs), 2) + " (expected " + strconv.FormatUint(uint64(signals), 2) + ")")
		}
		return err
	}
}

func unmarshalForOrdinal(ordinal uint64, respb []byte, resph []zx.Handle, resp Message, gen_ordinal ...uint64) error {
	var header MessageHeader
	if err := UnmarshalHeaderThenMessage(respb, resph, &header, resp); err != nil {
		return err
	}
	// TODO(FIDL-524): Remove temporary handling of two ordinals.
	expectedOrdinal := header.Ordinal == ordinal
	for _, ordinal := range gen_ordinal {
		expectedOrdinal = expectedOrdinal || header.Ordinal == ordinal
	}
	if !expectedOrdinal {
		return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
	}
	return nil
}

// Send sends the request over the channel with the specified ordinal
// without a response.
func (p *ChannelProxy) Send(ordinal uint64, req Message) error {
	respb := messageBytesPool.Get().([]byte)
	resph := messageHandlesPool.Get().([]zx.Handle)

	defer messageBytesPool.Put(respb)
	defer messageHandlesPool.Put(resph)

	// Marshal the message into the buffer.
	header := MessageHeader{
		Txid:    0, // Txid == 0 for messages without a response.
		Ordinal: ordinal,
	}
	nb, nh, err := MarshalHeaderThenMessage(&header, req, respb[:], resph[:])
	if err != nil {
		return err
	}

	// Write the encoded bytes to the channel.
	return withRetry(func() error {
		return p.Channel.Write(respb[:nb], resph[:nh], 0)
	}, *p.Channel.Handle(), zx.SignalChannelWritable, zx.SignalChannelPeerClosed)
}

// Recv waits for an event and writes the response into the response.
func (p *ChannelProxy) Recv(ordinal uint64, resp Message, gen_ordinal ...uint64) error {
	respb := messageBytesPool.Get().([]byte)
	resph := messageHandlesPool.Get().([]zx.Handle)

	defer messageBytesPool.Put(respb)
	defer messageHandlesPool.Put(resph)

	var nb, nh uint32
	if err := withRetry(func() error {
		var err error
		nb, nh, err = p.Channel.Read(respb[:], resph[:], 0)
		return err
	}, *p.Channel.Handle(), zx.SignalChannelReadable, zx.SignalChannelPeerClosed); err != nil {
		return err
	}

	return unmarshalForOrdinal(ordinal, respb[:nb], resph[:nh], resp, gen_ordinal...)
}

// Call sends the request over the channel with the specified ordinal
// and synchronously waits for a response. It then writes the response into the
// response.
func (p *ChannelProxy) Call(ordinal uint64, req Message, resp Message, gen_ordinal ...uint64) error {
	respb := messageBytesPool.Get().([]byte)
	resph := messageHandlesPool.Get().([]zx.Handle)

	defer messageBytesPool.Put(respb)
	defer messageHandlesPool.Put(resph)

	// Marshal the message into the buffer
	header := MessageHeader{
		Ordinal: ordinal,
	}
	nb, nh, err := MarshalHeaderThenMessage(&header, req, respb[:], resph[:])
	if err != nil {
		return err
	}

	// Make the IPC call.
	cnb, cnh, err := p.Channel.Call(0, zx.TimensecInfinite, respb[:nb], resph[:nh], respb[:], resph[:])
	if err != nil {
		return err
	}

	return unmarshalForOrdinal(ordinal, respb[:cnb], resph[:cnh], resp, gen_ordinal...)
}
