require "active_record"
require "friendly_id/base"
require "friendly_id/object_utils"
require "friendly_id/configuration"
require "friendly_id/finder_methods"

# @guide begin
#
# ## About FriendlyId
#
# FriendlyId is an add-on to Ruby's Active Record that allows you to replace ids
# in your URLs with strings:
#
#     # without FriendlyId
#     http://example.com/states/4323454
#
#     # with FriendlyId
#     http://example.com/states/washington
#
# It requires few changes to your application code and offers flexibility,
# performance and a well-documented codebase.
#
# ### Core Concepts
#
# #### Slugs
#
# The concept of *slugs* is at the heart of FriendlyId.
#
# A slug is the part of a URL which identifies a page using human-readable
# keywords, rather than an opaque identifier such as a numeric id. This can make
# your application more friendly both for users and search engines.
#
# #### Finders: Slugs Act Like Numeric IDs
#
# To the extent possible, FriendlyId lets you treat text-based identifiers like
# normal IDs. This means that you can perform finds with slugs just like you do
# with numeric ids:
#
#     Person.find(82542335)
#     Person.friendly.find("joe")
#
# @guide end
module FriendlyId
  autoload :History, "friendly_id/history"
  autoload :Slug, "friendly_id/slug"
  autoload :SimpleI18n, "friendly_id/simple_i18n"
  autoload :Reserved, "friendly_id/reserved"
  autoload :Scoped, "friendly_id/scoped"
  autoload :Slugged, "friendly_id/slugged"
  autoload :Finders, "friendly_id/finders"
  autoload :SequentiallySlugged, "friendly_id/sequentially_slugged"

  # FriendlyId takes advantage of `extended` to do basic model setup, primarily
  # extending {FriendlyId::Base} to add {FriendlyId::Base#friendly_id
  # friendly_id} as a class method.
  #
  # Previous versions of FriendlyId simply patched ActiveRecord::Base, but this
  # version tries to be less invasive.
  #
  # In addition to adding {FriendlyId::Base#friendly_id friendly_id}, the class
  # instance variable +@friendly_id_config+ is added. This variable is an
  # instance of an anonymous subclass of {FriendlyId::Configuration}. This
  # allows subsequently loaded modules like {FriendlyId::Slugged} and
  # {FriendlyId::Scoped} to add functionality to the configuration class only
  # for the current class, rather than monkey patching
  # {FriendlyId::Configuration} directly. This isolates other models from large
  # feature changes an addon to FriendlyId could potentially introduce.
  #
  # The upshot of this is, you can have two Active Record models that both have
  # a @friendly_id_config, but each config object can have different methods
  # and behaviors depending on what modules have been loaded, without
  # conflicts.  Keep this in mind if you're hacking on FriendlyId.
  #
  # For examples of this, see the source for {Scoped.included}.
  def self.extended(model_class)
    return if model_class.respond_to? :friendly_id
    class << model_class
      alias_method :relation_without_friendly_id, :relation
    end
    model_class.class_eval do
      extend Base
      @friendly_id_config = Class.new(Configuration).new(self)
      FriendlyId.defaults.call @friendly_id_config
      include Model
    end
  end

  # Allow developers to `include` FriendlyId or `extend` it.
  def self.included(model_class)
    model_class.extend self
  end

  # Set global defaults for all models using FriendlyId.
  #
  # The default defaults are to use the `:reserved` module and nothing else.
  #
  # @example
  #   FriendlyId.defaults do |config|
  #     config.base :name
  #     config.use :slugged
  #   end
  def self.defaults(&block)
    @defaults = block if block
    @defaults ||= ->(config) { config.use :reserved }
  end

  # Set the ActiveRecord table name prefix to friendly_id_
  #
  # This makes 'slugs' into 'friendly_id_slugs' and also respects any
  # 'global' table_name_prefix set on ActiveRecord::Base.
  def self.table_name_prefix
    "#{ActiveRecord::Base.table_name_prefix}friendly_id_"
  end
end
