# encoding: utf-8
# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.

require 'new_relic/control/frameworks/ruby'
module NewRelic
  class Control
    module Frameworks
      # Control subclass instantiated when Rails is detected.  Contains
      # Rails specific configuration, instrumentation, environment values,
      # etc.
      class Rails < NewRelic::Control::Frameworks::Ruby

        def env
          @env ||= RAILS_ENV.dup
        end

        # Rails can return an empty string from this method, causing
        # the agent not to start even when it is properly in a rails 3
        # application, so we test the value to make sure it actually
        # has contents, and bail to the parent class if it is empty.
        def root
          root = rails_root.to_s
          if !root.empty?
            root
          else
            super
          end
        end

        def rails_root
          RAILS_ROOT if defined?(RAILS_ROOT)
        end

        def rails_config
          if defined?(::Rails) && ::Rails.respond_to?(:configuration)
            ::Rails.configuration
          else
            @config
          end
        end

        # In versions of Rails prior to 2.0, the rails config was only available to
        # the init.rb, so it had to be passed on from there.  This is a best effort to
        # find a config and use that.
        def init_config(options={})
          @config = options[:config]
          # Install the dependency detection,
          if rails_config && ::Rails.configuration.respond_to?(:after_initialize)
            rails_config.after_initialize do
              # This will insure we load all the instrumentation as late as possible.  If the agent
              # is not enabled, it will load a limited amount of instrumentation.
              DependencyDetection.detect!
            end
          end
          if !Agent.config[:agent_enabled]
            # Might not be running if it does not think mongrel, thin, passenger, etc
            # is running, if it thinks it's a rake task, or if the agent_enabled is false.
            ::NewRelic::Agent.logger.info("New Relic Agent not running.")
          else
            install_developer_mode(rails_config) if Agent.config[:developer_mode]
            install_browser_monitoring(rails_config)
            install_agent_hooks(rails_config)
          end
        rescue => e
          ::NewRelic::Agent.logger.error("Failure during init_config for Rails. Is Rails required in a non-Rails app? Set NEW_RELIC_FRAMEWORK=ruby to avoid this message.",
                                         "The Ruby agent will continue running, but Rails-specific features may be missing.",
                                         e)
        end

        def install_agent_hooks(config)
          return if @agent_hooks_installed
          @agent_hooks_installed = true
          return if config.nil? || !config.respond_to?(:middleware)
          begin
            require 'new_relic/rack/agent_hooks'
            return unless NewRelic::Rack::AgentHooks.needed?
            config.middleware.use NewRelic::Rack::AgentHooks
            ::NewRelic::Agent.logger.debug("Installed New Relic Agent Hooks middleware")
          rescue => e
            ::NewRelic::Agent.logger.warn("Error installing New Relic Agent Hooks middleware", e)
          end
        end

        def install_browser_monitoring(config)
          return if @browser_monitoring_installed
          @browser_monitoring_installed = true
          return if config.nil? || !config.respond_to?(:middleware) || !Agent.config[:'browser_monitoring.auto_instrument']
          begin
            require 'new_relic/rack/browser_monitoring'
            config.middleware.use NewRelic::Rack::BrowserMonitoring
            ::NewRelic::Agent.logger.debug("Installed New Relic Browser Monitoring middleware")
          rescue => e
            ::NewRelic::Agent.logger.warn("Error installing New Relic Browser Monitoring middleware", e)
          end
        end

        def install_developer_mode(rails_config)
          return if @installed
          @installed = true
          if rails_config && rails_config.respond_to?(:middleware)
            begin
              require 'new_relic/rack/developer_mode'
              rails_config.middleware.use NewRelic::Rack::DeveloperMode
              ::NewRelic::Agent.logger.info("New Relic Agent Developer Mode enabled.")
              if env == "production"
                ::NewRelic::Agent.logger.warn("***New Relic Developer Mode is not intended to be enabled in production environments! We highly recommend setting developer_mode: false for the production environment in your newrelic.yml.")
              end
            rescue => e
              ::NewRelic::Agent.logger.warn("Error installing New Relic Developer Mode", e)
            end
          elsif rails_config
            ::NewRelic::Agent.logger.warn("Developer mode not available for Rails versions prior to 2.2")
          end
        end

        def rails_version
          @rails_version ||= NewRelic::VersionNumber.new(::Rails::VERSION::STRING)
        end

        protected

        def rails_vendor_root
          File.join(root,'vendor','rails')
        end

        def install_shim
          super
          require 'new_relic/agent/instrumentation/controller_instrumentation'
          if ActiveSupport.respond_to?(:on_load) # rails 3+
            ActiveSupport.on_load(:action_controller) { include NewRelic::Agent::Instrumentation::ControllerInstrumentation::Shim }
          else
            ActionController::Base.class_eval { include NewRelic::Agent::Instrumentation::ControllerInstrumentation::Shim }
          end
        end
      end
    end
  end
end
