/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/audio_processing/transient/file_utils.h"

#include "webrtc/base/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/file_wrapper.h"
#include "webrtc/typedefs.h"

namespace webrtc {

int ConvertByteArrayToFloat(const uint8_t bytes[4], float* out) {
  if (!bytes || !out) {
    return -1;
  }

  uint32_t binary_value = 0;
  for (int i = 3; i >= 0; --i) {
    binary_value <<= 8;
    binary_value += bytes[i];
  }

  *out = bit_cast<float>(binary_value);

  return 0;
}

int ConvertByteArrayToDouble(const uint8_t bytes[8], double* out) {
  if (!bytes || !out) {
    return -1;
  }

  uint64_t binary_value = 0;
  for (int i = 7; i >= 0; --i) {
    binary_value <<= 8;
    binary_value += bytes[i];
  }

  *out = bit_cast<double>(binary_value);

  return 0;
}

int ConvertFloatToByteArray(float value, uint8_t out_bytes[4]) {
  if (!out_bytes) {
    return -1;
  }

  uint32_t binary_value = bit_cast<uint32_t>(value);
  for (size_t i = 0; i < 4; ++i) {
    out_bytes[i] = binary_value;
    binary_value >>= 8;
  }

  return 0;
}

int ConvertDoubleToByteArray(double value, uint8_t out_bytes[8]) {
  if (!out_bytes) {
    return -1;
  }

  uint64_t binary_value = bit_cast<uint64_t>(value);
  for (size_t i = 0; i < 8; ++i) {
    out_bytes[i] = binary_value;
    binary_value >>= 8;
  }

  return 0;
}

size_t ReadInt16BufferFromFile(FileWrapper* file,
                               size_t length,
                               int16_t* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[2]);

  size_t int16s_read = 0;

  while (int16s_read < length) {
    size_t bytes_read = file->Read(byte_array.get(), 2);
    if (bytes_read < 2) {
      break;
    }
    int16_t value = byte_array[1];
    value <<= 8;
    value += byte_array[0];
    buffer[int16s_read] = value;
    ++int16s_read;
  }

  return int16s_read;
}

size_t ReadInt16FromFileToFloatBuffer(FileWrapper* file,
                                      size_t length,
                                      float* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<int16_t[]> buffer16(new int16_t[length]);

  size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get());

  for (size_t i = 0; i < int16s_read; ++i) {
    buffer[i] = buffer16[i];
  }

  return int16s_read;
}

size_t ReadInt16FromFileToDoubleBuffer(FileWrapper* file,
                                       size_t length,
                                       double* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<int16_t[]> buffer16(new int16_t[length]);

  size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get());

  for (size_t i = 0; i < int16s_read; ++i) {
    buffer[i] = buffer16[i];
  }

  return int16s_read;
}

size_t ReadFloatBufferFromFile(FileWrapper* file,
                               size_t length,
                               float* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[4]);

  size_t floats_read = 0;

  while (floats_read < length) {
    size_t bytes_read = file->Read(byte_array.get(), 4);
    if (bytes_read < 4) {
      break;
    }
    ConvertByteArrayToFloat(byte_array.get(), &buffer[floats_read]);
    ++floats_read;
  }

  return floats_read;
}

size_t ReadDoubleBufferFromFile(FileWrapper* file,
                                size_t length,
                                double* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[8]);

  size_t doubles_read = 0;

  while (doubles_read < length) {
    size_t bytes_read = file->Read(byte_array.get(), 8);
    if (bytes_read < 8) {
      break;
    }
    ConvertByteArrayToDouble(byte_array.get(), &buffer[doubles_read]);
    ++doubles_read;
  }

  return doubles_read;
}

size_t WriteInt16BufferToFile(FileWrapper* file,
                              size_t length,
                              const int16_t* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[2]);

  size_t int16s_written = 0;

  for (int16s_written = 0; int16s_written < length; ++int16s_written) {
    // Get byte representation.
    byte_array[0] = buffer[int16s_written] & 0xFF;
    byte_array[1] = (buffer[int16s_written] >> 8) & 0xFF;

    file->Write(byte_array.get(), 2);
  }

  file->Flush();

  return int16s_written;
}

size_t WriteFloatBufferToFile(FileWrapper* file,
                              size_t length,
                              const float* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[4]);

  size_t floats_written = 0;

  for (floats_written = 0; floats_written < length; ++floats_written) {
    // Get byte representation.
    ConvertFloatToByteArray(buffer[floats_written], byte_array.get());

    file->Write(byte_array.get(), 4);
  }

  file->Flush();

  return floats_written;
}

size_t WriteDoubleBufferToFile(FileWrapper* file,
                               size_t length,
                               const double* buffer) {
  if (!file || !file->Open() || !buffer || length <= 0) {
    return 0;
  }

  rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[8]);

  size_t doubles_written = 0;

  for (doubles_written = 0; doubles_written < length; ++doubles_written) {
    // Get byte representation.
    ConvertDoubleToByteArray(buffer[doubles_written], byte_array.get());

    file->Write(byte_array.get(), 8);
  }

  file->Flush();

  return doubles_written;
}

}  // namespace webrtc
