/*
 * Copyright (C) 2010, 2011, 2012 Igalia S.L.
 * Copyright (C) 2013 Samsung Electronics
 *
 * 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 "WebKitAccessibleHyperlink.h"

#if ENABLE(ACCESSIBILITY)

#include "AXObjectCache.h"
#include "AccessibilityObject.h"
#include "Editing.h"
#include "NotImplemented.h"
#include "Position.h"
#include "Range.h"
#include "RenderListMarker.h"
#include "RenderObject.h"
#include "TextIterator.h"
#include "WebKitAccessible.h"
#include "WebKitAccessibleUtil.h"
#include <wtf/glib/WTFGType.h>
#include <wtf/text/CString.h>

using namespace WebCore;

static void webkit_accessible_hyperlink_atk_action_interface_init(AtkActionIface*);

struct _WebKitAccessibleHyperlinkPrivate {
    WebKitAccessible* hyperlinkImpl;

    // We cache these values so we can return them as const values.
    CString actionName;
    CString actionKeyBinding;
};

WEBKIT_DEFINE_TYPE_WITH_CODE(
    WebKitAccessibleHyperlink, webkit_accessible_hyperlink, ATK_TYPE_HYPERLINK,
    G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, webkit_accessible_hyperlink_atk_action_interface_init))

enum {
    PROP_0,

    PROP_HYPERLINK_IMPL
};

static gboolean webkitAccessibleHyperlinkActionDoAction(AtkAction* action, gint)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, FALSE);

    if (!ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl))
        return FALSE;

    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
    return coreObject.performDefaultAction();
}

static gint webkitAccessibleHyperlinkActionGetNActions(AtkAction* action)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);

    return ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl) ? 1 : 0;
}

static const gchar* webkitAccessibleHyperlinkActionGetDescription(AtkAction* action, gint)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);

    // TODO: Need a way to provide/localize action descriptions.
    notImplemented();
    return "";
}

static const gchar* webkitAccessibleHyperlinkActionGetKeybinding(AtkAction* action, gint)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);

    if (!ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl))
        return nullptr;

    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
    accessibleHyperlink->priv->actionKeyBinding = coreObject.accessKey().utf8();
    return accessibleHyperlink->priv->actionKeyBinding.data();
}

static const gchar* webkitAccessibleHyperlinkActionGetName(AtkAction* action, gint)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);

    if (!ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl))
        return nullptr;

    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
    accessibleHyperlink->priv->actionName = coreObject.actionVerb().utf8();
    return accessibleHyperlink->priv->actionName.data();
}

static void webkit_accessible_hyperlink_atk_action_interface_init(AtkActionIface* iface)
{
    iface->do_action = webkitAccessibleHyperlinkActionDoAction;
    iface->get_n_actions = webkitAccessibleHyperlinkActionGetNActions;
    iface->get_description = webkitAccessibleHyperlinkActionGetDescription;
    iface->get_keybinding = webkitAccessibleHyperlinkActionGetKeybinding;
    iface->get_name = webkitAccessibleHyperlinkActionGetName;
}

static gchar* webkitAccessibleHyperlinkGetURI(AtkHyperlink* link, gint index)
{
    // FIXME: Do NOT support more than one instance of an AtkObject
    // implementing AtkHyperlinkImpl in every instance of AtkHyperLink
    if (index)
        return nullptr;

    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);

    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
    return !coreObject.url().isNull() ? g_strdup(coreObject.url().string().utf8().data()) : nullptr;
}

static AtkObject* webkitAccessibleHyperlinkGetObject(AtkHyperlink* link, gint index)
{
    // FIXME: Do NOT support more than one instance of an AtkObject
    // implementing AtkHyperlinkImpl in every instance of AtkHyperLink
    if (index)
        return nullptr;

    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);

    return ATK_OBJECT(accessibleHyperlink->priv->hyperlinkImpl);
}

static gint rangeLengthForObject(AccessibilityObject& obj, Range* range)
{
    // This is going to be the actual length in most of the cases
    int baseLength = TextIterator::rangeLength(range, { TextIteratorLengthOption::GenerateSpacesForReplacedElements });

    // Check whether the current hyperlink belongs to a list item.
    // If so, we need to consider the length of the item's marker
    AXCoreObject* parent = obj.parentObjectUnignored();
    if (!parent || !parent->isAccessibilityRenderObject() || !parent->isListItem())
        return baseLength;

    // Even if we don't expose list markers to Assistive
    // Technologies, we need to have a way to measure their length
    // for those cases when it's needed to take it into account
    // separately (as in getAccessibilityObjectForOffset)
    AXCoreObject* markerObj = parent->firstChild();
    if (!markerObj)
        return baseLength;

    RenderObject* renderer = markerObj->renderer();
    if (!is<RenderListMarker>(renderer))
        return baseLength;

    auto& marker = downcast<RenderListMarker>(*renderer);
    return baseLength + marker.text().length() + marker.suffix().length();
}

static gint webkitAccessibleHyperlinkGetStartIndex(AtkHyperlink* link)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);

    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
    AXCoreObject* parentUnignored = coreObject.parentObjectUnignored();
    if (!parentUnignored)
        return 0;

    Node* node = coreObject.node();
    if (!node)
        return 0;

    Node* parentNode = parentUnignored->node();
    if (!parentNode)
        return 0;

    auto range = Range::create(node->document(), firstPositionInOrBeforeNode(parentNode), firstPositionInOrBeforeNode(node));
    return rangeLengthForObject(coreObject, range.ptr());
}

static gint webkitAccessibleHyperlinkGetEndIndex(AtkHyperlink* link)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);

    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
    AXCoreObject* parentUnignored = coreObject.parentObjectUnignored();
    if (!parentUnignored)
        return 0;

    Node* node = coreObject.node();
    if (!node)
        return 0;

    Node* parentNode = parentUnignored->node();
    if (!parentNode)
        return 0;

    auto range = Range::create(node->document(), firstPositionInOrBeforeNode(parentNode), lastPositionInOrAfterNode(node));
    return rangeLengthForObject(coreObject, range.ptr());
}

static gboolean webkitAccessibleHyperlinkIsValid(AtkHyperlink* link)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, FALSE);

    // Link is valid for the whole object's lifetime
    return TRUE;
}

static gint webkitAccessibleHyperlinkGetNAnchors(AtkHyperlink* link)
{
    // FIXME Do NOT support more than one instance of an AtkObject
    // implementing AtkHyperlinkImpl in every instance of AtkHyperLink
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);

    return 1;
}

static gboolean webkitAccessibleHyperlinkIsSelectedLink(AtkHyperlink* link)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, FALSE);

    // Not implemented: this function is deprecated in ATK now
    notImplemented();
    return FALSE;
}

static void webkitAccessibleHyperlinkGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* pspec)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(object);

    switch (propId) {
    case PROP_HYPERLINK_IMPL:
        g_value_set_object(value, accessibleHyperlink->priv->hyperlinkImpl);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
    }
}

static void webkitAccessibleHyperlinkSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* pspec)
{
    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(object);

    switch (propId) {
    case PROP_HYPERLINK_IMPL:
        accessibleHyperlink->priv->hyperlinkImpl = WEBKIT_ACCESSIBLE(g_value_get_object(value));
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
    }
}

static void webkit_accessible_hyperlink_class_init(WebKitAccessibleHyperlinkClass* klass)
{
    GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
    gobjectClass->set_property = webkitAccessibleHyperlinkSetProperty;
    gobjectClass->get_property = webkitAccessibleHyperlinkGetProperty;

    AtkHyperlinkClass* atkHyperlinkClass = ATK_HYPERLINK_CLASS(klass);
    atkHyperlinkClass->get_uri = webkitAccessibleHyperlinkGetURI;
    atkHyperlinkClass->get_object = webkitAccessibleHyperlinkGetObject;
    atkHyperlinkClass->get_start_index = webkitAccessibleHyperlinkGetStartIndex;
    atkHyperlinkClass->get_end_index = webkitAccessibleHyperlinkGetEndIndex;
    atkHyperlinkClass->is_valid = webkitAccessibleHyperlinkIsValid;
    atkHyperlinkClass->get_n_anchors = webkitAccessibleHyperlinkGetNAnchors;
    atkHyperlinkClass->is_selected_link = webkitAccessibleHyperlinkIsSelectedLink;

    g_object_class_install_property(gobjectClass, PROP_HYPERLINK_IMPL,
        g_param_spec_object("hyperlink-impl",
            "Hyperlink implementation",
            "The associated WebKitAccessible instance.",
            WEBKIT_TYPE_ACCESSIBLE,
            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
}

WebKitAccessibleHyperlink* webkitAccessibleHyperlinkGetOrCreate(AtkHyperlinkImpl* hyperlinkImpl)
{
    g_return_val_if_fail(ATK_IS_HYPERLINK_IMPL(hyperlinkImpl), nullptr);
    g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(hyperlinkImpl), nullptr);

    if (auto* currentHyperLink = g_object_get_data(G_OBJECT(hyperlinkImpl), "webkit-accessible-hyperlink-object"))
        return WEBKIT_ACCESSIBLE_HYPERLINK(g_object_ref(currentHyperLink));

    auto* hyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(g_object_new(WEBKIT_TYPE_ACCESSIBLE_HYPERLINK, "hyperlink-impl", hyperlinkImpl, nullptr));
    g_object_set_data_full(G_OBJECT(hyperlinkImpl), "webkit-accessible-hyperlink-object", hyperlink, g_object_unref);
    return hyperlink;
}

#endif // ENABLE(ACCESSIBILITY)
