/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/SpeculationRuleSet.h"

#include "js/friend/ErrorMessages.h"
#include "mozilla/dom/PrefetchCandidates.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/speculationrules_ffi_generated.h"
#include "nsIURI.h"

namespace mozilla::dom {

/* static */ void SpeculationRuleSet::operator delete(
    void* aSpeculationRuleSet) {
  speculation_rule_set_destroy(
      reinterpret_cast<SpeculationRuleSet*>(aSpeculationRuleSet));
}

// https://html.spec.whatwg.org/#parse-a-speculation-rule-set-string
/* static */
Result<UniquePtr<SpeculationRuleSet>, SpeculationRuleParseError>
SpeculationRuleSet::Parse(const nsACString& aSource, nsIURI* aDocumentBaseUri,
                          nsIURI* aBaseUri) {
  MOZ_ASSERT(aDocumentBaseUri && aBaseUri);
  nsAutoCString documentBaseUri;
  aDocumentBaseUri->GetSpec(documentBaseUri);
  nsAutoCString baseUri;
  aBaseUri->GetSpec(baseUri);

  SpeculationRuleParseError parseError = SpeculationRuleParseError::None;
  SpeculationRuleSet* parsedRuleSet = parse_speculation_rule_set(
      &aSource, &documentBaseUri, &baseUri, &parseError);
  if (!parsedRuleSet) {
    // Steps 2 and 5.1
    return Err(parseError);
  }
  return UniquePtr<SpeculationRuleSet>(parsedRuleSet);
}

/* static */ void SpeculationRuleSet::ReportParseError(
    nsIGlobalObject* aGlobal, SpeculationRuleParseError aError) {
  MOZ_ASSERT(aGlobal);
  MOZ_ASSERT(aError != SpeculationRuleParseError::None);
  AutoJSAPI jsapi;
  if (!jsapi.Init(aGlobal)) {
    return;
  }
  JSErrNum errorNumber = JSMSG_SPECULATION_RULES_NOT_A_MAP;
  switch (aError) {
    case SpeculationRuleParseError::TopLevelValueMustBeJsonObject:
      errorNumber = JSMSG_SPECULATION_RULES_NOT_A_MAP;
      break;
    case SpeculationRuleParseError::InvalidTag:
      errorNumber = JSMSG_SPECULATION_RULES_INVALID_TAG;
      break;
    case SpeculationRuleParseError::InvalidBaseUrl:
      errorNumber = JSMSG_SPECULATION_RULES_INVALID_BASE_URL;
      break;
    case SpeculationRuleParseError::None:
      MOZ_ASSERT_UNREACHABLE();
      return;
  }
  JS_ReportErrorNumberASCII(jsapi.cx(), js::GetErrorMessage, nullptr,
                            errorNumber);
}

void SpeculationRuleSet::ConsiderLoads(PrefetchCandidates* aCandidates) {
  consider_speculative_loads_for_rule_set(this, aCandidates);
}

}  // namespace mozilla::dom
