## parse_items.playlists.r

if (FALSE) 
{

  user.ids_test <- c("catmusickitty", 1238571019)
  DT.user_playlists_rick <- get_list_of_playlists.by_user(user.ids_test)
  DT.usermeta_rick <-  get_user_data(user.ids_test)


  colsToBring <- c(playist_associatedto_user.name = "user.display_name"
                , playist_associatedto_user.total_followers="user.total_followers")
  addColsFrom_(DT.user_playlists_rick, DT.usermeta_rick
      , joinCols.r="playist_associatedto_user.id"
      , joinCols.g="user.id"
      , colsToBring=colsToBring
  )


}


parse_items.playlists <- function(items
  , expected_fields=get_expected_fields(url_type)
  , url_type="list_of_playlists"
  , paginate=TRUE
  , api.timestamp=items$api.timestamp
  , api.itemshref=items$href
  , token=get_spotify_API_token()
  , envir.token=parent.frame()
  , verbose.fetching=TRUE
  , verbose.writing=TRUE
) {
## This function is generally not called directly, but instead called from get_playlist_data

  if ("error" %in% names(items)) {
    msg <- valueIfErrOrNull(sprintf("    \"%s\"", items$error$message), capture.output(items[["error"]]))
    stop("the incoming json to parse_items.playlists() contained the erorr message\n ------------------ \n", msg, "\n ------------------ ", call.=FALSE)
  }

  url_type %<>% match_url_type
  force(expected_fields)

  ## Check that token is not expired; if so, refresh it
  token %<>% confirm_spotify_token(envir=envir.token)

  ## ----------------------------------- RECURSE IF PAGINATABLE -------------------------- ##
  ## If what was passed to the function is a paginat'able section (ie, "items" is a subgroup of what was passed)
  ## then call the function on the appropriate 'items' and also if paginate is TRUE, recurse
  if (check_expected_fields(items, url_type="pagination", quiet=TRUE)) {

    ## collect all the arguments that are the same for recursion. 
    ARGS <- collectArgs(except=c("items", "api.timestamp", "api.itemshref"))

    ret  <- do.call(parse_items.playlists, args=c(ARGS, list(items=items[["items"]], api.timestamp=api.timestamp, api.itemshref=api.itemshref)))
    # using do.call #   ret2 <- parse_items.playlists(items[["items"]], expected_fields=expected_fields, paginate=paginate, api.timestamp=api.timestamp, api.itemshref=api.itemshref, token=token, verbose.fetching=TRUE, verbose.writing=TRUE)
    # using do.call #   cat("ret & ret2", ifelse(identical(ret, ret2), "ARE", "ARE NOT"), "identical\n")

    next_url <- items$`next`
    if (paginate && !is.null(next_url)) {

      next_items <- get_json_from_spotify_url(next_url, url_type="pagination", token=token, envir.token=envir.token, verbose.fetching=verbose.fetching, verbose.writing=verbose.writing)
      next_ret  <- do.call(parse_items.playlists, args=c(ARGS, list(items=next_items, api.timestamp=next_items$api.timestamp, api.itemshref=next_url)))
      # using do.call #   next_ret2 <- parse_items.playlists(next_items, api.timestamp=next_items$api.timestamp, api.itemshref=next_url, expected_fields=expected_fields, paginate=paginate, token=token, verbose.fetching=TRUE, verbose.writing=TRUE)
      # using do.call #   cat("next_ret & next_ret2", ifelse(identical(next_ret, next_ret2), "ARE", "ARE NOT"), "identical\n")

      ## ERROR CHECK
      if (!check_expected_fields(next_items, url_type="pagination"))
        warning("issue caused when parsing url = ", next_url, call.=TRUE)
      if (!identical(names(ret), names(next_ret)))
        warning("names are not identical for ret & next_ret for url = ", next_url, call.=TRUE)

      ## RETURN THE rbound DT
      return(rbind(ret, next_ret, fill=TRUE))
    }
    return(ret)
  }
  ## ----------------------------------- RECURSE IF PAGINATABLE -------------------------- ##
  

  ## ERROR CHECK
  names(expected_fields) <- expected_fields
  if (!confirm_length_of_items(items, element="items"))
    stop("Stopping because items are not all of uniform length.  (What to do with the extra or missing rows?)")
  if (!check_expected_fields(items, expected_fields=expected_fields))
    stop("Stopping because items were not as expected and thus parsing will be off. (What to do with the extra or missing field?)")

  ## Our expectations as far as multi-column elements
  multi_col_elements <- c("images", "owner", "tracks", "external_urls")
  single_col_elements <- setdiff(names(items), multi_col_elements)

  ## TODO: add saftey checks
  .multi_and_single_are_as_expected <- c(
        sapply(items[multi_col_elements], is.list)
      , sapply(items[single_col_elements], Negate(is.list))
  )
  if (any(!.multi_and_single_are_as_expected))
    warning ("Some multi/single elements are not as expected")


  ## not using from multi: 
  ##   images, external_urls, tracks$href (only total), owner$href, owner$uri (only id)
  ## not using from single:
  not_using <- c("href", "type", "uri")
  using <- setdiff(single_col_elements, not_using)

  DT.ret <- data.table(items[using]
                , owner.id         = valueIfErrOrNull(items$owner$id, NA_character_)
                , number_of_tracks = valueIfErrOrNull(items$tracks$total, NA_integer_)
                , api.itemshref    =   valueIfNull(api.itemshref, "")
                , api.timestamp    =   valueIfNull(api.timestamp, "")
            )

  needs_is <- c("collaborative", "public") %>% intersect(names(DT.ret))
  setnames(DT.ret, needs_is, paste0("is_", needs_is))

  colOrder <- c("id", "name", "owner.id", "number_of_tracks") %>% intersect(names(DT.ret))
  setcolorderpt(DT.ret, colOrder)

  setnames_addPreface(DT.ret, "playlist", ".")

  return(DT.ret)

} ## // close function
