/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Peter Kelly (pmk@post.com)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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.
 *
 */

#pragma once

#include "Node.h"
#include "QualifiedName.h"

namespace WebCore {

class Attribute;
class CSSStyleDeclaration;
class MutableStyleProperties;

class Attr final : public Node {
    WTF_MAKE_ISO_ALLOCATED(Attr);
public:
    static Ref<Attr> create(Element&, const QualifiedName&);
    static Ref<Attr> create(Document&, const QualifiedName&, const AtomString& value);
    virtual ~Attr();

    String name() const { return qualifiedName().toString(); }
    bool specified() const { return true; }
    Element* ownerElement() const { return m_element; }

    WEBCORE_EXPORT const AtomString& value() const;
    WEBCORE_EXPORT void setValue(const AtomString&);

    const QualifiedName& qualifiedName() const { return m_name; }

    WEBCORE_EXPORT CSSStyleDeclaration* style();

    void attachToElement(Element&);
    void detachFromElementWithValue(const AtomString&);

    const AtomString& namespaceURI() const final { return m_name.namespaceURI(); }
    const AtomString& localName() const final { return m_name.localName(); }
    const AtomString& prefix() const final { return m_name.prefix(); }

private:
    Attr(Element&, const QualifiedName&);
    Attr(Document&, const QualifiedName&, const AtomString& value);

    String nodeName() const final { return name(); }
    NodeType nodeType() const final { return ATTRIBUTE_NODE; }

    String nodeValue() const final { return value(); }
    ExceptionOr<void> setNodeValue(const String&) final;

    ExceptionOr<void> setPrefix(const AtomString&) final;

    Ref<Node> cloneNodeInternal(Document&, CloningOperation) final;

    bool isAttributeNode() const final { return true; }

    Attribute& elementAttribute();

    // Attr wraps either an element/name, or a name/value pair (when it's a standalone Node.)
    // Note that m_name is always set, but m_element/m_standaloneValue may be null.
    Element* m_element { nullptr };
    QualifiedName m_name;
    AtomString m_standaloneValue;

    RefPtr<MutableStyleProperties> m_style;
};

} // namespace WebCore

SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Attr)
    static bool isType(const WebCore::Node& node) { return node.isAttributeNode(); }
SPECIALIZE_TYPE_TRAITS_END()
