module Sunspot #:nodoc:
  module Rails #:nodoc:
    # 
    # This module provides Sunspot Adapter implementations for Mongoid
    # models.
    #
    module Mongoid
      def self.included(base)
        base.class_eval do
          extend Sunspot::Rails::Searchable::ActsAsMethods
          Sunspot::Adapters::DataAccessor.register(Sunspot::Rails::Adapters::MongoidDataAccessor, base)
          Sunspot::Adapters::InstanceAdapter.register(Sunspot::Rails::Adapters::MongoidInstanceAdapter, base)
        end
      end
    end

    module Adapters
      class MongoidInstanceAdapter < Sunspot::Adapters::InstanceAdapter
        # 
        # Return the primary key for the adapted instance
        #
        # ==== Returns
        # 
        # Integer:: Database ID of model
        #
        def id
          @instance.id
        end
      end

      class MongoidDataAccessor < Sunspot::Adapters::DataAccessor
        # options for the find
        attr_accessor :select

        #
        # Set the fields to select from the database. This will be passed
        # to Mongoid.
        #
        # ==== Parameters
        #
        # value<Array>:: array of columns
        #
        def select=(value)
          @select = value
        end
        
        # 
        # Get one Mongoid document instance out of the database by ID
        #
        # ==== Parameters
        #
        # id<String>:: Database ID of model to retreive
        #
        # ==== Returns
        #
        # Mongoid model
        # 
        def load(id)
          @clazz.find(BSON::ObjectID.from_string(id)) rescue nil
        end

        # 
        # Get a collection of Mongoid instances out of the database by ID
        #
        # ==== Parameters
        #
        # ids<Array>:: Database IDs of models to retrieve
        #
        # ==== Returns
        #
        # Array:: Collection of Mongoid models
        #
        def load_all(ids)
          options = options_for_find
          if options[:select]
            @clazz.only(options[:select]).where(:_id.in => ids.map { |id| BSON::ObjectId.from_string(id) })
          else
            @clazz.where(:_id.in => ids.map { |id| BSON::ObjectId.from_string(id) })
          end
        end

        private

        def options_for_find
          options = {}
          options[:select]  =  @select unless  @select.blank?
          options
        end
      end
    end
  end
end