/*
 * Copyright (C) 2007, 2008, 2010 Apple 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. 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 "core/html/HTMLSourceElement.h"

#include "core/HTMLNames.h"
#include "core/css/MediaList.h"
#include "core/css/MediaQueryList.h"
#include "core/css/MediaQueryMatcher.h"
#include "core/dom/Document.h"
#include "core/events/Event.h"
#include "core/events/EventSender.h"
#include "core/html/HTMLMediaElement.h"
#include "core/html/HTMLPictureElement.h"
#include "platform/Logging.h"

namespace blink {

static SourceEventSender& sourceErrorEventSender()
{
    DEFINE_STATIC_LOCAL(SourceEventSender, sharedErrorEventSender, (EventTypeNames::error));
    return sharedErrorEventSender;
}

class HTMLSourceElement::Listener FINAL : public MediaQueryListListener {
public:
    explicit Listener(HTMLSourceElement* element) : m_element(element) { }
    virtual void notifyMediaQueryChanged() OVERRIDE
    {
        if (m_element)
            m_element->notifyMediaQueryChanged();
    }

    void clearElement() { m_element = nullptr; }
    virtual void trace(Visitor* visitor) OVERRIDE
    {
        visitor->trace(m_element);
        MediaQueryListListener::trace(visitor);
    }
private:
    RawPtrWillBeMember<HTMLSourceElement> m_element;
};

inline HTMLSourceElement::HTMLSourceElement(Document& document)
    : HTMLElement(HTMLNames::sourceTag, document)
    , m_listener(adoptRefWillBeNoop(new Listener(this)))
{
    WTF_LOG(Media, "HTMLSourceElement::HTMLSourceElement - %p", this);
    ScriptWrappable::init(this);
}

DEFINE_NODE_FACTORY(HTMLSourceElement)

HTMLSourceElement::~HTMLSourceElement()
{
    sourceErrorEventSender().cancelEvent(this);
#if !ENABLE(OILPAN)
    m_listener->clearElement();
#endif
}

Node::InsertionNotificationRequest HTMLSourceElement::insertedInto(ContainerNode* insertionPoint)
{
    HTMLElement::insertedInto(insertionPoint);
    Element* parent = parentElement();
    if (isHTMLMediaElement(parent))
        toHTMLMediaElement(parent)->sourceWasAdded(this);
    if (isHTMLPictureElement(parent))
        toHTMLPictureElement(parent)->sourceOrMediaChanged();
    return InsertionDone;
}

void HTMLSourceElement::removedFrom(ContainerNode* removalRoot)
{
    Element* parent = parentElement();
    if (!parent && removalRoot->isElementNode())
        parent = toElement(removalRoot);
    if (isHTMLMediaElement(parent))
        toHTMLMediaElement(parent)->sourceWasRemoved(this);
    if (isHTMLPictureElement(parent))
        toHTMLPictureElement(parent)->sourceOrMediaChanged();
    HTMLElement::removedFrom(removalRoot);
}

void HTMLSourceElement::setSrc(const String& url)
{
    setAttribute(HTMLNames::srcAttr, AtomicString(url));
}

const AtomicString& HTMLSourceElement::type() const
{
    return getAttribute(HTMLNames::typeAttr);
}

void HTMLSourceElement::setType(const AtomicString& type)
{
    setAttribute(HTMLNames::typeAttr, type);
}

void HTMLSourceElement::scheduleErrorEvent()
{
    WTF_LOG(Media, "HTMLSourceElement::scheduleErrorEvent - %p", this);
    sourceErrorEventSender().dispatchEventSoon(this);
}

void HTMLSourceElement::cancelPendingErrorEvent()
{
    WTF_LOG(Media, "HTMLSourceElement::cancelPendingErrorEvent - %p", this);
    sourceErrorEventSender().cancelEvent(this);
}

void HTMLSourceElement::dispatchPendingEvent(SourceEventSender* eventSender)
{
    ASSERT_UNUSED(eventSender, eventSender == &sourceErrorEventSender());
    WTF_LOG(Media, "HTMLSourceElement::dispatchPendingEvent - %p", this);
    dispatchEvent(Event::createCancelable(EventTypeNames::error));
}

bool HTMLSourceElement::mediaQueryMatches() const
{
    if (!m_mediaQueryList)
        return true;

    return m_mediaQueryList->matches();
}

bool HTMLSourceElement::isURLAttribute(const Attribute& attribute) const
{
    return attribute.name() == HTMLNames::srcAttr || HTMLElement::isURLAttribute(attribute);
}

void HTMLSourceElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    HTMLElement::parseAttribute(name, value);
    if (name == HTMLNames::mediaAttr) {
        if (m_mediaQueryList)
            m_mediaQueryList->removeListener(m_listener);
        RefPtrWillBeRawPtr<MediaQuerySet> set = MediaQuerySet::create(value);
        m_mediaQueryList = MediaQueryList::create(&document(), &document().mediaQueryMatcher(), set.release());
        m_mediaQueryList->addListener(m_listener);
    }
    if (name == HTMLNames::srcsetAttr
        || name == HTMLNames::sizesAttr
        || name == HTMLNames::mediaAttr
        || name == HTMLNames::typeAttr) {
        Element* parent = parentElement();
        if (isHTMLPictureElement(parent))
            toHTMLPictureElement(parent)->sourceOrMediaChanged();
    }
}

void HTMLSourceElement::notifyMediaQueryChanged()
{
    Element* parent = parentElement();
    if (isHTMLPictureElement(parent))
        toHTMLPictureElement(parent)->sourceOrMediaChanged();
}

void HTMLSourceElement::trace(Visitor* visitor)
{
    visitor->trace(m_mediaQueryList);
    visitor->trace(m_listener);
    HTMLElement::trace(visitor);
}

}
