define([
  "dojo/_base/declare",
  "dojo/topic",
  "dojo/request",
  "helpers/UrlBuilder",
  "mappers/CesiumParametersMapper",
  "gui/StatusBar",
  "helpers/NodeCache",
  "helpers/CameraChangeEvent",
  "mappers/CesiumMapper"
], function (declare, topic, request, UrlBuilder, CesiumParametersMapper, StatusBar, NodeCache, CameraChangeEvent, CesiumMapper) {

  return declare(null, {

    constructor: function () { },

    request: function (req) {
      let clientParams = new CesiumParametersMapper();
      let url = new UrlBuilder(location.protocol.slice(0, -1), req.host)
        .port(req.port)
        .path(req.endpoint)
        .param("service", "3DPS")
        .param("acceptversions", "1.0")
        .param("request", "GetScene")
        .param("boundingbox", req.boundingBox)
        .param("cullingvolume", clientParams.cullingVolume2Url())
        .param("camera", clientParams.camera2Url())
        .param("frustum", clientParams.frustum2Url())
        .param("drawingbuffer", clientParams.drawingBuffer2Url())
        .param("time", Date.now())
        .param("intersect", true)
        .build();

      StatusBar.beginProcess("Waiting for response");

      request(url, { handleAs: "json" })
        .then(async (portrayalNodes) => {

          if (portrayalNodes.length == 0) {
            NodeCache.clearAll();
            StatusBar.endProcess();
            topic.publish("PortrayalResponseHandled", "SceneRendered");
            return;
          }

          let requestTime = Number(portrayalNodes[0].time);
          if (requestTime < CameraChangeEvent.getTime()) return;

          let responseIds = portrayalNodes.map(n => { return n.id; });
          NodeCache.matchAll(responseIds);

          let mapper = new CesiumMapper();

          StatusBar.beginProcess("Processing");

          try {
            await Promise.all(
              portrayalNodes.map(async (node) => {
                if (requestTime < CameraChangeEvent.getTime()) throw BreakException;
                if (!NodeCache.contains(node.id)) {
                  let instances = await mapper.map(node);
                  await NodeCache.add(instances, node);
                }
              })
            );

            StatusBar.endProcess();
            topic.publish("PortrayalResponseHandled", "SceneRendered");

          } catch (e) {
            NodeCache.clearAll();
            StatusBar.endProcess();
            topic.publish("PortrayalResponseHandled", "BoundingBoxUndefined");
          }

        }, function (err) {
          NodeCache.clearAll();
          StatusBar.endProcess();
          topic.publish("PortrayalResponseHandled", "BoundingBoxUndefined");
        });

    }

  });

});