// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_REGEX_PATTERNS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_REGEX_PATTERNS_H_

#include <stddef.h>
#include <stdint.h>

#include <optional>
#include <string_view>

#include "base/containers/span.h"
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
#include "components/autofill/core/browser/form_parsing/buildflags.h"
#include "components/autofill/core/common/language_code.h"

namespace autofill {

// A MatchPatternRef dereferences to a MatchingPattern.
class MatchPatternRef {
 public:
  MatchingPattern operator*() const;

 private:
  // Internally, a MatchPatternRef is represented as
  // - an index into the `kPatterns` array generated by
  //   transpile_regex_patterns.py, and
  // - a boolean that indicates whether the pattern is an ordinary or a
  //   supplementary one.
  //
  // An *ordinary* pattern corresponds exactly to an entry the JSON file.
  //
  // A *supplementary* pattern is an ordinary MatchingPattern which is
  // restricted to MatchAttribute::kName. That is, supplementary patterns only
  // apply to the field's HTML name, not to the field's user-visible label.
  //
  // We use this for English patterns: we augment non-English languages with the
  // English patterns, restricted to the MatchAttribute::kName. The motivation
  // is that the coding language also of non-English pages is often English.
  //
  // Representing the distinction between ordinary and supplementary patterns in
  // MatchPatternRef saves us from storing the supplementary MatchingPatterns
  // explicitly and saves some binary size.
  //
  // The dereferencing operator implements the restriction to
  // MatchAttribute::kName of supplementary MatchPatternRef.

  // We choose a small integer to save memory in the generated arrays.
  // Since the generated code passes integer literals to the constructor, the
  // compiler will catch if the UnderlyingType is not sufficiently large.
  using UnderlyingType = int16_t;

  // A wrapper of the constructor used by the code generation.
  friend constexpr MatchPatternRef MakeMatchPatternRef(bool is_supplementary,
                                                       UnderlyingType index);
  friend class MatchPatternRefTestApi;

  constexpr MatchPatternRef(bool supplementary, UnderlyingType index)
      : value_(supplementary ? -index - 1 : index) {}

  constexpr bool is_supplementary() const { return value_ < 0; }

  constexpr size_t index() const {
    return is_supplementary() ? -value_ - 1 : value_;
  }

  // Encodes both whether the pattern is_supplementary() and the index().
  UnderlyingType value_;
};

// The different sets of patterns available for parsing.
// Each enum constant corresponds to a JSON file.
enum class PatternFile : uint8_t {
#if !BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS)
  // Patterns whose stability is above suspicion.
  kLegacy,
  kMaxValue = kLegacy
#else
  kDefault,
  kMaxValue = kDefault
#endif
};

// The active file depend on the build config and enabled features. If the
// active `HeuristicSource` is not based on a JSON file, nullopt is returned.
std::optional<PatternFile> GetActivePatternFile();

// Looks up the patterns for the given name and language.
// The name is typically a field type.
//
// If there are no patterns for the given name and language, falls back to the
// union of all patterns for the given type (across all languages).
//
// Hits a CHECK if there are no patterns for the given name at all.
//
// The returned patterns are sorted by their MatchingPattern::positive_score in
// decreasing order.
base::span<const MatchPatternRef> GetMatchPatterns(std::string_view name,
                                                   LanguageCode language_code,
                                                   PatternFile pattern_file);

// Returns true iff there at least one pattern for some PatternSource and
// pattern name.
bool IsSupportedLanguageCode(LanguageCode language_code);

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_REGEX_PATTERNS_H_
