// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base_view.h"

#include <lib/trace/event.h>
#include <lib/ui/scenic/cpp/commands.h>

#include <cmath>

namespace frame_compression {

namespace {

constexpr float kDisplayHeight = 50.0f;
constexpr float kInitialWindowXPos = 320.0f;
constexpr float kInitialWindowYPos = 240.0f;

// Inspect values.
constexpr char kBaseView[] = "base_view";
constexpr char kWidth[] = "width";
constexpr char kHeight[] = "height";

}  // namespace

BaseView::BaseView(scenic::ViewContext context, const std::string& debug_name, uint32_t width,
                   uint32_t height, inspect::Node inspect_node)
    : scenic::BaseView(std::move(context), debug_name),
      width_(width),
      height_(height),
      material_(session()),
      top_inspect_node_(std::move(inspect_node)),
      next_color_offset_(height / 2),
      node_(session()),
      inspect_node_(
          top_inspect_node_.CreateLazyValues(kBaseView, [this] { return PopulateStats(); })) {
  // Create a rectangle shape to display on.
  scenic::Rectangle shape(session(), static_cast<float>(width_), static_cast<float>(height_));

  node_.SetShape(shape);
  node_.SetMaterial(material_);
  root_node().AddChild(node_);

  // Translation of 0, 0 is the middle of the screen
  node_.SetTranslation(kInitialWindowXPos, kInitialWindowYPos, -kDisplayHeight);
}

png_structp BaseView::CreatePngReadStruct(FILE* png_fp, png_infop* info_ptr_ptr) {
  fseek(png_fp, 0, SEEK_SET);
  uint8_t header[8];
  fread(header, 1, 8, png_fp);
  FX_CHECK(png_sig_cmp(header, 0, 8) == 0) << "File is not recognized as a PNG file";
  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  FX_CHECK(png_ptr) << "png_create_read_struct failed";
  if (setjmp(png_jmpbuf(png_ptr))) {
    FX_CHECK(false) << "error during png_init_io";
  }
  png_init_io(png_ptr, png_fp);
  png_set_sig_bytes(png_ptr, 8);
  png_infop info_ptr = png_create_info_struct(png_ptr);
  FX_CHECK(info_ptr) << "png_create_info_struct failed";
  png_read_info(png_ptr, info_ptr);
  FX_CHECK(png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE);
  png_byte color_type = png_get_color_type(png_ptr, info_ptr);
  FX_CHECK(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
           color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY ||
           color_type == PNG_COLOR_TYPE_GRAY_ALPHA);
  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_palette_to_rgb(png_ptr);
  }
  if (color_type == PNG_COLOR_TYPE_GRAY) {
    png_set_expand_gray_1_2_4_to_8(png_ptr);
  }
  if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    png_set_gray_to_rgb(png_ptr);
  }
  png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
  png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
  if (bit_depth < 8) {
    png_set_packing(png_ptr);
  } else if (bit_depth == 16) {
    png_set_strip_16(png_ptr);
    png_set_swap(png_ptr);
  }
  *info_ptr_ptr = info_ptr;
  return png_ptr;
}

void BaseView::DestroyPngReadStruct(png_structp png_ptr, png_infop info_ptr) {
  png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
}

uint32_t BaseView::GetNextImageIndex() {
  const auto rv = next_image_index_;
  next_image_index_ = (next_image_index_ + 1) % kNumImages;
  return rv;
}

uint32_t BaseView::GetNextColorOffset() {
  const auto rv = next_color_offset_;
  next_color_offset_ = (next_color_offset_ + 1) % height_;
  return rv;
}

uint32_t BaseView::GetNextFrameNumber() {
  const auto rv = next_frame_number_;
  next_frame_number_ = next_frame_number_ + 1;
  return rv;
}

void BaseView::Animate(fuchsia::images::PresentationInfo presentation_info) {
  // Compute the amount of time that has elapsed since the view was created.
  float seconds = static_cast<float>(presentation_info.presentation_time) / 1'000'000'000;

  const float kHalfWidth = logical_size().x * 0.5f;
  const float kHalfHeight = logical_size().y * 0.5f;

  // Compute the translation for the window to swirl around the screen.
  node_.SetTranslation(kHalfWidth * (1.f + .1f * sin(seconds * 0.8f)),
                       kHalfHeight * (1.f + .1f * sin(seconds * 0.6f)), -kDisplayHeight);
}

fit::promise<inspect::Inspector> BaseView::PopulateStats() const {
  inspect::Inspector inspector;

  inspector.GetRoot().CreateUint(kWidth, width_, &inspector);
  inspector.GetRoot().CreateUint(kHeight, height_, &inspector);

  return fit::make_ok_promise(std::move(inspector));
}

}  // namespace frame_compression
