module Bullet

def add_safelist(options)

def add_safelist(options)
  reset_safelist
  @safelist[options[:type]][options[:class_name]] ||= []
  @safelist[options[:type]][options[:class_name]] << options[:association].to_sym
end

def app_root

Rails.root might be nil if `railties` is a dependency on a project that does not use Rails
def app_root
  @app_root ||= (defined?(::Rails.root) && !::Rails.root.nil? ? Rails.root.to_s : Dir.pwd).to_s
end

def build_request_uri(env)

def build_request_uri(env)
  return "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']}" if env['REQUEST_URI']
  if env['QUERY_STRING'].present?
    "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}?#{env['QUERY_STRING']}"
  else
    "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
  end
end

def bullet_logger=(active)

def bullet_logger=(active)
  if active
    require 'fileutils'
    FileUtils.mkdir_p(app_root + '/log')
    bullet_log_file = File.open("#{app_root}/log/bullet.log", 'a+')
    bullet_log_file.sync = true
    UniformNotifier.customized_logger = bullet_log_file
  end
end

def clear_safelist

def clear_safelist
  @safelist = nil
end

def console_enabled?

def console_enabled?
  UniformNotifier.active_notifiers.include?(UniformNotifier::JavascriptConsole)
end

def counter_cache_enable?

def counter_cache_enable?
  enable? && (@counter_cache_enable.nil? ? true : @counter_cache_enable)
end

def debug(title, message)

def debug(title, message)
  puts "[Bullet][#{title}] #{message}" if ENV['BULLET_DEBUG'] == 'true'
end

def delete_safelist(options)

def delete_safelist(options)
  reset_safelist
  @safelist[options[:type]][options[:class_name]] ||= []
  @safelist[options[:type]][options[:class_name]].delete(options[:association].to_sym)
  @safelist[options[:type]].delete_if { |_key, val| val.empty? }
end

def enable=(enable)

def enable=(enable)
  @enable = enable
  if enable?
    reset_safelist
    unless orm_patches_applied
      self.orm_patches_applied = true
      Bullet::Mongoid.enable if mongoid?
      Bullet::ActiveRecord.enable if active_record?
    end
  end
end

def enable?

def enable?
  !!@enable
end

def end_request

def end_request
  Thread.current.thread_variable_set(:bullet_start, nil)
  Thread.current.thread_variable_set(:bullet_notification_collector, nil)
  Thread.current.thread_variable_set(:bullet_object_associations, nil)
  Thread.current.thread_variable_set(:bullet_call_object_associations, nil)
  Thread.current.thread_variable_set(:bullet_possible_objects, nil)
  Thread.current.thread_variable_set(:bullet_impossible_objects, nil)
  Thread.current.thread_variable_set(:bullet_inversed_objects, nil)
  Thread.current.thread_variable_set(:bullet_eager_loadings, nil)
  Thread.current.thread_variable_set(:bullet_counter_possible_objects, nil)
  Thread.current.thread_variable_set(:bullet_counter_impossible_objects, nil)
end

def footer_info

def footer_info
  info = []
  notification_collector.collection.each { |notification| info << notification.short_notice }
  info
end

def for_each_active_notifier_with_notification

def for_each_active_notifier_with_notification
  UniformNotifier.active_notifiers.each do |notifier|
    notification_collector.collection.each do |notification|
      notification.notifier = notifier
      yield notification
    end
  end
end

def gather_inline_notifications

def gather_inline_notifications
  responses = []
  for_each_active_notifier_with_notification { |notification| responses << notification.notify_inline }
  responses.join("\n")
end

def get_safelist_associations(type, class_name)

def get_safelist_associations(type, class_name)
  Array.wrap(@safelist[type][class_name]).flat_map { |a| [a, a.to_s] }
end

def inject_into_page?

def inject_into_page?
  return false if defined?(@skip_html_injection) && @skip_html_injection
  console_enabled? || add_footer
end

def n_plus_one_query_enable?

def n_plus_one_query_enable?
  enable? && (@n_plus_one_query_enable.nil? ? true : @n_plus_one_query_enable)
end

def notification?

def notification?
  return unless start?
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
  notification_collector.notifications_present?
end

def notification_collector

def notification_collector
  Thread.current.thread_variable_get(:bullet_notification_collector)
end

def perform_out_of_channel_notifications(env = {})

def perform_out_of_channel_notifications(env = {})
  request_uri = build_request_uri(env)
  for_each_active_notifier_with_notification do |notification|
    notification.url = request_uri
    notification.notify_out_of_channel
  end
end

def profile

def profile
  return_value = nil
  if Bullet.enable?
    begin
      Bullet.start_request
      return_value = yield
      Bullet.perform_out_of_channel_notifications if Bullet.notification?
    ensure
      Bullet.end_request
    end
  else
    return_value = yield
  end
  return_value
end

def raise=(should_raise)

def raise=(should_raise)
  UniformNotifier.raise = (should_raise ? Notification::UnoptimizedQueryError : false)
end

def reset_safelist

def reset_safelist
  @safelist ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} }
end

def stacktrace_excludes

def stacktrace_excludes
  @stacktrace_excludes ||= []
end

def stacktrace_includes

def stacktrace_includes
  @stacktrace_includes ||= []
end

def start?

def start?
  enable? && Thread.current.thread_variable_get(:bullet_start)
end

def start_request

def start_request
  Thread.current.thread_variable_set(:bullet_start, true)
  Thread.current.thread_variable_set(:bullet_notification_collector, Bullet::NotificationCollector.new)
  Thread.current.thread_variable_set(:bullet_object_associations, Bullet::Registry::Base.new)
  Thread.current.thread_variable_set(:bullet_call_object_associations, Bullet::Registry::Base.new)
  Thread.current.thread_variable_set(:bullet_possible_objects, Bullet::Registry::Object.new)
  Thread.current.thread_variable_set(:bullet_impossible_objects, Bullet::Registry::Object.new)
  Thread.current.thread_variable_set(:bullet_inversed_objects, Bullet::Registry::Base.new)
  Thread.current.thread_variable_set(:bullet_eager_loadings, Bullet::Registry::Association.new)
  Thread.current.thread_variable_set(:bullet_call_stacks, Bullet::Registry::CallStack.new)
  unless Thread.current.thread_variable_get(:bullet_counter_possible_objects)
    Thread.current.thread_variable_set(:bullet_counter_possible_objects, Bullet::Registry::Object.new)
  end
  unless Thread.current.thread_variable_get(:bullet_counter_impossible_objects)
    Thread.current.thread_variable_set(:bullet_counter_impossible_objects, Bullet::Registry::Object.new)
  end
end

def text_notifications

def text_notifications
  info = []
  notification_collector.collection.each do |notification|
    info << notification.notification_data.values.compact.join("\n")
  end
  info
end

def unused_eager_loading_enable?

def unused_eager_loading_enable?
  enable? && (@unused_eager_loading_enable.nil? ? true : @unused_eager_loading_enable)
end

def warnings

def warnings
  notification_collector.collection.each_with_object({}) do |notification, warnings|
    warning_type = notification.class.to_s.split(':').last.tableize
    warnings[warning_type] ||= []
    warnings[warning_type] << notification
  end
end