/*************************************************************************************
 * Original code copyright (C) 2012 Steve Folta
 * Converted to Juce module (C) 2016 Leo Olivers
 * Forked from https://github.com/stevefolta/SFZero
 * For license info please see the LICENSE file distributed with this source code
 *************************************************************************************/

#include "SFZSample.h"
#include "SFZDebug.h"

#if 0
#include "water/audioformat/AudioFormatManager.h"
#include "water/audioformat/AudioFormatReader.h"
#include "water/text/StringPairArray.h"
#else
extern "C" {
#include "audio_decoder/ad.h"
}
#endif

namespace sfzero
{

bool Sample::load()
{
#if 0
    static water::AudioFormatManager afm;
    static bool needsInit = true;
    if (needsInit)
    {
        needsInit = false;
        afm.registerBasicFormats();
    }

    water::AudioFormatReader* reader = afm.createReaderFor(file_);
    CARLA_SAFE_ASSERT_RETURN(reader != nullptr, false);

    sampleRate_ = reader->sampleRate;
    sampleLength_ = (water::uint64) reader->lengthInSamples;

    // Read some extra samples, which will be filled with zeros, so interpolation
    // can be done without having to check for the edge all the time.
    CARLA_SAFE_ASSERT_RETURN(sampleLength_ < std::numeric_limits<int>::max(), false);

    water::AudioSampleBuffer* buf = new water::AudioSampleBuffer((int) reader->numChannels, static_cast<int>(sampleLength_ + 4), true);
    reader->read(buf, 0, static_cast<int>(sampleLength_ + 4), 0, true, true);
    buffer_ = buf;

    water::StringPairArray *metadata = &reader->metadataValues;
    int numLoops = metadata->getValue("NumSampleLoops", "0").getIntValue();
    if (numLoops > 0)
    {
        loopStart_ = (water::uint64) metadata->getValue("Loop0Start", "0").getLargeIntValue();
        loopEnd_ = (water::uint64) metadata->getValue("Loop0End", "0").getLargeIntValue();
    }
    delete reader;
#else
    const water::String filename(file_.getFullPathName());

    struct adinfo info;
    carla_zeroStruct(info);

    void* const handle = ad_open(filename.toRawUTF8(), &info);
    CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false);

    if (info.frames >= std::numeric_limits<int>::max())
    {
        carla_stderr2("sfzero::Sample::load() - file is too big!");
        ad_close(handle);
        return false;
    }

    sampleRate_ = info.sample_rate;
    sampleLength_ = info.frames/info.channels;
    // TODO loopStart_, loopEnd_

    // read interleaved buffer
    float* const rbuffer = (float*)std::calloc(1, sizeof(float)*info.frames);

    if (rbuffer == nullptr)
    {
        carla_stderr2("sfzero::Sample::load() - out of memory");
        ad_close(handle);
        return false;
    }

    // Fix for misinformation using libsndfile
    if (info.frames % info.channels)
        --info.frames;

    const ssize_t r = ad_read(handle, rbuffer, info.frames);
    if (r != info.frames)
    {
        if (r != 0)
            carla_stderr2("sfzero::Sample::load() - failed to read complete file: " P_SSIZE " vs " P_INT64, r, info.frames);
        ad_close(handle);
        return false;
    }

    // NOTE: We add some extra samples, which will be filled with zeros,
    // so interpolation can be done without having to check for the edge all the time.

    buffer_ = new water::AudioSampleBuffer(info.channels, sampleLength_ + 4, true);

    for (int i=info.channels; --i >= 0;)
        buffer_->copyFromInterleavedSource(i, rbuffer, r);

    std::free(rbuffer);
    ad_close(handle);
#endif

    return true;
}

Sample::~Sample() { }

water::String Sample::getShortName() { return (file_.getFileName()); }

void Sample::setBuffer(water::AudioSampleBuffer *newBuffer)
{
  buffer_ = newBuffer;
  sampleLength_ = buffer_->getNumSamples();
}

water::AudioSampleBuffer *Sample::detachBuffer()
{
  return buffer_.release();
}

water::String Sample::dump() { return file_.getFullPathName() + "\n"; }

#ifdef DEBUG
void Sample::checkIfZeroed(const char *where)
{
  if (buffer_ == nullptr)
  {
    dbgprintf("SFZSample::checkIfZeroed(%s): no buffer!", where);
    return;
  }

  int samplesLeft = buffer_->getNumSamples();
  water::int64 nonzero = 0, zero = 0;
  const float *p = buffer_->getReadPointer(0);
  for (; samplesLeft > 0; --samplesLeft)
  {
    if (*p++ == 0.0)
    {
      zero += 1;
    }
    else
    {
      nonzero += 1;
    }
  }
  if (nonzero > 0)
  {
    dbgprintf("Buffer not zeroed at %s (%lu vs. %lu).", where, nonzero, zero);
  }
  else
  {
    dbgprintf("Buffer zeroed at %s!  (%lu zeros)", where, zero);
  }
}
#endif // DEBUG

}
