# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# nocov start
.onLoad <- function(...) {
  register_vctrs_extension()

  s3_register("arrow::infer_type", "nanoarrow_array")
  s3_register("arrow::as_data_type", "nanoarrow_schema")
  s3_register("arrow::as_schema", "nanoarrow_schema")
  s3_register("arrow::as_arrow_array", "nanoarrow_array")
  s3_register("arrow::as_arrow_array", "nanoarrow_array_stream")
  s3_register("arrow::as_chunked_array", "nanoarrow_array")
  s3_register("arrow::as_chunked_array", "nanoarrow_array_stream")
  s3_register("arrow::as_record_batch", "nanoarrow_array")
  s3_register("arrow::as_arrow_table", "nanoarrow_array")
  s3_register("arrow::as_arrow_table", "nanoarrow_array_stream")
  s3_register("arrow::as_record_batch_reader", "nanoarrow_array_stream")

  s3_register("reticulate::r_to_py", "nanoarrow_schema")
  s3_register("reticulate::r_to_py", "nanoarrow_array")
  s3_register("reticulate::r_to_py", "nanoarrow_array_stream")
  s3_register("reticulate::py_to_r", "nanoarrow.schema.Schema")
  s3_register("reticulate::py_to_r", "nanoarrow.array.Array")
  s3_register("reticulate::py_to_r", "nanoarrow.array_stream.ArrayStream")

  s3_register("tibble::as_tibble", "nanoarrow_array")
}

# From the `vctrs` package (this function is intended to be copied
# without attribution or license requirements to avoid a hard dependency on
# vctrs:
# https://github.com/r-lib/vctrs/blob/c2a7710fe55e3a2249c4fdfe75bbccbafcf38804/R/register-s3.R#L25-L31
s3_register <- function(generic, class, method = NULL) {
  stopifnot(is.character(generic), length(generic) == 1)
  stopifnot(is.character(class), length(class) == 1)

  pieces <- strsplit(generic, "::")[[1]]
  stopifnot(length(pieces) == 2)
  package <- pieces[[1]]
  generic <- pieces[[2]]

  caller <- parent.frame()

  get_method_env <- function() {
    top <- topenv(caller)
    if (isNamespace(top)) {
      asNamespace(environmentName(top))
    } else {
      caller
    }
  }
  get_method <- function(method, env) {
    if (is.null(method)) {
      get(paste0(generic, ".", class), envir = get_method_env())
    } else {
      method
    }
  }

  register <- function(...) {
    envir <- asNamespace(package)

    # Refresh the method each time, it might have been updated by
    # `devtools::load_all()`
    method_fn <- get_method(method)
    stopifnot(is.function(method_fn))


    # Only register if generic can be accessed
    if (exists(generic, envir)) {
      registerS3method(generic, class, method_fn, envir = envir)
    } else if (identical(Sys.getenv("NOT_CRAN"), "true")) {
      warning(sprintf(
        "Can't find generic `%s` in package %s to register S3 method.",
        generic,
        package
      ))
    }
  }

  # Always register hook in case package is later unloaded & reloaded
  setHook(packageEvent(package, "onLoad"), register)

  # Avoid registration failures during loading (pkgload or regular)
  if (isNamespaceLoaded(package)) {
    register()
  }

  invisible()
}
# nocov end
