/*
 * Copyright (C) 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 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 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 "modules/accessibility/AXMenuListOption.h"

#include "SkMatrix44.h"
#include "core/dom/AccessibleNode.h"
#include "core/html/HTMLSelectElement.h"
#include "modules/accessibility/AXMenuListPopup.h"
#include "modules/accessibility/AXObjectCacheImpl.h"

namespace blink {

using namespace HTMLNames;

AXMenuListOption::AXMenuListOption(HTMLOptionElement* element,
                                   AXObjectCacheImpl& ax_object_cache)
    : AXMockObject(ax_object_cache), element_(element) {}

AXMenuListOption::~AXMenuListOption() {
  DCHECK(!element_);
}

void AXMenuListOption::Detach() {
  element_ = nullptr;
  AXMockObject::Detach();
}

AccessibilityRole AXMenuListOption::RoleValue() const {
  const AtomicString& aria_role =
      GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole);
  if (aria_role.IsEmpty())
    return kMenuListOptionRole;

  AccessibilityRole role = AriaRoleToWebCoreRole(aria_role);
  if (role)
    return role;
  return kMenuListOptionRole;
}

Element* AXMenuListOption::ActionElement() const {
  return element_;
}

AXObjectImpl* AXMenuListOption::ComputeParent() const {
  Node* node = GetNode();
  if (!node)
    return nullptr;
  HTMLSelectElement* select = toHTMLOptionElement(node)->OwnerSelectElement();
  if (!select)
    return nullptr;
  AXObjectImpl* select_ax_object = AxObjectCache().GetOrCreate(select);
  if (select_ax_object->HasChildren()) {
    const auto& child_objects = select_ax_object->Children();
    DCHECK(!child_objects.IsEmpty());
    DCHECK_EQ(child_objects.size(), 1UL);
    DCHECK(child_objects[0]->IsMenuListPopup());
    ToAXMenuListPopup(child_objects[0].Get())->UpdateChildrenIfNecessary();
  } else {
    select_ax_object->UpdateChildrenIfNecessary();
  }
  return parent_.Get();
}

bool AXMenuListOption::IsEnabled() const {
  // isDisabledFormControl() returns true if the parent <select> element is
  // disabled, which we don't want.
  return element_ && !element_->OwnElementDisabled();
}

bool AXMenuListOption::IsVisible() const {
  if (!parent_)
    return false;

  // In a single-option select with the popup collapsed, only the selected
  // item is considered visible.
  return !parent_->IsOffScreen() || IsSelected();
}

bool AXMenuListOption::IsOffScreen() const {
  // Invisible list options are considered to be offscreen.
  return !IsVisible();
}

bool AXMenuListOption::IsSelected() const {
  AXMenuListPopup* parent = static_cast<AXMenuListPopup*>(ParentObject());
  if (parent && !parent->IsOffScreen())
    return parent->ActiveDescendant() == this;
  return element_ && element_->Selected();
}

void AXMenuListOption::SetSelected(bool b) {
  if (!element_ || !CanSetSelectedAttribute())
    return;

  element_->SetSelected(b);
}

bool AXMenuListOption::CanSetSelectedAttribute() const {
  return IsEnabled();
}

bool AXMenuListOption::ComputeAccessibilityIsIgnored(
    IgnoredReasons* ignored_reasons) const {
  return AccessibilityIsIgnoredByDefault(ignored_reasons);
}

void AXMenuListOption::GetRelativeBounds(
    AXObjectImpl** out_container,
    FloatRect& out_bounds_in_container,
    SkMatrix44& out_container_transform) const {
  *out_container = nullptr;
  out_bounds_in_container = FloatRect();
  out_container_transform.setIdentity();

  AXObjectImpl* parent = ParentObject();
  if (!parent)
    return;
  DCHECK(parent->IsMenuListPopup());

  AXObjectImpl* grandparent = parent->ParentObject();
  if (!grandparent)
    return;
  DCHECK(grandparent->IsMenuList());
  grandparent->GetRelativeBounds(out_container, out_bounds_in_container,
                                 out_container_transform);
}

String AXMenuListOption::TextAlternative(bool recursive,
                                         bool in_aria_labelled_by_traversal,
                                         AXObjectSet& visited,
                                         AXNameFrom& name_from,
                                         AXRelatedObjectVector* related_objects,
                                         NameSources* name_sources) const {
  // If nameSources is non-null, relatedObjects is used in filling it in, so it
  // must be non-null as well.
  if (name_sources)
    DCHECK(related_objects);

  if (!GetNode())
    return String();

  bool found_text_alternative = false;
  String text_alternative = AriaTextAlternative(
      recursive, in_aria_labelled_by_traversal, visited, name_from,
      related_objects, name_sources, &found_text_alternative);
  if (found_text_alternative && !name_sources)
    return text_alternative;

  name_from = kAXNameFromContents;
  text_alternative = element_->DisplayLabel();
  if (name_sources) {
    name_sources->push_back(NameSource(found_text_alternative));
    name_sources->back().type = name_from;
    name_sources->back().text = text_alternative;
    found_text_alternative = true;
  }

  return text_alternative;
}

DEFINE_TRACE(AXMenuListOption) {
  visitor->Trace(element_);
  AXMockObject::Trace(visitor);
}

}  // namespace blink
