"use strict"

// This function is used to do remote procedure calls from the worker to the
// main thread. It is exposed as a built-in global to every module by the
// worker loader. To make sure the worker loader can access it, it needs to be
// defined before loading the worker loader script below.
this.rpc = function (method, ...params) {
  let id = nextId++;

  postMessage(JSON.stringify({
    type: "rpc",
    method: method,
    params: params,
    id: id
  }));

  let deferred = Promise.defer();
  rpcDeferreds[id] = deferred;
  return deferred.promise;
};

loadSubScript("resource://devtools/shared/worker/loader.js");

var Promise = worker.require("promise");
var { ActorPool } = worker.require("devtools/server/actors/common");
var { ThreadActor } = worker.require("devtools/server/actors/script");
var { WebConsoleActor } = worker.require("devtools/server/actors/webconsole");
var { TabSources } = worker.require("devtools/server/actors/utils/TabSources");
var makeDebugger = worker.require("devtools/server/actors/utils/make-debugger");
var { DebuggerServer } = worker.require("devtools/server/main");

DebuggerServer.init();
DebuggerServer.createRootActor = function () {
  throw new Error("Should never get here!");
};

var connections = Object.create(null);
var nextId = 0;
var rpcDeferreds = [];

this.addEventListener("message",  function (event) {
  let packet = JSON.parse(event.data);
  switch (packet.type) {
  case "connect":
    // Step 3: Create a connection to the parent.
    let connection = DebuggerServer.connectToParent(packet.id, this);
    connections[packet.id] = {
      connection : connection,
      rpcs: []
    };

    // Step 4: Create a thread actor for the connection to the parent.
    let pool = new ActorPool(connection);
    connection.addActorPool(pool);

    let sources = null;

    let parent = {
      makeDebugger: makeDebugger.bind(null, {
        findDebuggees: () => {
          return [this.global];
        },

        shouldAddNewGlobalAsDebuggee: () => {
          return true;
        },
      }),

      get sources() {
        if (sources === null) {
          sources = new TabSources(threadActor);
        }
        return sources;
      },

      window: global
    };

    let threadActor = new ThreadActor(parent, global);
    pool.addActor(threadActor);

    let consoleActor = new WebConsoleActor(connection, parent);
    pool.addActor(consoleActor);

    // Step 5: Send a response packet to the parent to notify
    // it that a connection has been established.
    postMessage(JSON.stringify({
      type: "connected",
      id: packet.id,
      threadActor: threadActor.actorID,
      consoleActor: consoleActor.actorID,
    }));
    break;

  case "disconnect":
    connections[packet.id].connection.close();
    break;

  case "rpc":
    let deferred = rpcDeferreds[packet.id];
    delete rpcDeferreds[packet.id];
    if (packet.error) {
        deferred.reject(packet.error);
    }
    deferred.resolve(packet.result);
    break;
  };
});
