/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const CC = Components.Constructor;
const BinaryInputStream = CC(
  "@mozilla.org/binaryinputstream;1",
  "nsIBinaryInputStream",
  "setInputStream"
);

function DEBUG(str) {
  // dump("********** " + str + "\n");
}

function setOurState(data) {
  x = {
    data,
    QueryInterface(iid) {
      return this;
    },
  };
  x.wrappedJSObject = x;
  setObjectState("beacon-handler", x);
  DEBUG("our state is " + data);
}

function getOurState() {
  var data;
  getObjectState("beacon-handler", function (x) {
    // x can be null if no one has set any state yet
    if (x) {
      data = x.wrappedJSObject.data;
    }
  });
  return data;
}

function handleRequest(request, response) {
  DEBUG("Entered request handler");
  response.setHeader("Cache-Control", "no-cache", false);

  function finishControlResponse(response) {
    DEBUG("********* sending out the control GET response");
    var data = getState("beaconData");
    var mimetype = getState("beaconMimetype");
    DEBUG("GET was sending : " + data + "\n");
    DEBUG("GET was sending : " + mimetype + "\n");
    var result = {
      data,
      mimetype,
    };
    response.write(JSON.stringify(result));
    setOurState(null);
  }

  if (request.method == "GET") {
    DEBUG(" ------------ GET --------------- ");
    response.setHeader("Content-Type", "application/json", false);
    switch (request.queryString) {
      case "getLastBeaconCors":
        // Allow CORS responses of the last beacon
        var originHeader = request.getHeader("origin");
        response.setHeader(
          "Access-Control-Allow-Headers",
          "content-type",
          false
        );
        response.setHeader("Access-Control-Allow-Methods", "POST, GET", false);
        response.setHeader("Access-Control-Allow-Origin", originHeader, false);
        response.setHeader("Access-Control-Allow-Credentials", "true", false);
      // fallthrough
      case "getLastBeacon":
        var state = getOurState();
        if (state === "unblocked") {
          finishControlResponse(response);
        } else {
          DEBUG("GET has  arrived, but POST has not, blocking response!");
          setOurState(response);
          response.processAsync();
        }
        break;
      default:
        response.setStatusLine(request.httpVersion, 400, "Bad Request");
        break;
    }
    return;
  }

  if (request.method == "POST") {
    DEBUG(" ------------ POST --------------- ");
    var body = new BinaryInputStream(request.bodyInputStream);
    var avail;
    var bytes = [];

    while ((avail = body.available()) > 0) {
      Array.prototype.push.apply(bytes, body.readByteArray(avail));
    }

    var data = "";
    for (var i = 0; i < bytes.length; i++) {
      // We are only passing strings at this point.
      if (bytes[i] < 32) {
        continue;
      }
      var charcode = String.fromCharCode(bytes[i]);
      data += charcode;
    }

    var mimetype = "";
    if (request.hasHeader("Content-Type")) {
      mimetype = request.getHeader("Content-Type");
    }

    // check to see if this is form data.
    if (mimetype.indexOf("multipart/form-data") != -1) {
      // trim the mime type to make testing easier.
      mimetype = "multipart/form-data";
      // Extract only the form-data name.

      var pattern = /; name=\"(.+)\";/;
      data = data.split(pattern)[1];
    }

    DEBUG("**********   POST was sending : " + data + "\n");
    DEBUG("**********   POST was sending : " + mimetype + "\n");
    setState("beaconData", data);
    setState("beaconMimetype", mimetype);

    response.setHeader("Content-Type", "text/plain", false);
    response.write("ok");

    var blockedResponse = getOurState();
    if (typeof blockedResponse == "object" && blockedResponse) {
      DEBUG("GET is already pending, finishing!");
      finishControlResponse(blockedResponse);
      blockedResponse.finish();
    } else {
      DEBUG("GET has not arrived, marking it as unblocked");
      setOurState("unblocked");
    }

    return;
  }

  response.setStatusLine(request.httpVersion, 402, "Bad Request");
}
