// Copyright (c) 2016, 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.

#ifndef RUNTIME_BIN_LOADER_H_
#define RUNTIME_BIN_LOADER_H_

#include "bin/isolate_data.h"
#include "include/dart_api.h"
#include "include/dart_native_api.h"
#include "platform/assert.h"
#include "platform/globals.h"
#include "bin/thread.h"

namespace dart {
namespace bin {

class Loader {
 public:
  explicit Loader(IsolateData* isolate_data);
  ~Loader();

  static void InitForSnapshot(const char* snapshot_uri);

  static Dart_Handle ReloadNativeExtensions();

  // Loads contents of the specified url.
  static Dart_Handle LoadUrlContents(Dart_Handle url,
                                     uint8_t** payload,
                                     intptr_t* payload_length);


  // A static tag handler that hides all usage of a loader for an isolate.
  static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
                                       Dart_Handle library,
                                       Dart_Handle url);

  Dart_Handle error() const { return error_; }

  static void InitOnce();

 private:
  // The port assigned to our native message handler.
  Dart_Port port_;
  // Each Loader is associated with an Isolate via its IsolateData.
  IsolateData* isolate_data_;
  // Remember the first error that occurs during loading.
  Dart_Handle error_;
  // This monitor is used to protect the pending operations count and the
  // I/O result queue.
  Monitor* monitor_;

  // The number of operations dispatched to the service isolate for loading.
  // Must be accessed with monitor_ held.
  intptr_t pending_operations_;

  // The result of an I/O request to the service isolate. Payload is either
  // a UInt8Array or a C string containing an error message.
  struct IOResult {
    uint8_t* payload;
    intptr_t payload_length;
    char* library_uri;
    char* uri;
    char* resolved_uri;
    int8_t tag;

    void Setup(Dart_CObject* message);
    void Cleanup();
  };
  // An array of I/O results queued from the service isolate.
  IOResult* results_;
  intptr_t results_length_;
  intptr_t results_capacity_;
  uint8_t* payload_;
  intptr_t payload_length_;
  typedef bool (*ProcessResult)(Loader* loader, IOResult* result);

  intptr_t results_length() {
    return *static_cast<volatile intptr_t*>(&results_length_);
  }

  // Send the loader init request to the service isolate.
  void Init(const char* package_root,
            const char* packages_file,
            const char* working_directory,
            const char* root_script_uri);

  // Send a request for a dart-ext: import to the service isolate.
  void SendImportExtensionRequest(Dart_Handle url, Dart_Handle library_url);

  // Send a request from the tag handler to the service isolate.
  void SendRequest(Dart_LibraryTag tag,
                   Dart_Handle url,
                   Dart_Handle library_url);

  // Send a request from the tag handler to the kernel isolate.
  void SendKernelRequest(Dart_LibraryTag tag, Dart_Handle url);

  /// Queue |message| and notify the loader that a message is available.
  void QueueMessage(Dart_CObject* message);

  /// Blocks the caller until the loader is finished.
  void BlockUntilComplete(ProcessResult process_result);

  /// Returns false if |result| is an error and the loader should quit.
  static bool ProcessResultLocked(Loader* loader, IOResult* result);

  /// Returns false if |result| is an error and the loader should quit.
  static bool ProcessUrlLoadResultLocked(Loader* loader, IOResult* result);

  /// Returns false if an error occurred and the loader should quit.
  bool ProcessQueueLocked(ProcessResult process_result);

  // Special inner tag handler for dart: uris.
  static Dart_Handle DartColonLibraryTagHandler(Dart_LibraryTag tag,
                                                Dart_Handle library,
                                                Dart_Handle url,
                                                const char* library_url_string,
                                                const char* url_string);

  // We use one native message handler callback for N loaders. The native
  // message handler callback provides us with the Dart_Port which we use as a
  // key into our map of active loaders from |port| to |isolate_data|.

  // Static information to map Dart_Port back to the isolate in question.
  struct LoaderInfo {
    Dart_Port port;
    IsolateData* isolate_data;
  };

  // The map of active loaders.
  static Mutex* loader_infos_lock_;
  static LoaderInfo* loader_infos_;
  static intptr_t loader_infos_length_;
  static intptr_t loader_infos_capacity_;

  static void AddLoader(Dart_Port port, IsolateData* data);
  static void RemoveLoader(Dart_Port port);
  static intptr_t LoaderIndexFor(Dart_Port port);
  static Loader* LoaderFor(Dart_Port port);
  static Loader* LoaderForLocked(Dart_Port port);

  // This is the global callback for the native message handlers.
  static void NativeMessageHandler(Dart_Port dest_port_id,
                                   Dart_CObject* message);
};

}  // namespace bin
}  // namespace dart

#endif  // RUNTIME_BIN_LOADER_H_
