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

#include "tools/viewer/MSKPSlide.h"

#include "include/core/SkCanvas.h"
#include "include/core/SkStream.h"
#include "include/private/base/SkTPin.h"
#include "src/core/SkOSFile.h"
#include "imgui.h"

MSKPSlide::MSKPSlide(const SkString& name, const SkString& path)
        : MSKPSlide(name, SkStream::MakeFromFile(path.c_str())) {}

MSKPSlide::MSKPSlide(const SkString& name, std::unique_ptr<SkStreamSeekable> stream)
        : fStream(std::move(stream)) {
    fName = name;
}

SkISize MSKPSlide::getDimensions() const {
    return fPlayer ? fPlayer->maxDimensions() : SkISize{0, 0};
}

void MSKPSlide::draw(SkCanvas* canvas) {
    if (!fPlayer) {
        ImGui::Text("Could not read mskp file %s.\n", fName.c_str());
        return;
    }
    ImGui::Begin("MSKP");

    ImGui::BeginGroup();
    // Play/Pause button
    if (ImGui::Button(fPaused ? "Play " : "Pause")) {
        fPaused = !fPaused;
        if (fPaused) {
            // This will ensure that when playback is unpaused we start on the current frame.
            fLastFrameTime = -1;
        }
    }
    // Control the frame rate of MSKP playback
    ImGui::Text("FPS: ");                   ImGui::SameLine();
    ImGui::RadioButton(  "1", &fFPS,    1); ImGui::SameLine();
    ImGui::RadioButton( "15", &fFPS,   15); ImGui::SameLine();
    ImGui::RadioButton( "30", &fFPS,   30); ImGui::SameLine();
    ImGui::RadioButton( "60", &fFPS,   60); ImGui::SameLine();
    ImGui::RadioButton("120", &fFPS,  120); ImGui::SameLine();
    ImGui::RadioButton("1:1", &fFPS,   -1); // Draw one MSKP frame for each real viewer frame.
    if (fFPS < 0) {
        // Like above, will cause onAnimate() to resume at current frame when FPS is changed
        // back to another frame rate.
        fLastFrameTime = -1;
    }
    // Frame control. Slider and +/- buttons. Ctrl-Click slider to type frame number.
    ImGui::Text("Frame:");
    ImGui::SameLine();
    ImGui::PushButtonRepeat(true);  // Enable click-and-hold for frame arrows.
    int oldFrame = fFrame;
    if (ImGui::ArrowButton("-mksp_frame", ImGuiDir_Left)) {
        fFrame = (fFrame + fPlayer->numFrames() - 1)%fPlayer->numFrames();
    }
    ImGui::SameLine();
    if (ImGui::SliderInt("##msk_frameslider", &fFrame, 0, fPlayer->numFrames()-1, "% 3d")) {
        fFrame = SkTPin(fFrame, 0, fPlayer->numFrames() - 1);
    }
    ImGui::SameLine();
    if (ImGui::ArrowButton("+mskp_frame", ImGuiDir_Right)) {
        fFrame = (fFrame + 1)%fPlayer->numFrames();
    }
    if (fFrame != oldFrame) {
        // When manually adjusting frames force layers to redraw.
        this->redrawLayers();
    }

    ImGui::PopButtonRepeat();
    ImGui::EndGroup();

    ImGui::BeginGroup();
    ImGui::Checkbox("Show Frame Bounds", &fShowFrameBounds);
    ImGui::SetNextItemWidth(200);
    ImGui::ColorPicker4("background", fBackgroundColor, ImGuiColorEditFlags_AlphaBar);
    // ImGui lets user enter out of range values by typing.
    for (float& component : fBackgroundColor) {
        component = SkTPin(component, 0.f, 1.f);
    }
    ImGui::EndGroup();

    // UI for visualizing contents of offscreen layers.
    ImGui::Text("Offscreen Layers "); ImGui::SameLine();
    ImGui::Checkbox("List All Layers", &fListAllLayers);
    ImGui::RadioButton("root", &fDrawLayerID, -1);
    const std::vector<int>& layerIDs = fListAllLayers ? fAllLayerIDs : fFrameLayerIDs[fFrame];
    fLayerIDStrings.resize(layerIDs.size());
    for (size_t i = 0; i < layerIDs.size(); ++i) {
        fLayerIDStrings[i] = SkStringPrintf("%d", layerIDs[i]);
        ImGui::RadioButton(fLayerIDStrings[i].c_str(), &fDrawLayerID, layerIDs[i]);
    }
    ImGui::End();

    auto bounds = SkIRect::MakeSize(fPlayer->frameDimensions(fFrame));

    if (fShowFrameBounds) {
        SkPaint boundsPaint;
        boundsPaint.setStyle(SkPaint::kStroke_Style);
        boundsPaint.setColor(SK_ColorRED);
        boundsPaint.setStrokeWidth(0.f);
        boundsPaint.setAntiAlias(true);
        // Outset so that at default scale we draw at pixel centers of the rows/cols surrounding the
        // bounds.
        canvas->drawRect(SkRect::Make(bounds).makeOutset(0.5f, 0.5f), boundsPaint);
    }

    canvas->save();
    if (fDrawLayerID >= 0) {
        // clip out the root layer content, but still call playFrame so layer contents are updated
        // to fFrame.
        bounds = SkIRect::MakeEmpty();
    }
    canvas->clipIRect(bounds);
    canvas->clear(SkColor4f{fBackgroundColor[0],
                            fBackgroundColor[1],
                            fBackgroundColor[2],
                            fBackgroundColor[3]});
    fPlayer->playFrame(canvas, fFrame);
    canvas->restore();

    if (fDrawLayerID >= 0) {
        if (sk_sp<SkImage> layerImage = fPlayer->layerSnapshot(fDrawLayerID)) {
            canvas->save();
            canvas->clipIRect(SkIRect::MakeSize(layerImage->dimensions()));
            canvas->clear(SkColor4f{fBackgroundColor[0],
                                    fBackgroundColor[1],
                                    fBackgroundColor[2],
                                    fBackgroundColor[3]});
            canvas->drawImage(std::move(layerImage), 0, 0);
            canvas->restore();
        }
        return;
    }
}

bool MSKPSlide::animate(double nanos) {
    if (!fPlayer || fPaused) {
        return false;
    }
    if (fLastFrameTime < 0) {
        // We're coming off being paused or switching from 1:1 mode to steady FPS. Advance 1 frame
        // and reset the frame time to start accumulating time from now.
        fFrame = (fFrame + 1)%fPlayer->numFrames();
        fLastFrameTime = nanos;
        return this->fPlayer->numFrames() > 1;
    }
    if (fFPS < 0) {
        // 1:1 mode. Always draw the next frame on each animation cycle.
        fFrame = (fFrame + 1)%fPlayer->numFrames();
        return this->fPlayer->numFrames() > 1;
    }
    double elapsed = nanos - fLastFrameTime;
    double frameTime = 1E9/fFPS;
    int framesToAdvance = elapsed/frameTime;
    fFrame = fFrame + framesToAdvance;
    if (fFrame >= fPlayer->numFrames()) {
        this->redrawLayers();
    }
    fFrame %= fPlayer->numFrames();
    // Instead of just adding elapsed, note the time when this frame should have begun.
    fLastFrameTime += framesToAdvance*frameTime;
    return framesToAdvance > 0;
}

void MSKPSlide::load(SkScalar, SkScalar) {
    if (!fStream) {
        return;
    }
    fStream->rewind();
    fPlayer = MSKPPlayer::Make(fStream.get());
    if (!fPlayer) {
        return;
    }
    fAllLayerIDs = fPlayer->layerIDs();
    fFrameLayerIDs.clear();
    fFrameLayerIDs.resize(fPlayer->numFrames());
    for (int i = 0; i < fPlayer->numFrames(); ++i) {
        fFrameLayerIDs[i] = fPlayer->layerIDs(i);
    }
}

void MSKPSlide::unload() { fPlayer.reset(); }

void MSKPSlide::gpuTeardown() {
    if (fPlayer) {
        fPlayer->resetLayers();
    }
}

void MSKPSlide::redrawLayers() {
    if (fDrawLayerID >= 0) {
        // Completely reset the layers so that we won't see content from later frames on layers
        // that haven't been visited from frames 0..fFrames.
        fPlayer->resetLayers();
    } else {
        // Just rewind layers so that we redraw any layer from scratch on the next frame that
        // updates it. Important for benchmarking/profiling as otherwise if a layer is only
        // drawn once in the frame sequence then it will never be updated after the first play
        // through. This doesn't reallocate the layer backing stores.
        fPlayer->rewindLayers();
    }
}
