class Bj
  module ClassMethods
    attribute("rails_root"){ Util.const_or_env("RAILS_ROOT"){ "." } }
    attribute("rails_env"){ Util.const_or_env("RAILS_ENV"){ "development" } }
    attribute("database_yml"){ File.join rails_root, "config", "database.yml" }
    attribute("configurations"){ YAML.load IO.read(database_yml) }
    attribute("tables"){ Table.list }
    attribute("hostname"){ Socket.gethostname }
    attribute("logger"){ Bj::Logger.off STDERR }
    attribute("ruby"){ Util.which_ruby }
    attribute("script"){ Util.find_script "bj" }
    attribute("ttl"){ Integer(Bj::Table::Config["ttl"] || (twenty_four_hours = 24 * 60 * 60)) }
    attribute('table'){ Table }
    attribute('config'){ table.config }
    attribute('util'){ Util }
    attribute('runner'){ Runner }
    attribute('joblist'){ Joblist }

    def transaction options = {}, &block
      options.to_options!
      options.reverse_merge! :rails_env => Bj.rails_env
      bj_rails_env = Bj.rails_env
      begin
        Bj.rails_env = options[:rails_env].to_s
        connecting(options) do
          ActiveRecord::Base.transaction do 
            block.call ActiveRecord::Base.connection
          end
        end
      ensure
        Bj.rails_env = bj_rails_env 
      end
    end

    def connecting options = {}, &block
      options.to_options!
      rails_env = (options[:rails_env] || Bj.rails_env).to_s
      previous = ar_connection
      ActiveRecord::Base.connection = connections[rails_env] unless ActiveRecord::Base.connection == connections[rails_env]
      begin
        block.call ActiveRecord::Base.connection
      ensure
        ActiveRecord::Base.connection = previous unless ActiveRecord::Base.connection == previous
      end
    end

    def connections
      @connections ||= Hash.new do |hash, rails_env|
        rails_env = rails_env.to_s
        ActiveRecord::Base.establish_connection configurations[rails_env]
        hash[rails_env] = ActiveRecord::Base.connection
      end.merge(ar_connections)
      @connections
    end

    def ar_connections
      if defined?(RAILS_ENV)
        { RAILS_ENV => ar_connection } 
      else
        {}
      end
    end

    def ar_connection
      begin
        ActiveRecord::Base.connection
      rescue ActiveRecord::ConnectionNotEstablished 
        ActiveRecord::Base.establish_connection configurations[rails_env] 
      end
    end

    def chroot options = {}, &block
      if defined? @chrooted and @chrooted
        return block.call(@chrooted)
      end
      begin
        Dir.chdir @chrooted = rails_root do |pwd|
          raise RailsRoot, "<#{ pwd }> is not a rails root" unless Util.valid_rails_root?(pwd)
          block.call(@chrooted)
        end
      ensure
        @chrooted = nil 
      end
    end

    def boot
      load File.join(rails_root, "config", "boot.rb")
      load File.join(rails_root, "config", "environment.rb")
    end
  end
  send :extend, ClassMethods
end