// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "bin/dbg_connection.h"
#include "bin/dbg_message.h"
#include "bin/dartutils.h"
#include "bin/log.h"
#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"

#include "platform/globals.h"
#include "platform/json.h"
#include "platform/thread.h"
#include "platform/utils.h"

#include "include/dart_api.h"


namespace dart {
namespace bin {

int DebuggerConnectionHandler::listener_fd_ = -1;
dart::Monitor* DebuggerConnectionHandler::handler_lock_ = new dart::Monitor();

// TODO(asiva): Remove this once we have support for multiple debugger
// connections. For now we just store the single debugger connection
// handler in a static variable.
static DebuggerConnectionHandler* singleton_handler = NULL;


class MessageBuffer {
 public:
  explicit MessageBuffer(int fd);
  ~MessageBuffer();
  void ReadData();
  bool IsValidMessage() const;
  void PopMessage();
  int MessageId() const;
  char* buf() const { return buf_; }
  bool Alive() const { return connection_is_alive_; }

 private:
  static const int kInitialBufferSize = 256;
  char* buf_;
  int buf_length_;
  int fd_;
  int data_length_;
  bool connection_is_alive_;

  DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
};


MessageBuffer::MessageBuffer(int fd)
    :  buf_(NULL),
       buf_length_(0),
       fd_(fd),
       data_length_(0),
       connection_is_alive_(true) {
  buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize));
  if (buf_ == NULL) {
    FATAL("Failed to allocate message buffer\n");
  }
  buf_length_ = kInitialBufferSize;
  buf_[0] = '\0';
  data_length_ = 0;
}


MessageBuffer::~MessageBuffer() {
  free(buf_);
  buf_ = NULL;
  fd_ = -1;
}


bool MessageBuffer::IsValidMessage() const {
  if (data_length_ == 0) {
    return false;
  }
  dart::JSONReader msg_reader(buf_);
  return msg_reader.EndOfObject() != NULL;
}


int MessageBuffer::MessageId() const {
  dart::JSONReader r(buf_);
  r.Seek("id");
  if (r.Type() == dart::JSONReader::kInteger) {
    return atoi(r.ValueChars());
  } else {
    return -1;
  }
}


void MessageBuffer::ReadData() {
  ASSERT(data_length_ >= 0);
  ASSERT(data_length_ < buf_length_);
  int max_read = buf_length_ - data_length_ - 1;
  if (max_read == 0) {
    // TODO(hausner):
    // Buffer is full. What should we do if there is no valid message
    // in the buffer? This might be possible if the client sends a message
    // that's larger than the buffer, of if the client sends malformed
    // messages that keep piling up.
    ASSERT(IsValidMessage());
    return;
  }
  // TODO(hausner): Handle error conditions returned by Read. We may
  // want to close the debugger connection if we get any errors.
  int bytes_read =
      DebuggerConnectionImpl::Receive(fd_, buf_ + data_length_, max_read);
  if (bytes_read == 0) {
    connection_is_alive_ = false;
    return;
  }
  ASSERT(bytes_read > 0);
  data_length_ += bytes_read;
  ASSERT(data_length_ < buf_length_);
  buf_[data_length_] = '\0';
}


void MessageBuffer::PopMessage() {
  dart::JSONReader msg_reader(buf_);
  const char* end = msg_reader.EndOfObject();
  if (end != NULL) {
    ASSERT(*end == '}');
    end++;
    data_length_ = 0;
    while (*end != '\0') {
      buf_[data_length_] = *end++;
      data_length_++;
    }
    buf_[data_length_] = '\0';
    ASSERT(data_length_ < buf_length_);
  }
}


static bool IsValidJSON(const char* msg) {
  dart::JSONReader r(msg);
  return r.CheckMessage();
}


DebuggerConnectionHandler::DebuggerConnectionHandler(int debug_fd)
    : debug_fd_(debug_fd), msgbuf_(NULL) {
  msgbuf_ = new MessageBuffer(debug_fd_);
}


DebuggerConnectionHandler::~DebuggerConnectionHandler() {
  CloseDbgConnection();
  DebuggerConnectionHandler::RemoveDebuggerConnection(debug_fd_);
}


int DebuggerConnectionHandler::MessageId() {
  ASSERT(msgbuf_ != NULL);
  return msgbuf_->MessageId();
}


void DebuggerConnectionHandler::HandleUnknownMsg() {
  int msg_id = msgbuf_->MessageId();
  ASSERT(msg_id >= 0);
  SendError(debug_fd_, msg_id, "unknown debugger command");
}


typedef void (*CommandHandler)(DbgMessage* msg);

struct JSONDebuggerCommand {
  const char* cmd_string;
  CommandHandler handler_function;
};


void DebuggerConnectionHandler::HandleMessages() {
  static JSONDebuggerCommand generic_debugger_commands[] = {
    { "interrupt", HandleInterruptCmd },
    { "getIsolateIds", HandleIsolatesListCmd },
    { NULL, NULL }
  };

  for (;;) {
    // Read a message.
    while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) {
      msgbuf_->ReadData();
    }
    if (!msgbuf_->Alive()) {
      return;
    }

    // Parse out the command portion from the message.
    dart::JSONReader r(msgbuf_->buf());
    bool found = r.Seek("command");
    if (r.Error()) {
      FATAL("Illegal JSON message received");
    }
    if (!found) {
      Log::Print("'command' not found in JSON message: '%s'\n",
                      msgbuf_->buf());
      msgbuf_->PopMessage();
    }

    // Check if this is a generic command (not isolate specific).
    int i = 0;
    bool is_handled = false;
    while (generic_debugger_commands[i].cmd_string != NULL) {
      if (r.IsStringLiteral(generic_debugger_commands[i].cmd_string)) {
        DbgMessage* msg = new DbgMessage(i,
                                         msgbuf_->buf(),
                                         r.EndOfObject(),
                                         debug_fd_);
        (*generic_debugger_commands[i].handler_function)(msg);
        is_handled = true;
        msgbuf_->PopMessage();
        delete msg;
        break;
      }
      i++;
    }
    if (!is_handled) {
      // Check if this is an isolate specific command.
      int32_t cmd_idx = DbgMsgQueueList::LookupIsolateCommand(r.ValueChars(),
                                                              r.ValueLen());
      if (cmd_idx != DbgMsgQueueList::kInvalidCommand) {
        const char* start = msgbuf_->buf();
        const char* end = r.EndOfObject();
        // Get debug message queue corresponding to isolate.
        MessageParser msg_parser(start, (end - start));
        Dart_IsolateId isolate_id =
            static_cast<Dart_IsolateId>(msg_parser.GetIntParam("isolateId"));
        if (!DbgMsgQueueList::AddIsolateMessage(isolate_id,
                                                cmd_idx,
                                                msgbuf_->buf(),
                                                r.EndOfObject(),
                                                debug_fd_)) {
          SendError(debug_fd_, MessageId(), "Invalid isolate specified");
        }
        msgbuf_->PopMessage();
        continue;
      }

      // This is an unrecognized command, report error and move on to next.
      Log::Print("unrecognized command received: '%s'\n", msgbuf_->buf());
      HandleUnknownMsg();
      msgbuf_->PopMessage();
    }
  }
}


void DebuggerConnectionHandler::SendError(int debug_fd,
                                          int msg_id,
                                          const char* err_msg) {
  dart::TextBuffer msg(64);
  msg.Printf("{\"id\": %d, \"error\": \"Error: ", msg_id);
  msg.AddEscapedString(err_msg);
  msg.Printf("\"}");
  SendMsg(debug_fd, &msg);
}


void DebuggerConnectionHandler::CloseDbgConnection() {
  if (debug_fd_ >= 0) {
    Socket::Close(debug_fd_);
  }
  if (msgbuf_ != NULL) {
    delete msgbuf_;
    msgbuf_ = NULL;
  }
  // TODO(hausner): Need to tell the VM debugger object to remove all
  // breakpoints.
}


int DebuggerConnectionHandler::StartHandler(const char* address,
                                            int port_number) {
  ASSERT(handler_lock_ != NULL);
  MonitorLocker ml(handler_lock_);
  if (listener_fd_ != -1) {
    // The debugger connection handler was already started.
    return Socket::GetPort(listener_fd_);
  }

  // First setup breakpoint, exception and delayed breakpoint handlers.
  DbgMsgQueueList::Initialize();

  // Initialize the socket implementation.
  if (!Socket::Initialize()) {
    FATAL("Failed initializing socket implementation.");
  }

  // Now setup a listener socket and start a thread which will
  // listen, accept connections from debuggers, read and handle/dispatch
  // debugger commands received on these connections.
  ASSERT(listener_fd_ == -1);
  OSError *os_error;
  AddressList<SocketAddress>* addresses =
      Socket::LookupAddress(address, -1, &os_error);
  listener_fd_ = ServerSocket::CreateBindListen(
      addresses->GetAt(0)->addr(), port_number, 1);
  delete addresses;
  port_number = Socket::GetPort(listener_fd_);
  DebuggerConnectionImpl::StartHandler(port_number);
  return port_number;
}


void DebuggerConnectionHandler::WaitForConnection() {
  ASSERT(handler_lock_ != NULL);
  MonitorLocker ml(handler_lock_);
  while (!IsConnected()) {
    dart::Monitor::WaitResult res = ml.Wait();
    ASSERT(res == dart::Monitor::kNotified);
  }
}


void DebuggerConnectionHandler::SendMsg(int debug_fd, dart::TextBuffer* msg) {
  ASSERT(handler_lock_ != NULL);
  MonitorLocker ml(handler_lock_);
  SendMsgHelper(debug_fd, msg);
}


void DebuggerConnectionHandler::BroadcastMsg(dart::TextBuffer* msg) {
  ASSERT(handler_lock_ != NULL);
  MonitorLocker ml(handler_lock_);
  // TODO(asiva): Once we support connection to multiple debuggers
  // we need to send the message to all of them.
  ASSERT(singleton_handler != NULL);
  SendMsgHelper(singleton_handler->debug_fd(), msg);
}


void DebuggerConnectionHandler::SendMsgHelper(int debug_fd,
                                              dart::TextBuffer* msg) {
  ASSERT(debug_fd >= 0);
  ASSERT(IsValidJSON(msg->buf()));
  // Sending messages in short pieces can be used to stress test the
  // debugger front-end's message handling code.
  const bool send_in_pieces = false;
  if (send_in_pieces) {
    intptr_t remaining = msg->length();
    intptr_t sent = 0;
    const intptr_t max_piece_len = 122;  // Pretty arbitrary, not a power of 2.
    dart::Monitor sleep;
    while (remaining > 0) {
      intptr_t piece_len = remaining;
      if (piece_len > max_piece_len) {
        piece_len = max_piece_len;
      }
      intptr_t written =
          DebuggerConnectionImpl::Send(debug_fd, msg->buf() + sent, piece_len);
      ASSERT(written == piece_len);
      sent += written;
      remaining -= written;
      // Wait briefly so the OS does not coalesce message fragments.
      {
        MonitorLocker ml(&sleep);
        ml.Wait(10);
      }
    }
    return;
  }
  intptr_t bytes_written =
      DebuggerConnectionImpl::Send(debug_fd, msg->buf(), msg->length());
  ASSERT(msg->length() == bytes_written);
  // TODO(hausner): Error checking. Probably just shut down the debugger
  // session if we there is an error while writing.
}


void DebuggerConnectionHandler::AcceptDbgConnection(int debug_fd) {
  Socket::SetNoDelay(debug_fd, true);
  AddNewDebuggerConnection(debug_fd);
  {
    ASSERT(handler_lock_ != NULL);
    MonitorLocker ml(handler_lock_);
    ml.NotifyAll();
  }
  // TODO(asiva): Once we implement support for multiple connections
  // we should have a different callback for wakeups on fds which
  // are not the listener_fd_.
  // In that callback we would lookup the handler object
  // corresponding to that fd and invoke HandleMessages on it.
  // For now we run that code here.
  DebuggerConnectionHandler* handler = GetDebuggerConnectionHandler(debug_fd);
  if (handler != NULL) {
    handler->HandleMessages();
    delete handler;
  }
}


void DebuggerConnectionHandler::HandleInterruptCmd(DbgMessage* in_msg) {
  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
  int msg_id = msg_parser.MessageId();
  Dart_IsolateId isolate_id =
      static_cast<Dart_IsolateId>(msg_parser.GetIntParam("isolateId"));
  if (isolate_id == ILLEGAL_ISOLATE_ID || Dart_GetIsolate(isolate_id) == NULL) {
    in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
    return;
  }
  if (!DbgMsgQueueList::InterruptIsolate(isolate_id)) {
    in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
    return;
  }
  dart::TextBuffer msg(64);
  msg.Printf("{ \"id\": %d }", msg_id);
  in_msg->SendReply(&msg);
}


void DebuggerConnectionHandler::HandleIsolatesListCmd(DbgMessage* in_msg) {
  MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
  int msg_id = msg_parser.MessageId();
  ASSERT(msg_id >= 0);
  dart::TextBuffer msg(64);
  msg.Printf("{ \"id\": %d, \"result\": { \"isolateIds\": [", msg_id);
  DbgMsgQueueList::ListIsolateIds(&msg);
  msg.Printf("]}}");
  in_msg->SendReply(&msg);
}


void DebuggerConnectionHandler::AddNewDebuggerConnection(int debug_fd) {
  // TODO(asiva): Support multiple debugger connections, for now we just
  // create one handler, store it in a static variable and use it.
  ASSERT(singleton_handler == NULL);
  singleton_handler = new DebuggerConnectionHandler(debug_fd);
}


void DebuggerConnectionHandler::RemoveDebuggerConnection(int debug_fd) {
  // TODO(asiva): Support multiple debugger connections, for now we just
  // set the static handler back to NULL.
  ASSERT(singleton_handler != NULL);
  singleton_handler = NULL;
}


DebuggerConnectionHandler*
DebuggerConnectionHandler::GetDebuggerConnectionHandler(int debug_fd) {
  // TODO(asiva): Support multiple debugger connections, for now we just
  // return the one static handler that was created.
  ASSERT(singleton_handler != NULL);
  return singleton_handler;
}


bool DebuggerConnectionHandler::IsConnected() {
  // TODO(asiva): Support multiple debugger connections.
  // Return true if a connection has been established.
  return singleton_handler != NULL;
}

}  // namespace bin
}  // namespace dart
