/*
 * Copyright 2019 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tools/debugger/DebugLayerManager.h"

#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPicture.h"
#include "include/core/SkSurface.h"
#include "include/private/SkTHash.h"
#include "tools/debugger/DebugCanvas.h"

#include <memory>
#include <vector>
#include <tuple>
#include <unordered_map>

void DebugLayerManager::setCommand(int nodeId, int frame, int command) {
  auto* drawEvent = fDraws.find({frame, nodeId});
  if (!drawEvent) {
    SkDebugf("Could not set command playhead for event {%d, %d}, it is not tracked by"
      "DebugLayerManager.\n", frame, nodeId);
    return;
  }
  const int count = drawEvent->debugCanvas->getSize();
  drawEvent->command = command < count ? command : count - 1;
  // Invalidate stored images that depended on this combination of node and frame.
  // actually this does all of the events for this nodeId, but close enough.
  auto relevantFrames = listFramesForNode(nodeId);
  for (const auto& frame : relevantFrames) {
    fDraws[{frame, nodeId}].image = nullptr;
  }
}

void DebugLayerManager::storeSkPicture(int nodeId, int frame, sk_sp<SkPicture> picture,
    SkIRect dirty) {
  const LayerKey k = {frame, nodeId};

  // Make debug canvas using bounds from SkPicture. This will be equal to whatever width and
  // height were passed into SkPictureRecorder::beginRecording(w, h) which is the layer bounds.
  const auto& layerBounds = picture->cullRect().roundOut();
  auto debugCanvas = std::make_unique<DebugCanvas>(layerBounds);
  // Must be set or they end up undefined due to cosmic rays, bad luck, etc.
  debugCanvas->setOverdrawViz(false);
  debugCanvas->setDrawGpuOpBounds(false);
  debugCanvas->setClipVizColor(SK_ColorTRANSPARENT);
  // Setting this allows a layer to contain another layer. TODO(nifong): write a test for this.
  debugCanvas->setLayerManagerAndFrame(this, frame);
  // Only draw picture to the debug canvas once.
  debugCanvas->drawPicture(picture);
  int numCommands = debugCanvas->getSize();

  DrawEvent event = {
    frame == 0 || dirty==layerBounds,            // fullRedraw
    nullptr,                                      // image
    std::move(debugCanvas),                       // debugCanvas
    numCommands-1,                                // command
    {layerBounds.width(), layerBounds.height()},  // layerBounds
  };

  fDraws.set(k, std::move(event));
  keys.push_back(k);
}

void DebugLayerManager::drawLayerEventTo(SkCanvas* canvas, const int nodeId, const int frame) {
    auto& evt = fDraws[{frame, nodeId}];
    evt.debugCanvas->drawTo(canvas, evt.command);
    canvas->flush();
}

sk_sp<SkImage> DebugLayerManager::getLayerAsImage(const int nodeId, const int frame) {
  // What is the last frame having an SkPicture for this layer? call it frame N
  // have cached image of it? if so, return it.
  // if not, draw it at frame N by the following method:
  // The picture at frame N could have been a full redraw, or it could have been clipped to a
  // dirty region. In order to know what the layer looked like on this frame, we must draw every
  // picture starting with the last full redraw, up to the last one before the current frame, since
  // any of those previous draws could be showing through.

  // list of frames this node was updated on.
  auto relevantFrames = listFramesForNode(nodeId);
  // find largest one not greater than `frame`.
  uint32_t i = relevantFrames.size()-1;
  while (relevantFrames[i] > frame) { i--; }
  const int frameN = relevantFrames[i];
  // Fetch the draw event
  auto& drawEvent = fDraws[{frameN, nodeId}];
  // if an image of this is cached, return it.
  if (drawEvent.image) {
    return drawEvent.image;
  }
  // when it's not cached, we'll have to render it in an offscreen surface.
  // start at the last full redraw. (pick up counting backwards from above)
  while (i>0 && !(fDraws[{relevantFrames[i], nodeId}].fullRedraw)) { i--; }
  // The correct layer bounds can be obtained from any drawEvent on this layer.
  // the color type and alpha type are chosen here to match wasm-skp-debugger/cpu.js which was
  // chosen to match the capabilities of HTML canvas, which this ultimately has to be drawn into.
  // TODO(nifong): introduce a method of letting the user choose the backend for this.
  auto surface = SkSurface::MakeRaster(SkImageInfo::Make(drawEvent.layerBounds,
    kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, nullptr));
  // draw everything from the last full redraw up to the current frame.
  // other frames drawn are partial, meaning they were clipped to not completely cover the layer.
  // count back up with i
  auto* canvas = surface->getCanvas();
  for (; i<relevantFrames.size() && relevantFrames[i]<=frameN; i++) {
    drawLayerEventTo(canvas, nodeId, relevantFrames[i]);
  }
  drawEvent.image = surface->makeImageSnapshot();
  return drawEvent.image;
}

DebugLayerManager::DrawEventSummary DebugLayerManager::event(int nodeId, int frame) const {
  auto* evt = fDraws.find({frame, nodeId});
  if (!evt) { return {}; }
  return {
    true, evt->debugCanvas->getSize(),
    evt->layerBounds.width(), evt->layerBounds.height()
  };
}

std::vector<DebugLayerManager::LayerSummary> DebugLayerManager::summarizeLayers(int frame) const {
  // Find the last update on or before `frame` for every node
  // key: nodeId, one entry for every layer
  // value: summary of the layer.
  std::unordered_map<int, LayerSummary> summaryMap;
  for (const auto& key : keys) {
    auto* evt = fDraws.find(key);
    if (!evt) { continue; }
    // -1 as a default value for the last update serves as a way of indicating that this layer
    // is present in the animation, but doesn't have an update less than or equal to `frame`
    int lastUpdate = (key.frame <= frame ? key.frame : -1);

    // do we have an entry for this layer yet? is it later than the one we're looking at?
    auto found = summaryMap.find(key.nodeId);
    if (found != summaryMap.end()) {
      LayerSummary& item = summaryMap[key.nodeId];
      if (lastUpdate > item.frameOfLastUpdate) {
        item.frameOfLastUpdate = key.frame;
        item.fullRedraw = evt->fullRedraw;
      }
    } else {
      // record first entry for this layer
      summaryMap.insert({key.nodeId, {
        key.nodeId, lastUpdate, evt->fullRedraw,
        evt->layerBounds.width(), evt->layerBounds.height()
      }});
    }
  }
  std::vector<LayerSummary> result;
  for (auto it = summaryMap.begin(); it != summaryMap.end(); ++it) {
    result.push_back(it->second);
  }
  return result;
}

std::vector<int> DebugLayerManager::listNodesForFrame(int frame) const {
  std::vector<int> result;
  for (const auto& key : keys) {
    if (key.frame == frame) {
      result.push_back(key.nodeId);
    }
  }
  return result;
}

std::vector<int> DebugLayerManager::listFramesForNode(int nodeId) const {
  std::vector<int> result;
  for (const auto& key : keys) {
    if (key.nodeId == nodeId) {
      result.push_back(key.frame);
    }
  }
  return result;
}

DebugCanvas* DebugLayerManager::getEventDebugCanvas(int nodeId, int frame) {
  auto& evt = fDraws[{frame, nodeId}];
  return evt.debugCanvas.get();
}

void DebugLayerManager::setOverdrawViz(bool overdrawViz) {
  for (const auto& key : keys) {
    auto& evt = fDraws[key];
    evt.debugCanvas->setOverdrawViz(overdrawViz);
  }
}

void DebugLayerManager::setClipVizColor(SkColor clipVizColor) {
  for (const auto& key : keys) {
    auto& evt = fDraws[key];
    evt.debugCanvas->setClipVizColor(clipVizColor);
  }
}

void DebugLayerManager::setDrawGpuOpBounds(bool drawGpuOpBounds) {
  for (const auto& key : keys) {
    auto& evt = fDraws[key];
    evt.debugCanvas->setDrawGpuOpBounds(drawGpuOpBounds);
  }
}
