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

#include <lib/async/wait.h>
#include <lib/fidl-async/bind.h>
#include <stdlib.h>
#include <string.h>
#include <zircon/assert.h>
#include <zircon/syscalls.h>

typedef struct fidl_binding {
  async_wait_t wait;
  fidl_dispatch_t* dispatch;
  async_dispatcher_t* dispatcher;
  void* ctx;
  const void* ops;
} fidl_binding_t;

typedef struct fidl_connection {
  fidl_txn_t txn;
  zx_handle_t channel;
  zx_txid_t txid;
  fidl_binding_t* binding;
} fidl_connection_t;

static zx_status_t fidl_reply(fidl_txn_t* txn, const fidl_msg_t* msg) {
  fidl_connection_t* conn = (fidl_connection_t*)txn;
  if (conn->txid == 0u)
    return ZX_ERR_BAD_STATE;
  if (msg->num_bytes < sizeof(fidl_message_header_t))
    return ZX_ERR_INVALID_ARGS;
  fidl_message_header_t* hdr = (fidl_message_header_t*)msg->bytes;
  hdr->txid = conn->txid;
  conn->txid = 0u;
  return zx_channel_write(conn->channel, 0, msg->bytes, msg->num_bytes, msg->handles,
                          msg->num_handles);
}

static void fidl_binding_destroy(fidl_binding_t* binding) {
  zx_handle_close(binding->wait.object);
  free(binding);
}

static void fidl_message_handler(async_dispatcher_t* dispatcher, async_wait_t* wait,
                                 zx_status_t status, const zx_packet_signal_t* signal) {
  fidl_binding_t* binding = (fidl_binding_t*)wait;
  if (status != ZX_OK) {
    goto shutdown;
  }

  if (signal->observed & ZX_CHANNEL_READABLE) {
    char bytes[ZX_CHANNEL_MAX_MSG_BYTES];
    zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES];
    for (uint64_t i = 0; i < signal->count; i++) {
      fidl_msg_t msg = {
          .bytes = bytes,
          .handles = handles,
          .num_bytes = 0u,
          .num_handles = 0u,
      };
      status = zx_channel_read(wait->object, 0, bytes, handles, ZX_CHANNEL_MAX_MSG_BYTES,
                               ZX_CHANNEL_MAX_MSG_HANDLES, &msg.num_bytes, &msg.num_handles);
      if (status == ZX_ERR_SHOULD_WAIT) {
        // This occurs when someone else has read the message we were expecting.
        goto shutdown;
      }
      if (status != ZX_OK || msg.num_bytes < sizeof(fidl_message_header_t)) {
        goto shutdown;
      }
      fidl_message_header_t* hdr = (fidl_message_header_t*)msg.bytes;
      fidl_connection_t conn = {
          .txn.reply = fidl_reply,
          .channel = wait->object,
          .txid = hdr->txid,
          .binding = binding,
      };
      status = binding->dispatch(binding->ctx, &conn.txn, &msg, binding->ops);
      switch (status) {
        case ZX_OK:
          continue;
        case ZX_ERR_ASYNC:
          return;
        default:
          goto shutdown;
      }
    }

    // Only |status| == ZX_OK will lead here
    if (async_begin_wait(dispatcher, wait) == ZX_OK) {
      return;
    } else {
      goto shutdown;
    }
  } else {
    ZX_DEBUG_ASSERT(signal->observed & ZX_CHANNEL_PEER_CLOSED);
  }

shutdown:
  fidl_binding_destroy(binding);
}

zx_status_t fidl_bind(async_dispatcher_t* dispatcher, zx_handle_t channel,
                      fidl_dispatch_t* dispatch, void* ctx, const void* ops) {
  fidl_binding_t* binding = calloc(1, sizeof(fidl_binding_t));
  binding->wait.handler = fidl_message_handler;
  binding->wait.object = channel;
  binding->wait.trigger = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
  binding->wait.options = 0;
  binding->dispatch = dispatch;
  binding->dispatcher = dispatcher;
  binding->ctx = ctx;
  binding->ops = ops;
  zx_status_t status = async_begin_wait(dispatcher, &binding->wait);
  if (status != ZX_OK) {
    fidl_binding_destroy(binding);
  }
  return status;
}

typedef struct fidl_async_txn {
  fidl_connection_t connection;
} fidl_async_txn_t;

fidl_async_txn_t* fidl_async_txn_create(fidl_txn_t* txn) {
  fidl_connection_t* connection = (fidl_connection_t*)txn;

  fidl_async_txn_t* async_txn = calloc(1, sizeof(fidl_async_txn_t));
  memcpy(&async_txn->connection, connection, sizeof(*connection));

  return async_txn;
}

fidl_txn_t* fidl_async_txn_borrow(fidl_async_txn_t* async_txn) {
  return &async_txn->connection.txn;
}

zx_status_t fidl_async_txn_complete(fidl_async_txn_t* async_txn, bool rebind) {
  zx_status_t status = ZX_OK;
  if (rebind) {
    status = async_begin_wait(async_txn->connection.binding->dispatcher,
                              &async_txn->connection.binding->wait);
    if (status == ZX_OK) {
      free(async_txn);
      return ZX_OK;
    }
  }

  fidl_binding_destroy(async_txn->connection.binding);
  free(async_txn);
  return status;
}
