/*
 * Copyright (C) 2010 Julien Chaffraix <jchaffraix@webkit.org>  All right reserved.
 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
 * OWNER OR 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"
#include "XMLHttpRequestProgressEventThrottle.h"

#include "EventNames.h"
#include "EventTarget.h"
#include "XMLHttpRequest.h"
#include "XMLHttpRequestProgressEvent.h"

namespace WebCore {

const Seconds XMLHttpRequestProgressEventThrottle::minimumProgressEventDispatchingInterval { 50_ms }; // 50 ms per specification.

XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(XMLHttpRequest& target)
    : m_target(target)
    , m_dispatchThrottledProgressEventTimer(target.scriptExecutionContext(), *this, &XMLHttpRequestProgressEventThrottle::dispatchThrottledProgressEventTimerFired)
{
    m_dispatchThrottledProgressEventTimer.suspendIfNeeded();
}

XMLHttpRequestProgressEventThrottle::~XMLHttpRequestProgressEventThrottle() = default;

void XMLHttpRequestProgressEventThrottle::updateProgress(bool isAsync, bool lengthComputable, unsigned long long loaded, unsigned long long total)
{
    m_lengthComputable = lengthComputable;
    m_loaded = loaded;
    m_total = total;

    if (!isAsync || !m_target.hasEventListeners(eventNames().progressEvent))
        return;

    if (!m_shouldDeferEventsDueToSuspension && !m_dispatchThrottledProgressEventTimer.isActive()) {
        // The timer is not active so the least frequent event for now is every byte. Just dispatch the event.

        // We should not have any throttled progress event.
        ASSERT(!m_hasPendingThrottledProgressEvent);

        dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, lengthComputable, loaded, total));
        m_dispatchThrottledProgressEventTimer.startRepeating(minimumProgressEventDispatchingInterval);
        m_hasPendingThrottledProgressEvent = false;
        return;
    }

    // The timer is already active so minimumProgressEventDispatchingInterval is the least frequent event.
    m_hasPendingThrottledProgressEvent = true;
}

void XMLHttpRequestProgressEventThrottle::dispatchReadyStateChangeEvent(Event& event, ProgressEventAction progressEventAction)
{
    if (progressEventAction == FlushProgressEvent)
        flushProgressEvent();

    dispatchEventWhenPossible(event);
}

void XMLHttpRequestProgressEventThrottle::dispatchEventWhenPossible(Event& event)
{
    if (m_shouldDeferEventsDueToSuspension)
        m_target.queueTaskToDispatchEvent(m_target, TaskSource::Networking, event);
    else
        m_target.dispatchEvent(event);
}

void XMLHttpRequestProgressEventThrottle::dispatchProgressEvent(const AtomString& type)
{
    ASSERT(type == eventNames().loadstartEvent || type == eventNames().progressEvent || type == eventNames().loadEvent || type == eventNames().loadendEvent || type == eventNames().abortEvent || type == eventNames().errorEvent || type == eventNames().timeoutEvent);

    if (type == eventNames().loadstartEvent) {
        m_lengthComputable = false;
        m_loaded = 0;
        m_total = 0;
    }

    if (m_target.hasEventListeners(type))
        dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(type, m_lengthComputable, m_loaded, m_total));
}

void XMLHttpRequestProgressEventThrottle::flushProgressEvent()
{
    if (!m_hasPendingThrottledProgressEvent)
        return;

    m_hasPendingThrottledProgressEvent = false;
    // We stop the timer as this is called when no more events are supposed to occur.
    m_dispatchThrottledProgressEventTimer.cancel();

    dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, m_lengthComputable, m_loaded, m_total));
}

void XMLHttpRequestProgressEventThrottle::dispatchThrottledProgressEventTimerFired()
{
    ASSERT(m_dispatchThrottledProgressEventTimer.isActive());
    if (!m_hasPendingThrottledProgressEvent) {
        // No progress event was queued since the previous dispatch, we can safely stop the timer.
        m_dispatchThrottledProgressEventTimer.cancel();
        return;
    }

    dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, m_lengthComputable, m_loaded, m_total));
    m_hasPendingThrottledProgressEvent = false;
}

void XMLHttpRequestProgressEventThrottle::suspend()
{
    m_shouldDeferEventsDueToSuspension = true;

    if (m_hasPendingThrottledProgressEvent) {
        m_target.queueTaskKeepingObjectAlive(m_target, TaskSource::Networking, [this] {
            flushProgressEvent();
        });
    }
}

void XMLHttpRequestProgressEventThrottle::resume()
{
    m_target.queueTaskKeepingObjectAlive(m_target, TaskSource::Networking, [this] {
        m_shouldDeferEventsDueToSuspension = false;
    });
}

} // namespace WebCore
