/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 * Copyright (C) 2011 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:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "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 THE COPYRIGHT
 * OWNER 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 "third_party/blink/renderer/core/html/forms/text_field_input_type.h"

#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/events/before_text_inserted_event.h"
#include "third_party/blink/renderer/core/events/drag_event.h"
#include "third_party/blink/renderer/core/events/keyboard_event.h"
#include "third_party/blink/renderer/core/events/mouse_event.h"
#include "third_party/blink/renderer/core/events/text_event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/forms/form_data.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/text_control_inner_elements.h"
#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/layout_details_marker.h"
#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class DataListIndicatorElement final : public HTMLDivElement {
 private:
  inline HTMLInputElement* HostInput() const {
    return To<HTMLInputElement>(OwnerShadowHost());
  }

  LayoutObject* CreateLayoutObject(const ComputedStyle&,
                                   LegacyLayout) override {
    UseCounter::Count(GetDocument(), WebFeature::kLegacyLayoutByDetailsMarker);
    return new LayoutDetailsMarker(this);
  }

  EventDispatchHandlingState* PreDispatchEventHandler(Event& event) override {
    // Chromium opens autofill popup in a mousedown event listener
    // associated to the document. We don't want to open it in this case
    // because we opens a datalist chooser later.
    // FIXME: We should dispatch mousedown events even in such case.
    if (event.type() == event_type_names::kMousedown)
      event.stopPropagation();
    return nullptr;
  }

  void DefaultEventHandler(Event& event) override {
    DCHECK(GetDocument().IsActive());
    if (event.type() != event_type_names::kClick)
      return;
    HTMLInputElement* host = HostInput();
    if (host && !host->IsDisabledOrReadOnly()) {
      GetDocument().GetPage()->GetChromeClient().OpenTextDataListChooser(*host);
      event.SetDefaultHandled();
    }
  }

  bool WillRespondToMouseClickEvents() override {
    return HostInput() && !HostInput()->IsDisabledOrReadOnly() &&
           GetDocument().IsActive();
  }

 public:
  DataListIndicatorElement(Document& document) : HTMLDivElement(document) {
    SetShadowPseudoId(AtomicString("-webkit-calendar-picker-indicator"));
    setAttribute(html_names::kIdAttr, shadow_element_names::kIdPickerIndicator);
  }
};

TextFieldInputType::TextFieldInputType(HTMLInputElement& element)
    : InputType(element), InputTypeView(element) {}

TextFieldInputType::~TextFieldInputType() = default;

void TextFieldInputType::Trace(Visitor* visitor) const {
  InputTypeView::Trace(visitor);
  InputType::Trace(visitor);
}

InputTypeView* TextFieldInputType::CreateView() {
  return this;
}

InputType::ValueMode TextFieldInputType::GetValueMode() const {
  return ValueMode::kValue;
}

SpinButtonElement* TextFieldInputType::GetSpinButtonElement() const {
  auto* element = GetElement().UserAgentShadowRoot()->getElementById(
      shadow_element_names::kIdSpinButton);
  CHECK(!element || IsA<SpinButtonElement>(element));
  return To<SpinButtonElement>(element);
}

bool TextFieldInputType::MayTriggerVirtualKeyboard() const {
  return true;
}

bool TextFieldInputType::IsTextField() const {
  return true;
}

bool TextFieldInputType::ValueMissing(const String& value) const {
  // For text-mode input elements, the value is missing only if it is mutable.
  // https://html.spec.whatwg.org/multipage/input.html#the-required-attribute
  return GetElement().IsRequired() && value.IsEmpty() &&
         !GetElement().IsDisabledOrReadOnly();
}

bool TextFieldInputType::CanSetSuggestedValue() {
  return true;
}

void TextFieldInputType::SetValue(const String& sanitized_value,
                                  bool value_changed,
                                  TextFieldEventBehavior event_behavior,
                                  TextControlSetValueSelection selection) {
  // We don't use InputType::setValue.  TextFieldInputType dispatches events
  // different way from InputType::setValue.
  if (event_behavior == TextFieldEventBehavior::kDispatchNoEvent)
    GetElement().SetNonAttributeValue(sanitized_value);
  else
    GetElement().SetNonAttributeValueByUserEdit(sanitized_value);

  // The following early-return can't be moved to the beginning of this
  // function. We need to update non-attribute value even if the value is not
  // changed.  For example, <input type=number> has a badInput string, that is
  // to say, IDL value=="", and new value is "", which should clear the badInput
  // string and update validiity.
  if (!value_changed)
    return;
  GetElement().UpdateView();

  if (selection == TextControlSetValueSelection::kSetSelectionToEnd) {
    unsigned max = VisibleValue().length();
    GetElement().SetSelectionRange(max, max);
  }

  switch (event_behavior) {
    case TextFieldEventBehavior::kDispatchChangeEvent:
      // If the user is still editing this field, dispatch an input event rather
      // than a change event.  The change event will be dispatched when editing
      // finishes.
      if (GetElement().IsFocused())
        GetElement().DispatchInputEvent();
      else
        GetElement().DispatchFormControlChangeEvent();
      break;

    case TextFieldEventBehavior::kDispatchInputEvent:
      GetElement().DispatchInputEvent();
      break;

    case TextFieldEventBehavior::kDispatchInputAndChangeEvent:
      GetElement().DispatchInputEvent();
      GetElement().DispatchFormControlChangeEvent();
      break;

    case TextFieldEventBehavior::kDispatchNoEvent:
      break;
  }
}

void TextFieldInputType::HandleKeydownEvent(KeyboardEvent& event) {
  if (!GetElement().IsFocused())
    return;
  if (ChromeClient* chrome_client = GetChromeClient()) {
    chrome_client->HandleKeyboardEventOnTextField(GetElement(), event);
    return;
  }
  event.SetDefaultHandled();
}

void TextFieldInputType::HandleKeydownEventForSpinButton(KeyboardEvent& event) {
  if (GetElement().IsDisabledOrReadOnly())
    return;
  const String& key = event.key();
  if (key == "ArrowUp")
    SpinButtonStepUp();
  else if (key == "ArrowDown" && !event.altKey())
    SpinButtonStepDown();
  else
    return;
  GetElement().DispatchFormControlChangeEvent();
  event.SetDefaultHandled();
}

void TextFieldInputType::ForwardEvent(Event& event) {
  if (SpinButtonElement* spin_button = GetSpinButtonElement()) {
    spin_button->ForwardEvent(event);
    if (event.DefaultHandled())
      return;
  }

  // Style and layout may be dirty at this point. E.g. if an event handler for
  // the input element has modified its type attribute. If so, the LayoutObject
  // and the input type is out of sync. Avoid accessing the LayoutObject if we
  // have scheduled a forced re-attach (GetForceReattachLayoutTree()) for the
  // input element.
  if (GetElement().GetLayoutObject() &&
      !GetElement().GetForceReattachLayoutTree() &&
      (IsA<MouseEvent>(event) || IsA<DragEvent>(event) ||
       event.HasInterface(event_interface_names::kWheelEvent) ||
       event.type() == event_type_names::kBlur ||
       event.type() == event_type_names::kFocus)) {
    if (event.type() == event_type_names::kBlur) {
      if (LayoutBox* inner_editor_layout_object =
              GetElement().InnerEditorElement()->GetLayoutBox()) {
        // FIXME: This class has no need to know about PaintLayer!
        if (PaintLayer* inner_layer = inner_editor_layout_object->Layer()) {
          if (PaintLayerScrollableArea* inner_scrollable_area =
                  inner_layer->GetScrollableArea()) {
            inner_scrollable_area->SetScrollOffset(
                ScrollOffset(0, 0), mojom::blink::ScrollType::kProgrammatic);
          }
        }
      }
    }

    GetElement().ForwardEvent(event);
  }
}

void TextFieldInputType::HandleBlurEvent() {
  InputTypeView::HandleBlurEvent();
  GetElement().EndEditing();
  if (SpinButtonElement* spin_button = GetSpinButtonElement())
    spin_button->ReleaseCapture();
}

bool TextFieldInputType::ShouldSubmitImplicitly(const Event& event) {
  return (event.type() == event_type_names::kTextInput &&
          event.HasInterface(event_interface_names::kTextEvent) &&
          To<TextEvent>(event).data() == "\n") ||
         InputTypeView::ShouldSubmitImplicitly(event);
}

void TextFieldInputType::CustomStyleForLayoutObject(ComputedStyle& style) {
  // The flag is necessary in order that a text field <input> with non-'visible'
  // overflow property doesn't change its baseline.
  style.SetShouldIgnoreOverflowPropertyForInlineBlockBaseline();
}

bool TextFieldInputType::TypeShouldForceLegacyLayout() const {
  if (RuntimeEnabledFeatures::LayoutNGTextControlEnabled())
    return false;
  UseCounter::Count(GetElement().GetDocument(),
                    WebFeature::kLegacyLayoutByTextControl);
  return true;
}

LayoutObject* TextFieldInputType::CreateLayoutObject(
    const ComputedStyle& style,
    LegacyLayout legacy) const {
  return LayoutObjectFactory::CreateTextControlSingleLine(GetElement(), style,
                                                          legacy);
}

void TextFieldInputType::CreateShadowSubtree() {
  DCHECK(IsShadowHost(GetElement()));
  ShadowRoot* shadow_root = GetElement().UserAgentShadowRoot();
  DCHECK(!shadow_root->HasChildren());

  bool should_have_spin_button = GetElement().IsSteppable();
  bool should_have_data_list_indicator = GetElement().HasValidDataListOptions();
  bool creates_container = should_have_spin_button ||
                           should_have_data_list_indicator || NeedsContainer();

  HTMLElement* inner_editor = GetElement().CreateInnerEditorElement();
  if (!creates_container) {
    shadow_root->AppendChild(inner_editor);
    return;
  }

  Document& document = GetElement().GetDocument();
  auto* container = MakeGarbageCollected<HTMLDivElement>(document);
  container->SetIdAttribute(shadow_element_names::kIdTextFieldContainer);
  container->SetShadowPseudoId(
      shadow_element_names::kPseudoTextFieldDecorationContainer);
  shadow_root->AppendChild(container);

  auto* editing_view_port =
      MakeGarbageCollected<EditingViewPortElement>(document);
  editing_view_port->AppendChild(inner_editor);
  container->AppendChild(editing_view_port);

  if (should_have_data_list_indicator) {
    container->AppendChild(
        MakeGarbageCollected<DataListIndicatorElement>(document));
  }
  // FIXME: Because of a special handling for a spin button in
  // LayoutTextControlSingleLine, we need to put it to the last position. It's
  // inconsistent with multiple-fields date/time types.
  if (should_have_spin_button) {
    container->AppendChild(
        MakeGarbageCollected<SpinButtonElement, Document&,
                             SpinButtonElement::SpinButtonOwner&>(document,
                                                                  *this));
  }

  // See listAttributeTargetChanged too.
}

Element* TextFieldInputType::ContainerElement() const {
  return GetElement().UserAgentShadowRoot()->getElementById(
      shadow_element_names::kIdTextFieldContainer);
}

void TextFieldInputType::DestroyShadowSubtree() {
  InputTypeView::DestroyShadowSubtree();
  if (SpinButtonElement* spin_button = GetSpinButtonElement())
    spin_button->RemoveSpinButtonOwner();
}

void TextFieldInputType::ListAttributeTargetChanged() {
  if (ChromeClient* chrome_client = GetChromeClient())
    chrome_client->TextFieldDataListChanged(GetElement());
  Element* picker = GetElement().UserAgentShadowRoot()->getElementById(
      shadow_element_names::kIdPickerIndicator);
  bool did_have_picker_indicator = picker;
  bool will_have_picker_indicator = GetElement().HasValidDataListOptions();
  if (did_have_picker_indicator == will_have_picker_indicator)
    return;
  EventDispatchForbiddenScope::AllowUserAgentEvents allow_events;
  if (will_have_picker_indicator) {
    Document& document = GetElement().GetDocument();
    if (Element* container = ContainerElement()) {
      container->InsertBefore(
          MakeGarbageCollected<DataListIndicatorElement>(document),
          GetSpinButtonElement());
    } else {
      // FIXME: The following code is similar to createShadowSubtree(),
      // but they are different. We should simplify the code by making
      // containerElement mandatory.
      auto* rp_container = MakeGarbageCollected<HTMLDivElement>(document);
      rp_container->SetIdAttribute(shadow_element_names::kIdTextFieldContainer);
      rp_container->SetShadowPseudoId(
          shadow_element_names::kPseudoTextFieldDecorationContainer);
      Element* inner_editor = GetElement().InnerEditorElement();
      inner_editor->parentNode()->ReplaceChild(rp_container, inner_editor);
      auto* editing_view_port =
          MakeGarbageCollected<EditingViewPortElement>(document);
      editing_view_port->AppendChild(inner_editor);
      rp_container->AppendChild(editing_view_port);
      rp_container->AppendChild(
          MakeGarbageCollected<DataListIndicatorElement>(document));
      if (GetElement().GetDocument().FocusedElement() == GetElement())
        GetElement().UpdateFocusAppearance(SelectionBehaviorOnFocus::kRestore);
    }
  } else {
    picker->remove(ASSERT_NO_EXCEPTION);
  }
}

void TextFieldInputType::ValueAttributeChanged() {
  UpdateView();
}

void TextFieldInputType::DisabledOrReadonlyAttributeChanged() {
  if (SpinButtonElement* spin_button = GetSpinButtonElement())
    spin_button->ReleaseCapture();
}

void TextFieldInputType::DisabledAttributeChanged() {
  DisabledOrReadonlyAttributeChanged();
}

void TextFieldInputType::ReadonlyAttributeChanged() {
  DisabledOrReadonlyAttributeChanged();
}

bool TextFieldInputType::SupportsReadOnly() const {
  return true;
}

static bool IsASCIILineBreak(UChar c) {
  return c == '\r' || c == '\n';
}

static String LimitLength(const String& string, unsigned max_length) {
  unsigned new_length = std::min(max_length, string.length());
  if (new_length == string.length())
    return string;
  if (new_length > 0 && U16_IS_LEAD(string[new_length - 1]))
    --new_length;
  return string.Left(new_length);
}

String TextFieldInputType::SanitizeValue(const String& proposed_value) const {
  return LimitLength(proposed_value.RemoveCharacters(IsASCIILineBreak),
                     std::numeric_limits<int>::max());
}

void TextFieldInputType::HandleBeforeTextInsertedEvent(
    BeforeTextInsertedEvent& event) {
  // Make sure that the text to be inserted will not violate the maxLength.

  // We use HTMLInputElement::innerEditorValue() instead of
  // HTMLInputElement::value() because they can be mismatched by
  // sanitizeValue() in HTMLInputElement::subtreeHasChanged() in some cases.
  unsigned old_length = GetElement().InnerEditorValue().length();

  // selectionLength represents the selection length of this text field to be
  // removed by this insertion.
  // If the text field has no focus, we don't need to take account of the
  // selection length. The selection is the source of text drag-and-drop in
  // that case, and nothing in the text field will be removed.
  unsigned selection_length = 0;
  if (GetElement().IsFocused()) {
    // TODO(editing-dev): Use of UpdateStyleAndLayout
    // needs to be audited.  See http://crbug.com/590369 for more details.
    GetElement().GetDocument().UpdateStyleAndLayout(
        DocumentUpdateReason::kEditing);

    selection_length = GetElement()
                           .GetDocument()
                           .GetFrame()
                           ->Selection()
                           .SelectedText()
                           .length();
  }
  DCHECK_GE(old_length, selection_length);

  // Selected characters will be removed by the next text event.
  unsigned base_length = old_length - selection_length;
  unsigned max_length;
  if (MaxLength() < 0)
    max_length = std::numeric_limits<int>::max();
  else
    max_length = static_cast<unsigned>(MaxLength());
  unsigned appendable_length =
      max_length > base_length ? max_length - base_length : 0;

  // Truncate the inserted text to avoid violating the maxLength and other
  // constraints.
  String event_text = event.GetText();
  unsigned text_length = event_text.length();
  while (text_length > 0 && IsASCIILineBreak(event_text[text_length - 1]))
    text_length--;
  event_text.Truncate(text_length);
  event_text.Replace("\r\n", " ");
  event_text.Replace('\r', ' ');
  event_text.Replace('\n', ' ');

  event.SetText(LimitLength(event_text, appendable_length));
}

bool TextFieldInputType::ShouldRespectListAttribute() {
  return true;
}

void TextFieldInputType::UpdatePlaceholderText(bool is_suggested_value) {
  if (!SupportsPlaceholder())
    return;
  HTMLElement* placeholder = GetElement().PlaceholderElement();
  String placeholder_text = GetElement().GetPlaceholderValue();
  if (placeholder_text.IsEmpty()) {
    if (placeholder)
      placeholder->remove(ASSERT_NO_EXCEPTION);
    return;
  }
  if (!placeholder) {
    auto* new_element =
        MakeGarbageCollected<HTMLDivElement>(GetElement().GetDocument());
    placeholder = new_element;
    placeholder->SetShadowPseudoId(
        shadow_element_names::kPseudoInputPlaceholder);
    placeholder->SetInlineStyleProperty(CSSPropertyID::kDisplay,
                                        GetElement().IsPlaceholderVisible()
                                            ? CSSValueID::kBlock
                                            : CSSValueID::kNone,
                                        true);
    placeholder->setAttribute(html_names::kIdAttr,
                              shadow_element_names::kIdPlaceholder);
    Element* container = ContainerElement();
    Node* previous = container ? container : GetElement().InnerEditorElement();
    previous->parentNode()->InsertBefore(placeholder, previous);
    SECURITY_DCHECK(placeholder->parentNode() == previous->parentNode());
  }
  if (is_suggested_value) {
    placeholder->SetInlineStyleProperty(CSSPropertyID::kUserSelect,
                                        CSSValueID::kNone, true);
  } else {
    placeholder->RemoveInlineStyleProperty(CSSPropertyID::kUserSelect);
  }
  placeholder->setTextContent(placeholder_text);
}

void TextFieldInputType::AppendToFormData(FormData& form_data) const {
  InputType::AppendToFormData(form_data);
  const AtomicString& dirname_attr_value =
      GetElement().FastGetAttribute(html_names::kDirnameAttr);
  if (!dirname_attr_value.IsNull()) {
    form_data.AppendFromElement(dirname_attr_value,
                                GetElement().DirectionForFormData());
  }
}

String TextFieldInputType::ConvertFromVisibleValue(
    const String& visible_value) const {
  return visible_value;
}

void TextFieldInputType::SubtreeHasChanged() {
  GetElement().SetValueFromRenderer(SanitizeUserInputValue(
      ConvertFromVisibleValue(GetElement().InnerEditorValue())));
  GetElement().UpdatePlaceholderVisibility();
  GetElement().PseudoStateChanged(CSSSelector::kPseudoValid);
  GetElement().PseudoStateChanged(CSSSelector::kPseudoInvalid);
  GetElement().PseudoStateChanged(CSSSelector::kPseudoInRange);
  GetElement().PseudoStateChanged(CSSSelector::kPseudoOutOfRange);

  DidSetValueByUserEdit();
}

void TextFieldInputType::DidSetValueByUserEdit() {
  if (!GetElement().IsFocused())
    return;
  if (ChromeClient* chrome_client = GetChromeClient())
    chrome_client->DidChangeValueInTextField(GetElement());
}

void TextFieldInputType::SpinButtonStepDown() {
  StepUpFromLayoutObject(-1);
}

void TextFieldInputType::SpinButtonStepUp() {
  StepUpFromLayoutObject(1);
}

void TextFieldInputType::UpdateView() {
  if (GetElement().SuggestedValue().IsEmpty() &&
      GetElement().NeedsToUpdateViewValue()) {
    // Update the view only if needsToUpdateViewValue is true. It protects
    // an unacceptable view value from being overwritten with the DOM value.
    //
    // e.g. <input type=number> has a view value "abc", and input.max is
    // updated. In this case, updateView() is called but we should not
    // update the view value.
    GetElement().SetInnerEditorValue(VisibleValue());
    GetElement().UpdatePlaceholderVisibility();
  }
}

void TextFieldInputType::FocusAndSelectSpinButtonOwner() {
  GetElement().focus();
  GetElement().SetSelectionRange(0, std::numeric_limits<int>::max());
}

bool TextFieldInputType::ShouldSpinButtonRespondToMouseEvents() {
  return !GetElement().IsDisabledOrReadOnly();
}

bool TextFieldInputType::ShouldSpinButtonRespondToWheelEvents() {
  return ShouldSpinButtonRespondToMouseEvents() && GetElement().IsFocused();
}

void TextFieldInputType::SpinButtonDidReleaseMouseCapture(
    SpinButtonElement::EventDispatch event_dispatch) {
  if (event_dispatch == SpinButtonElement::kEventDispatchAllowed)
    GetElement().DispatchFormControlChangeEvent();
}

}  // namespace blink
