// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "core/fpdfdoc/cpdf_formfield.h"

#include <map>
#include <memory>
#include <set>
#include <utility>

#include "constants/form_fields.h"
#include "constants/form_flags.h"
#include "core/fpdfapi/font/cpdf_font.h"
#include "core/fpdfapi/page/cpdf_docpagedata.h"
#include "core/fpdfapi/parser/cfdf_document.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_name.h"
#include "core/fpdfapi/parser/cpdf_number.h"
#include "core/fpdfapi/parser/cpdf_string.h"
#include "core/fpdfapi/parser/fpdf_parser_decode.h"
#include "core/fpdfapi/parser/fpdf_parser_utility.h"
#include "core/fpdfdoc/cpdf_defaultappearance.h"
#include "core/fpdfdoc/cpdf_formcontrol.h"
#include "core/fpdfdoc/cpdf_generateap.h"
#include "core/fpdfdoc/cpdf_interactiveform.h"
#include "third_party/base/check.h"
#include "third_party/base/stl_util.h"

namespace {

const CPDF_Object* GetFieldAttrRecursive(const CPDF_Dictionary* pFieldDict,
                                         const ByteString& name,
                                         int nLevel) {
  static constexpr int kGetFieldMaxRecursion = 32;
  if (!pFieldDict || nLevel > kGetFieldMaxRecursion)
    return nullptr;

  const CPDF_Object* pAttr = pFieldDict->GetDirectObjectFor(name);
  if (pAttr)
    return pAttr;

  return GetFieldAttrRecursive(
      pFieldDict->GetDictFor(pdfium::form_fields::kParent), name, nLevel + 1);
}

}  // namespace

// static
Optional<FormFieldType> CPDF_FormField::IntToFormFieldType(int value) {
  if (value >= static_cast<int>(FormFieldType::kUnknown) &&
      value < static_cast<int>(kFormFieldTypeCount)) {
    return {static_cast<FormFieldType>(value)};
  }
  return {};
}

// static
const CPDF_Object* CPDF_FormField::GetFieldAttr(
    const CPDF_Dictionary* pFieldDict,
    const ByteString& name) {
  return GetFieldAttrRecursive(pFieldDict, name, 0);
}

// static
CPDF_Object* CPDF_FormField::GetFieldAttr(CPDF_Dictionary* pFieldDict,
                                          const ByteString& name) {
  return const_cast<CPDF_Object*>(GetFieldAttrRecursive(
      static_cast<const CPDF_Dictionary*>(pFieldDict), name, 0));
}

// static
WideString CPDF_FormField::GetFullNameForDict(CPDF_Dictionary* pFieldDict) {
  WideString full_name;
  std::set<CPDF_Dictionary*> visited;
  CPDF_Dictionary* pLevel = pFieldDict;
  while (pLevel) {
    visited.insert(pLevel);
    WideString short_name = pLevel->GetUnicodeTextFor(pdfium::form_fields::kT);
    if (!short_name.IsEmpty()) {
      if (full_name.IsEmpty())
        full_name = std::move(short_name);
      else
        full_name = short_name + L'.' + full_name;
    }
    pLevel = pLevel->GetDictFor(pdfium::form_fields::kParent);
    if (pdfium::Contains(visited, pLevel))
      break;
  }
  return full_name;
}

CPDF_FormField::CPDF_FormField(CPDF_InteractiveForm* pForm,
                               CPDF_Dictionary* pDict)
    : m_pForm(pForm), m_pDict(pDict) {
  InitFieldFlags();
}

CPDF_FormField::~CPDF_FormField() = default;

void CPDF_FormField::InitFieldFlags() {
  const CPDF_Object* ft_attr =
      GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kFT);
  ByteString type_name = ft_attr ? ft_attr->GetString() : ByteString();
  uint32_t flags = GetFieldFlags();
  m_bRequired = flags & pdfium::form_flags::kRequired;
  m_bNoExport = flags & pdfium::form_flags::kNoExport;

  if (type_name == pdfium::form_fields::kBtn) {
    if (flags & pdfium::form_flags::kButtonRadio) {
      m_Type = kRadioButton;
      m_bIsUnison = flags & pdfium::form_flags::kButtonRadiosInUnison;
    } else if (flags & pdfium::form_flags::kButtonPushbutton) {
      m_Type = kPushButton;
    } else {
      m_Type = kCheckBox;
      m_bIsUnison = true;
    }
  } else if (type_name == pdfium::form_fields::kTx) {
    if (flags & pdfium::form_flags::kTextFileSelect)
      m_Type = kFile;
    else if (flags & pdfium::form_flags::kTextRichText)
      m_Type = kRichText;
    else
      m_Type = kText;
    LoadDA();
  } else if (type_name == pdfium::form_fields::kCh) {
    if (flags & pdfium::form_flags::kChoiceCombo) {
      m_Type = kComboBox;
    } else {
      m_Type = kListBox;
      m_bIsMultiSelectListBox = flags & pdfium::form_flags::kChoiceMultiSelect;
    }
    m_bUseSelectedIndices = UseSelectedIndicesObject();
    LoadDA();
  } else if (type_name == pdfium::form_fields::kSig) {
    m_Type = kSign;
  }
}

WideString CPDF_FormField::GetFullName() const {
  return GetFullNameForDict(m_pDict.Get());
}

bool CPDF_FormField::ResetField() {
  switch (m_Type) {
    case kCheckBox:
    case kRadioButton: {
      int iCount = CountControls();
      // TODO(weili): Check whether anything special needs to be done for
      // |m_bIsUnison|.
      for (int i = 0; i < iCount; i++) {
        CheckControl(i, GetControl(i)->IsDefaultChecked(),
                     NotificationOption::kDoNotNotify);
      }
      if (m_pForm->GetFormNotify())
        m_pForm->GetFormNotify()->AfterCheckedStatusChange(this);
      break;
    }
    case kComboBox:
    case kListBox: {
      ClearSelection(NotificationOption::kDoNotNotify);
      WideString csValue;
      int iIndex = GetDefaultSelectedItem();
      if (iIndex >= 0)
        csValue = GetOptionLabel(iIndex);
      if (!NotifyListOrComboBoxBeforeChange(csValue)) {
        return false;
      }
      SetItemSelection(iIndex, NotificationOption::kDoNotNotify);
      NotifyListOrComboBoxAfterChange();
      break;
    }
    case kText:
    case kRichText:
    case kFile:
    default: {
      const CPDF_Object* pDV = GetDefaultValueObject();
      WideString csDValue;
      if (pDV)
        csDValue = pDV->GetUnicodeText();

      WideString csValue;
      {
        // Limit the scope of |pV| because it may get invalidated below.
        const CPDF_Object* pV = GetValueObject();
        if (pV)
          csValue = pV->GetUnicodeText();
      }

      bool bHasRV = !!GetFieldAttr(m_pDict.Get(), "RV");
      if (!bHasRV && (csDValue == csValue))
        return false;

      if (!NotifyBeforeValueChange(csDValue)) {
        return false;
      }
      if (pDV) {
        RetainPtr<CPDF_Object> pClone = pDV->Clone();
        if (!pClone)
          return false;

        m_pDict->SetFor(pdfium::form_fields::kV, std::move(pClone));
        if (bHasRV) {
          m_pDict->SetFor("RV", pDV->Clone());
        }
      } else {
        m_pDict->RemoveFor(pdfium::form_fields::kV);
        m_pDict->RemoveFor("RV");
      }
      NotifyAfterValueChange();
      break;
    }
  }
  return true;
}

int CPDF_FormField::CountControls() const {
  return pdfium::CollectionSize<int>(GetControls());
}

CPDF_FormControl* CPDF_FormField::GetControl(int index) const {
  return GetControls()[index].Get();
}

int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const {
  if (!pControl)
    return -1;

  const auto& controls = GetControls();
  auto it = std::find(controls.begin(), controls.end(), pControl);
  return it != controls.end() ? it - controls.begin() : -1;
}

FormFieldType CPDF_FormField::GetFieldType() const {
  switch (m_Type) {
    case kPushButton:
      return FormFieldType::kPushButton;
    case kCheckBox:
      return FormFieldType::kCheckBox;
    case kRadioButton:
      return FormFieldType::kRadioButton;
    case kComboBox:
      return FormFieldType::kComboBox;
    case kListBox:
      return FormFieldType::kListBox;
    case kText:
    case kRichText:
    case kFile:
      return FormFieldType::kTextField;
    case kSign:
      return FormFieldType::kSignature;
    default:
      return FormFieldType::kUnknown;
  }
}

CPDF_AAction CPDF_FormField::GetAdditionalAction() const {
  CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kAA);
  return CPDF_AAction(pObj ? pObj->GetDict() : nullptr);
}

WideString CPDF_FormField::GetAlternateName() const {
  const CPDF_Object* pObj =
      GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kTU);
  return pObj ? pObj->GetUnicodeText() : WideString();
}

WideString CPDF_FormField::GetMappingName() const {
  const CPDF_Object* pObj =
      GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kTM);
  return pObj ? pObj->GetUnicodeText() : WideString();
}

uint32_t CPDF_FormField::GetFieldFlags() const {
  const CPDF_Object* pObj =
      GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kFf);
  return pObj ? pObj->GetInteger() : 0;
}

ByteString CPDF_FormField::GetDefaultStyle() const {
  const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "DS");
  return pObj ? pObj->GetString() : ByteString();
}

void CPDF_FormField::SetOpt(RetainPtr<CPDF_Object> pOpt) {
  m_pDict->SetFor("Opt", std::move(pOpt));
}

WideString CPDF_FormField::GetValue(bool bDefault) const {
  if (GetType() == kCheckBox || GetType() == kRadioButton)
    return GetCheckValue(bDefault);

  const CPDF_Object* pValue =
      bDefault ? GetDefaultValueObject() : GetValueObject();
  if (!pValue) {
    if (!bDefault && m_Type != kText)
      pValue = GetDefaultValueObject();
    if (!pValue)
      return WideString();
  }

  switch (pValue->GetType()) {
    case CPDF_Object::kString:
    case CPDF_Object::kStream:
      return pValue->GetUnicodeText();
    case CPDF_Object::kArray:
      pValue = pValue->AsArray()->GetDirectObjectAt(0);
      if (pValue)
        return pValue->GetUnicodeText();
      break;
    default:
      break;
  }
  return WideString();
}

WideString CPDF_FormField::GetValue() const {
  return GetValue(false);
}

WideString CPDF_FormField::GetDefaultValue() const {
  return GetValue(true);
}

bool CPDF_FormField::SetValue(const WideString& value,
                              bool bDefault,
                              NotificationOption notify) {
  switch (m_Type) {
    case kCheckBox:
    case kRadioButton: {
      SetCheckValue(value, bDefault, notify);
      return true;
    }
    case kFile:
    case kRichText:
    case kText:
    case kComboBox: {
      WideString csValue = value;
      if (notify == NotificationOption::kNotify &&
          !NotifyBeforeValueChange(csValue)) {
        return false;
      }
      ByteString key(bDefault ? pdfium::form_fields::kDV
                              : pdfium::form_fields::kV);
      m_pDict->SetNewFor<CPDF_String>(key, csValue);
      int iIndex = FindOption(csValue);
      if (iIndex < 0) {
        if (m_Type == kRichText && !bDefault) {
          m_pDict->SetFor("RV", m_pDict->GetObjectFor(key)->Clone());
        }
        m_pDict->RemoveFor("I");
      } else {
        if (!bDefault) {
          ClearSelection(NotificationOption::kDoNotNotify);
          SetItemSelection(iIndex, NotificationOption::kDoNotNotify);
        }
      }
      if (notify == NotificationOption::kNotify)
        NotifyAfterValueChange();
      break;
    }
    case kListBox: {
      int iIndex = FindOption(value);
      if (iIndex < 0)
        return false;

      if (bDefault && iIndex == GetDefaultSelectedItem())
        return false;

      if (notify == NotificationOption::kNotify &&
          !NotifyBeforeSelectionChange(value)) {
        return false;
      }
      if (!bDefault) {
        ClearSelection(NotificationOption::kDoNotNotify);
        SetItemSelection(iIndex, NotificationOption::kDoNotNotify);
      }
      if (notify == NotificationOption::kNotify)
        NotifyAfterSelectionChange();
      break;
    }
    default:
      break;
  }
  return true;
}

bool CPDF_FormField::SetValue(const WideString& value,
                              NotificationOption notify) {
  return SetValue(value, false, notify);
}

int CPDF_FormField::GetMaxLen() const {
  if (const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "MaxLen"))
    return pObj->GetInteger();

  for (auto& pControl : GetControls()) {
    if (!pControl)
      continue;

    const CPDF_Dictionary* pWidgetDict = pControl->GetWidget();
    if (pWidgetDict->KeyExist("MaxLen"))
      return pWidgetDict->GetIntegerFor("MaxLen");
  }
  return 0;
}

int CPDF_FormField::CountSelectedItems() const {
  const CPDF_Object* pValue = GetValueOrSelectedIndicesObject();
  if (!pValue)
    return 0;

  if (pValue->IsString() || pValue->IsNumber())
    return pValue->GetString().IsEmpty() ? 0 : 1;
  const CPDF_Array* pArray = pValue->AsArray();
  return pArray ? pArray->size() : 0;
}

int CPDF_FormField::GetSelectedIndex(int index) const {
  const CPDF_Object* pValue = GetValueOrSelectedIndicesObject();
  if (!pValue)
    return -1;

  if (pValue->IsNumber())
    return pValue->GetInteger();

  WideString sel_value;
  if (pValue->IsString()) {
    if (index != 0)
      return -1;
    sel_value = pValue->GetUnicodeText();
  } else {
    const CPDF_Array* pArray = pValue->AsArray();
    if (!pArray || index < 0)
      return -1;

    const CPDF_Object* elementValue = pArray->GetDirectObjectAt(index);
    sel_value = elementValue ? elementValue->GetUnicodeText() : WideString();
  }
  if (index < CountSelectedOptions()) {
    int iOptIndex = GetSelectedOptionIndex(index);
    WideString csOpt = GetOptionValue(iOptIndex);
    if (csOpt == sel_value)
      return iOptIndex;
  }
  for (int i = 0; i < CountOptions(); i++) {
    if (sel_value == GetOptionValue(i))
      return i;
  }
  return -1;
}

bool CPDF_FormField::ClearSelection(NotificationOption notify) {
  if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) {
    WideString csValue;
    int iIndex = GetSelectedIndex(0);
    if (iIndex >= 0)
      csValue = GetOptionLabel(iIndex);
    if (!NotifyListOrComboBoxBeforeChange(csValue))
      return false;
  }
  m_pDict->RemoveFor(pdfium::form_fields::kV);
  m_pDict->RemoveFor("I");
  if (notify == NotificationOption::kNotify)
    NotifyListOrComboBoxAfterChange();
  return true;
}

bool CPDF_FormField::IsItemSelected(int index) const {
  DCHECK(GetType() == kComboBox || GetType() == kListBox);
  if (index < 0 || index >= CountOptions())
    return false;

  // First consider the /I entry if it is valid, then fall back to the /V entry.
  return m_bUseSelectedIndices ? IsSelectedIndex(index)
                               : IsSelectedOption(GetOptionValue(index));
}

bool CPDF_FormField::SetItemSelection(int index, NotificationOption notify) {
  DCHECK(GetType() == kComboBox || GetType() == kListBox);
  if (index < 0 || index >= CountOptions())
    return false;

  WideString opt_value = GetOptionValue(index);
  if (notify == NotificationOption::kNotify &&
      !NotifyListOrComboBoxBeforeChange(opt_value)) {
    return false;
  }

  SetItemSelectionSelected(index, opt_value);

  // UseSelectedIndicesObject() has a non-trivial linearithmic run-time, so run
  // only if necessary.
  if (!m_bUseSelectedIndices)
    m_bUseSelectedIndices = UseSelectedIndicesObject();

  if (notify == NotificationOption::kNotify)
    NotifyListOrComboBoxAfterChange();
  return true;
}

void CPDF_FormField::SetItemSelectionSelected(int index,
                                              const WideString& opt_value) {
  if (GetType() != kListBox) {
    m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, opt_value);
    CPDF_Array* pI = m_pDict->SetNewFor<CPDF_Array>("I");
    pI->AppendNew<CPDF_Number>(index);
    return;
  }

  SelectOption(index, true, NotificationOption::kDoNotNotify);
  if (!m_bIsMultiSelectListBox) {
    m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, opt_value);
    return;
  }

  CPDF_Array* pArray = m_pDict->SetNewFor<CPDF_Array>(pdfium::form_fields::kV);
  for (int i = 0; i < CountOptions(); i++) {
    if (i == index || IsItemSelected(i))
      pArray->AppendNew<CPDF_String>(GetOptionValue(i));
  }
}

bool CPDF_FormField::IsItemDefaultSelected(int index) const {
  DCHECK(GetType() == kComboBox || GetType() == kListBox);
  if (index < 0 || index >= CountOptions())
    return false;
  int iDVIndex = GetDefaultSelectedItem();
  return iDVIndex >= 0 && iDVIndex == index;
}

int CPDF_FormField::GetDefaultSelectedItem() const {
  DCHECK(GetType() == kComboBox || GetType() == kListBox);
  const CPDF_Object* pValue = GetDefaultValueObject();
  if (!pValue)
    return -1;
  WideString csDV = pValue->GetUnicodeText();
  if (csDV.IsEmpty())
    return -1;
  for (int i = 0; i < CountOptions(); i++) {
    if (csDV == GetOptionValue(i))
      return i;
  }
  return -1;
}

int CPDF_FormField::CountOptions() const {
  const CPDF_Array* pArray = ToArray(GetFieldAttr(m_pDict.Get(), "Opt"));
  return pArray ? pArray->size() : 0;
}

WideString CPDF_FormField::GetOptionText(int index, int sub_index) const {
  const CPDF_Array* pArray = ToArray(GetFieldAttr(m_pDict.Get(), "Opt"));
  if (!pArray)
    return WideString();

  const CPDF_Object* pOption = pArray->GetDirectObjectAt(index);
  if (!pOption)
    return WideString();
  if (const CPDF_Array* pOptionArray = pOption->AsArray())
    pOption = pOptionArray->GetDirectObjectAt(sub_index);

  const CPDF_String* pString = ToString(pOption);
  return pString ? pString->GetUnicodeText() : WideString();
}

WideString CPDF_FormField::GetOptionLabel(int index) const {
  return GetOptionText(index, 1);
}

WideString CPDF_FormField::GetOptionValue(int index) const {
  return GetOptionText(index, 0);
}

int CPDF_FormField::FindOption(const WideString& csOptValue) const {
  for (int i = 0; i < CountOptions(); i++) {
    if (GetOptionValue(i) == csOptValue)
      return i;
  }
  return -1;
}

bool CPDF_FormField::CheckControl(int iControlIndex,
                                  bool bChecked,
                                  NotificationOption notify) {
  DCHECK(GetType() == kCheckBox || GetType() == kRadioButton);
  CPDF_FormControl* pControl = GetControl(iControlIndex);
  if (!pControl)
    return false;
  if (!bChecked && pControl->IsChecked() == bChecked)
    return false;

  const WideString csWExport = pControl->GetExportValue();
  int iCount = CountControls();
  for (int i = 0; i < iCount; i++) {
    CPDF_FormControl* pCtrl = GetControl(i);
    if (m_bIsUnison) {
      WideString csEValue = pCtrl->GetExportValue();
      if (csEValue == csWExport) {
        if (pCtrl->GetOnStateName() == pControl->GetOnStateName())
          pCtrl->CheckControl(bChecked);
        else if (bChecked)
          pCtrl->CheckControl(false);
      } else if (bChecked) {
        pCtrl->CheckControl(false);
      }
    } else {
      if (i == iControlIndex)
        pCtrl->CheckControl(bChecked);
      else if (bChecked)
        pCtrl->CheckControl(false);
    }
  }

  const CPDF_Object* pOpt = GetFieldAttr(m_pDict.Get(), "Opt");
  if (!ToArray(pOpt)) {
    ByteString csBExport = PDF_EncodeText(csWExport);
    if (bChecked) {
      m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, csBExport);
    } else {
      ByteString csV;
      const CPDF_Object* pV = GetValueObject();
      if (pV)
        csV = pV->GetString();
      if (csV == csBExport)
        m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, "Off");
    }
  } else if (bChecked) {
    m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV,
                                  ByteString::Format("%d", iControlIndex));
  }
  if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify())
    m_pForm->GetFormNotify()->AfterCheckedStatusChange(this);
  return true;
}

WideString CPDF_FormField::GetCheckValue(bool bDefault) const {
  DCHECK(GetType() == kCheckBox || GetType() == kRadioButton);
  WideString csExport = L"Off";
  int iCount = CountControls();
  for (int i = 0; i < iCount; i++) {
    CPDF_FormControl* pControl = GetControl(i);
    bool bChecked =
        bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked();
    if (bChecked) {
      csExport = pControl->GetExportValue();
      break;
    }
  }
  return csExport;
}

bool CPDF_FormField::SetCheckValue(const WideString& value,
                                   bool bDefault,
                                   NotificationOption notify) {
  DCHECK(GetType() == kCheckBox || GetType() == kRadioButton);
  int iCount = CountControls();
  for (int i = 0; i < iCount; i++) {
    CPDF_FormControl* pControl = GetControl(i);
    WideString csExport = pControl->GetExportValue();
    bool val = csExport == value;
    if (!bDefault) {
      CheckControl(GetControlIndex(pControl), val,
                   NotificationOption::kDoNotNotify);
    }
    if (val)
      break;
  }
  if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify())
    m_pForm->GetFormNotify()->AfterCheckedStatusChange(this);
  return true;
}

int CPDF_FormField::GetTopVisibleIndex() const {
  const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "TI");
  return pObj ? pObj->GetInteger() : 0;
}

int CPDF_FormField::CountSelectedOptions() const {
  const CPDF_Array* pArray = ToArray(GetSelectedIndicesObject());
  return pArray ? pArray->size() : 0;
}

int CPDF_FormField::GetSelectedOptionIndex(int index) const {
  const CPDF_Array* pArray = ToArray(GetSelectedIndicesObject());
  if (!pArray)
    return -1;

  int iCount = pArray->size();
  if (iCount < 0 || index >= iCount)
    return -1;
  return pArray->GetIntegerAt(index);
}

bool CPDF_FormField::IsSelectedOption(const WideString& wsOptValue) const {
  const CPDF_Object* pValueObject = GetValueObject();
  if (!pValueObject)
    return false;

  const CPDF_Array* pValueArray = pValueObject->AsArray();
  if (pValueArray) {
    CPDF_ArrayLocker locker(pValueArray);
    for (const auto& pObj : locker) {
      if (pObj->IsString() && pObj->GetUnicodeText() == wsOptValue)
        return true;
    }
  }

  return pValueObject->IsString() &&
         pValueObject->GetUnicodeText() == wsOptValue;
}

bool CPDF_FormField::IsSelectedIndex(int iOptIndex) const {
  const CPDF_Object* pSelectedIndicesObject = GetSelectedIndicesObject();
  if (!pSelectedIndicesObject)
    return false;

  const CPDF_Array* pSelectedIndicesArray = pSelectedIndicesObject->AsArray();
  if (pSelectedIndicesArray) {
    CPDF_ArrayLocker locker(pSelectedIndicesArray);
    for (const auto& pObj : locker) {
      if (pObj->IsNumber() && pObj->GetInteger() == iOptIndex)
        return true;
    }
  }

  return pSelectedIndicesObject->IsNumber() &&
         pSelectedIndicesObject->GetInteger() == iOptIndex;
}

bool CPDF_FormField::SelectOption(int iOptIndex,
                                  bool bSelected,
                                  NotificationOption notify) {
  CPDF_Array* pArray = m_pDict->GetArrayFor("I");
  if (!pArray) {
    if (!bSelected)
      return true;

    pArray = m_pDict->SetNewFor<CPDF_Array>("I");
  }

  bool bReturn = false;
  for (size_t i = 0; i < pArray->size(); i++) {
    int iFind = pArray->GetIntegerAt(i);
    if (iFind == iOptIndex) {
      if (bSelected)
        return true;

      if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) {
        WideString csValue = GetOptionLabel(iOptIndex);
        if (!NotifyListOrComboBoxBeforeChange(csValue))
          return false;
      }
      pArray->RemoveAt(i);
      bReturn = true;
      break;
    }

    if (iFind > iOptIndex) {
      if (!bSelected)
        continue;

      if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) {
        WideString csValue = GetOptionLabel(iOptIndex);
        if (!NotifyListOrComboBoxBeforeChange(csValue))
          return false;
      }
      pArray->InsertNewAt<CPDF_Number>(i, iOptIndex);
      bReturn = true;
      break;
    }
  }
  if (!bReturn) {
    if (bSelected)
      pArray->AppendNew<CPDF_Number>(iOptIndex);
    if (pArray->IsEmpty())
      m_pDict->RemoveFor("I");
  }
  if (notify == NotificationOption::kNotify)
    NotifyListOrComboBoxAfterChange();

  return true;
}

bool CPDF_FormField::UseSelectedIndicesObject() const {
  DCHECK(GetType() == kComboBox || GetType() == kListBox);

  const CPDF_Object* pSelectedIndicesObject = GetSelectedIndicesObject();
  if (!pSelectedIndicesObject)
    return false;

  // If there's not value object, then just use the indices object.
  const CPDF_Object* pValueObject = GetValueObject();
  if (!pValueObject)
    return true;

  // Verify that the selected indices object is either an array or a number and
  // count the number of indices.
  size_t selected_indices_size;
  const CPDF_Array* pSelectedIndicesArray = pSelectedIndicesObject->AsArray();
  if (pSelectedIndicesArray)
    selected_indices_size = pSelectedIndicesArray->size();
  else if (pSelectedIndicesObject->IsNumber())
    selected_indices_size = 1;
  else
    return false;

  // Verify that the number of values is equal to |selected_indices_size|. Then,
  // count the number of occurances of each of the distinct values in the values
  // object.
  std::map<WideString, size_t> values;
  const CPDF_Array* pValueArray = pValueObject->AsArray();
  if (pValueArray) {
    if (pValueArray->size() != selected_indices_size)
      return false;
    CPDF_ArrayLocker locker(pValueArray);
    for (const auto& pObj : locker) {
      if (pObj->IsString())
        values[pObj->GetUnicodeText()]++;
    }
  } else if (pValueObject->IsString()) {
    if (selected_indices_size != 1)
      return false;
    values[pValueObject->GetUnicodeText()]++;
  }

  // Validate each index in the selected indices object. Then, verify that items
  // identified by selected indices entry do not differ from those in the values
  // entry of the field dictionary.
  const int num_options = CountOptions();
  if (pSelectedIndicesArray) {
    CPDF_ArrayLocker locker(pSelectedIndicesArray);
    for (const auto& pObj : locker) {
      if (!pObj->IsNumber())
        return false;

      int index = pObj->GetInteger();
      if (index < 0 || index >= num_options)
        return false;

      WideString wsOptValue = GetOptionValue(index);
      auto it = values.find(wsOptValue);
      if (it == values.end())
        return false;

      it->second--;
      if (it->second == 0)
        values.erase(it);
    }

    return values.empty();
  }

  DCHECK(pSelectedIndicesObject->IsNumber());
  int index = pSelectedIndicesObject->GetInteger();
  if (index < 0 || index >= num_options)
    return false;

  return pdfium::Contains(values, GetOptionValue(index));
}

void CPDF_FormField::LoadDA() {
  CPDF_Dictionary* pFormDict = m_pForm->GetFormDict();
  if (!pFormDict)
    return;

  ByteString DA;
  if (const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "DA"))
    DA = pObj->GetString();

  if (DA.IsEmpty())
    DA = pFormDict->GetStringFor("DA");

  if (DA.IsEmpty())
    return;

  CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
  if (!pDR)
    return;

  CPDF_Dictionary* pFont = pDR->GetDictFor("Font");
  if (!ValidateFontResourceDict(pFont))
    return;

  CPDF_DefaultAppearance appearance(DA);
  Optional<ByteString> font_name = appearance.GetFont(&m_FontSize);
  if (!font_name)
    return;

  CPDF_Dictionary* pFontDict = pFont->GetDictFor(*font_name);
  if (!pFontDict)
    return;

  auto* pData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument());
  m_pFont = pData->GetFont(pFontDict);
}

bool CPDF_FormField::NotifyBeforeSelectionChange(const WideString& value) {
  auto* pNotify = m_pForm->GetFormNotify();
  return !pNotify || pNotify->BeforeSelectionChange(this, value);
}

void CPDF_FormField::NotifyAfterSelectionChange() {
  auto* pNotify = m_pForm->GetFormNotify();
  if (pNotify)
    pNotify->AfterSelectionChange(this);
}

bool CPDF_FormField::NotifyBeforeValueChange(const WideString& value) {
  auto* pNotify = m_pForm->GetFormNotify();
  return !pNotify || pNotify->BeforeValueChange(this, value);
}

void CPDF_FormField::NotifyAfterValueChange() {
  auto* pNotify = m_pForm->GetFormNotify();
  if (pNotify)
    pNotify->AfterValueChange(this);
}

bool CPDF_FormField::NotifyListOrComboBoxBeforeChange(const WideString& value) {
  switch (GetType()) {
    case kListBox:
      return NotifyBeforeSelectionChange(value);
    case kComboBox:
      return NotifyBeforeValueChange(value);
    default:
      return true;
  }
}

void CPDF_FormField::NotifyListOrComboBoxAfterChange() {
  switch (GetType()) {
    case kListBox:
      NotifyAfterSelectionChange();
      break;
    case kComboBox:
      NotifyAfterValueChange();
      break;
    default:
      break;
  }
}

const CPDF_Object* CPDF_FormField::GetDefaultValueObject() const {
  return GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kDV);
}

const CPDF_Object* CPDF_FormField::GetValueObject() const {
  return GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kV);
}

const CPDF_Object* CPDF_FormField::GetSelectedIndicesObject() const {
  DCHECK(GetType() == kComboBox || GetType() == kListBox);
  return GetFieldAttr(m_pDict.Get(), "I");
}

const CPDF_Object* CPDF_FormField::GetValueOrSelectedIndicesObject() const {
  DCHECK(GetType() == kComboBox || GetType() == kListBox);
  const CPDF_Object* pValue = GetValueObject();
  return pValue ? pValue : GetSelectedIndicesObject();
}

const std::vector<UnownedPtr<CPDF_FormControl>>& CPDF_FormField::GetControls()
    const {
  return m_pForm->GetControlsForField(this);
}
