/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 * Copyright (C) 2003, 2008, 2009, 2010 Apple Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/html/HTMLBaseElement.h"

#include "core/HTMLNames.h"
#include "core/dom/Attribute.h"
#include "core/dom/Document.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/html/parser/TextResourceDecoder.h"

namespace blink {

using namespace HTMLNames;

inline HTMLBaseElement::HTMLBaseElement(Document& document)
    : HTMLElement(baseTag, document)
{
}

DEFINE_NODE_FACTORY(HTMLBaseElement)

void HTMLBaseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    if (name == hrefAttr || name == targetAttr)
        document().processBaseElement();
    else
        HTMLElement::parseAttribute(name, value);
}

Node::InsertionNotificationRequest HTMLBaseElement::insertedInto(ContainerNode* insertionPoint)
{
    HTMLElement::insertedInto(insertionPoint);
    if (insertionPoint->inDocument())
        document().processBaseElement();
    return InsertionDone;
}

void HTMLBaseElement::removedFrom(ContainerNode* insertionPoint)
{
    HTMLElement::removedFrom(insertionPoint);
    if (insertionPoint->inDocument())
        document().processBaseElement();
}

bool HTMLBaseElement::isURLAttribute(const Attribute& attribute) const
{
    return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
}

KURL HTMLBaseElement::href() const
{
    // This does not use the getURLAttribute function because that will resolve relative to the document's base URL;
    // base elements like this one can be used to set that base URL. Thus we need to resolve relative to the document's
    // URL and ignore the base URL.

    const AtomicString& attributeValue = fastGetAttribute(hrefAttr);
    if (attributeValue.isNull())
        return document().url();

    KURL url = document().encoding().isValid() ?
        KURL(document().url(), stripLeadingAndTrailingHTMLSpaces(attributeValue)) :
        KURL(document().url(), stripLeadingAndTrailingHTMLSpaces(attributeValue), document().encoding());

    if (!url.isValid())
        return KURL();

    return url;
}

void HTMLBaseElement::setHref(const AtomicString& value)
{
    setAttribute(hrefAttr, value);
}

}
