// Copyright 2018 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 "util.h"

#include <stdarg.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
#include <memory>

void Exit(const char* format, ...) {
  // Let's not have a buffer on the stack, not because it couldn't be done
  // safely, but because we'd potentially run into stack size vs. message length
  // tradeoffs, stack expansion granularity fun, or whatever else.

  va_list args;
  va_start(args, format);
  size_t buffer_bytes = vsnprintf(nullptr, 0, format, args) + 1;
  va_end(args);

  // ~buffer never actually runs since this method never returns
  std::unique_ptr<char[]> buffer(new char[buffer_bytes]);

  va_start(args, format);
  size_t buffer_bytes_2 =
      vsnprintf(buffer.get(), buffer_bytes, format, args) + 1;
  (void)buffer_bytes_2;
  // sanity check; should match so go ahead and assert that it does.
  assert(buffer_bytes == buffer_bytes_2);
  va_end(args);

  printf("%s - exiting\n", buffer.get());

  // If anything goes wrong, exit(-1) is used directly (until we have any reason
  // to do otherwise).
  exit(-1);
}

// This is obviously not how anyone would really stream a file, but this example
// program isn't about streaming a large media file.
std::unique_ptr<uint8_t[]> read_whole_file(const char* filename, size_t* size) {
  std::ifstream file;
  // std::ios::ate means start at the end to tellg() will get the size
  file.open(filename, std::ios::in | std::ios::binary | std::ios::ate);
  if (!file.is_open()) {
    Exit("failed to open file %s", filename);
  }
  std::streampos input_size = file.tellg();
  *size = input_size;
  if (input_size == -1) {
    Exit("file.tellg() failed");
  }
  VLOGF("file size is: %lld\n", static_cast<long long>(input_size));
  std::unique_ptr<uint8_t[]> raw_adts = std::make_unique<uint8_t[]>(input_size);
  file.seekg(0, std::ios::beg);
  if (!file) {
    Exit("file.seekg(0, beg) failed");
  }
  file.read(reinterpret_cast<char*>(raw_adts.get()), input_size);
  if (!file) {
    Exit("file.read() failed");
  }
  file.close();
  if (!file) {
    Exit("file.close() failed");
  }
  return raw_adts;
}

void PostSerial(async_dispatcher_t* dispatcher, fit::closure to_run) {
  zx_status_t post_result = async::PostTask(dispatcher, std::move(to_run));
  if (post_result != ZX_OK) {
    Exit("async::PostTask() failed - post_result: %d", post_result);
  }
}

void SHA256_Update_AudioParameters(SHA256_CTX* sha256_ctx,
                                   const fuchsia::mediacodec::PcmFormat& pcm) {
  uint32_t pcm_mode_le = htole32(pcm.pcm_mode);
  if (!SHA256_Update(sha256_ctx, &pcm_mode_le, sizeof(pcm_mode_le))) {
    assert(false);
  }
  uint32_t bits_per_sample_le = htole32(pcm.bits_per_sample);
  if (!SHA256_Update(sha256_ctx, &bits_per_sample_le,
                     sizeof(bits_per_sample_le))) {
    assert(false);
  }
  uint32_t frames_per_second_le = htole32(pcm.frames_per_second);
  if (!SHA256_Update(sha256_ctx, &frames_per_second_le,
                     sizeof(frames_per_second_le))) {
    assert(false);
  }
  for (fuchsia::mediacodec::AudioChannelId channel_id : *pcm.channel_map) {
    uint32_t channel_id_le = htole32(channel_id);
    if (!SHA256_Update(sha256_ctx, &channel_id_le, sizeof(channel_id_le))) {
      assert(false);
    }
  }
}

void SHA256_Update_VideoParameters(
    SHA256_CTX* sha256_ctx,
    const fuchsia::mediacodec::VideoUncompressedFormat& video) {
  UpdateSha256(sha256_ctx, video.fourcc);
  UpdateSha256(sha256_ctx, video.primary_width_pixels);
  UpdateSha256(sha256_ctx, video.primary_height_pixels);
  UpdateSha256(sha256_ctx, video.secondary_width_pixels);
  UpdateSha256(sha256_ctx, video.secondary_height_pixels);
  UpdateSha256(sha256_ctx, video.planar);
  UpdateSha256(sha256_ctx, video.swizzled);
  UpdateSha256(sha256_ctx, video.primary_line_stride_bytes);
  UpdateSha256(sha256_ctx, video.secondary_line_stride_bytes);
  UpdateSha256(sha256_ctx, video.primary_start_offset);
  UpdateSha256(sha256_ctx, video.secondary_start_offset);
  UpdateSha256(sha256_ctx, video.tertiary_start_offset);
  UpdateSha256(sha256_ctx, video.primary_pixel_stride);
  UpdateSha256(sha256_ctx, video.secondary_pixel_stride);
  UpdateSha256(sha256_ctx, video.special_formats.is_temp_field_todo_remove());
  UpdateSha256(sha256_ctx, video.special_formats.temp_field_todo_remove());
}

void SHA256_Update_VideoPlane(SHA256_CTX* sha256_ctx, uint8_t* start,
                              uint32_t width, uint32_t stride,
                              uint32_t height) {
  uint8_t* src = start;
  for (uint32_t row = 0; row < height; ++row) {
    SHA256_Update(sha256_ctx, src, width);
    src += stride;
  }
}
