// 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::media::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::media::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::media::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;
  }
}
