/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#if ENABLE(WEB_AUDIO)

#include "CachedAudio.h"

#include "AudioBuffer.h"
#include "AudioContext.h"
#include "Document.h"
#include "EventNames.h"
// #include "Frame.h"
#include "SharedBuffer.h"
#include "XMLHttpRequestProgressEvent.h"
#include <stdio.h>

namespace WebCore {

PassRefPtr<CachedAudio> CachedAudio::create(const String& url, AudioContext* context, Document* document, double bufferSampleRate, bool mixToMono)
{
    return adoptRef(new CachedAudio(url, context, document, bufferSampleRate, mixToMono));
}

CachedAudio::CachedAudio(const String& url, AudioContext* context, Document* document, double bufferSampleRate, bool mixToMono)
  : CachedResource(url, CachedResource::ImageResource /* need to define our own constant */   )
  , ActiveDOMObject(document, this)
  , m_context(context)
  , m_document(document)
  , m_mixToMono(mixToMono)
  , m_bufferSampleRate(bufferSampleRate)
  , m_buffer(0)
{
    fprintf(stderr, "%p: CachedAudio::CachedAudio() : url = %s : document = %p\n", this, url.utf8().data(), document );
    setStatus(Unknown);
    
    // TODO(crogers) : fix this HACK to avoid getting deleted in setRequest(NULL)
    // since we're also a ActiveDOMObject, it will try to garbage collect us.....
    increasePreloadCount();
}

CachedAudio::~CachedAudio()
{
}

void CachedAudio::send()
{
    setPendingActivity(this);
    // load(m_document->docLoader());
    load(m_document->cachedResourceLoader());
}

void CachedAudio::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
{
    if (errorOccurred())
        return;
    
    if (data.get())
    {
        const char *p = data->data();
        unsigned int dataSize = data->size();
        
    
        fprintf(stderr, "%p: CachedAudio::data() : p = %p : size = %d : allReceived = %d\n", this, p, dataSize, int(allDataReceived) );

        if (allDataReceived) {
            // Create AudioBuffer
            m_buffer = AudioBuffer::createFromAudioFileData(p, dataSize, m_mixToMono, m_bufferSampleRate);

            if (m_buffer.get() && m_context)
                m_context->refBuffer(m_buffer);
                
            if (!m_buffer.get()) {
                fprintf(stderr, "CachedAudio::data() : ERROR decoding audio data for %s\n", url().utf8().data());
                dispatchErrorEvent();
            }
                
            dispatchLoadEvent();
        }
    }
    else
    {
        fprintf(stderr, "CachedAudio::data() : NULL data : allReceived = %d\n", int(allDataReceived) );
        dispatchErrorEvent();
    }
}

void CachedAudio::error()
{
    fprintf(stderr, "CachedAudio::error() !!!!\n");
    dispatchErrorEvent();
}

void CachedAudio::didAddClient(CachedResourceClient*)
{
}

void CachedAudio::dispatchAbortEvent()
{
}

void CachedAudio::dispatchErrorEvent()
{
    dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().errorEvent));
}

void CachedAudio::dispatchLoadEvent()
{
    dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadEvent));
}

// ActiveDOMObject stuff...
bool CachedAudio::canSuspend() const
{
    return false; // FIXME: is this right?
}

void CachedAudio::stop()
{
}

void CachedAudio::contextDestroyed()
{
    ActiveDOMObject::contextDestroyed();
}

ScriptExecutionContext* CachedAudio::scriptExecutionContext() const
{
    return m_document;
}

EventTargetData* CachedAudio::eventTargetData()
{
    return &m_eventTargetData;
}

EventTargetData* CachedAudio::ensureEventTargetData()
{
    return &m_eventTargetData;
}

void CachedAudio::ref()
{
    RefCounted<CachedAudio>::ref();
}

void CachedAudio::deref()
{
    if (refCount() == 1)
        decreasePreloadCount(); // to offset increasePreloadCount() called in constructor.  Yes this is hacky, but better than leaking...
        
    RefCounted<CachedAudio>::deref();
}

void CachedAudio::refEventTarget()
{
    CachedAudio::ref();
}

void CachedAudio::derefEventTarget()
{
    CachedAudio::deref();
}

} // namespace WebCore

#endif // ENABLE(WEB_AUDIO)
