module BreadcrumbTrail

  # A module to extend Controllers with.  It provides the main methods
  # that are used within the application, namely `breadcrumbs` and
  # `render_breadcrumbs`.
  module ActionController
    extend ActiveSupport::Concern

    included do
      include HelperMethods
      helper HelperMethods
      helper_method :breadcrumb, :breadcrumbs
    end

    # This extends a controller, providing the `breadcrumb` method to
    # the class as a method.
    module ClassMethods

      # Creates a before action that defines a breadcrumb before the
      # action takes place.  See {HelperMethods#breadcrumb}.
      #
      # @param (see HelperMethods#breadcrumb)
      # @return [void]
      def breadcrumb(options, &block)
        before_action(options.delete(:action) || {}) do
          breadcrumb(options, &block)
        end
      end
    end

    # This is both included in the controller and used as a helper,
    # so any methods defined here are usable in both the controller
    # and in the views.  These methods are the primary interface
    # that the developer uses to define and render breadcrumbs.
    module HelperMethods

      # Define a breadcrumb with the given options.  All of this
      # information is passed directly to the Breadcrumb initializer.
      #
      # @see Breadcrumb#initialize
      # @params options [Hash] A hash of options to pass directly to
      #   the Breadcrumb.
      # @yield
      # @return [void]
      def breadcrumb(options, &block)
        breadcrumbs << Breadcrumb.new(**options, &block)
      end

      # All of the defined breadcrumbs, in order.
      #
      # @return [Array<Breadcrumb>]
      def breadcrumbs
        @_breadcrumbs ||= []
      end

      # Renders the defined breadcrumbs, with the given options.
      #
      # @param options [Hash] The options that are passed to the
      #   builder to help render the breadcrumbs.
      # @option options [Hash] :builder (Builder) The builder to use.
      #   If this isn't provided, a sensible default is used.
      # @yield
      # @return [String]
      def render_breadcrumbs(options = {}, &block)
        block_given = block_given?
        builder = options.fetch(:builder) do
          if block_given
            BlockBuilder
          else
            HTMLBuilder
          end
        end

        builder.new(self, breadcrumbs, options, &block).call
      end

    end
  end
end