# encoding: UTF-8

require 'xapian-fu'

module Spontaneous::Search
  class Database
    def self.create(index, revision)
      db = self.new(index, revision)
      db.create
      db
    end

    def initialize(index, revision)
      @index, @revision, @database = index, revision, nil
    end

    def create
      FileUtils.mkdir_p(directory)
      @database = XapianFu::XapianDb.new(xapian_options.merge({
        :create => true,
        :overwrite => true
      }))
    end

    def xapian_options
      options = { :dir => directory,
        :language => @index.language,
        :fields => @index.fields,
        :spelling => true,
        :weights => weighting_proc
      }
      options[:stemmer] = @index.stemmer unless @index.stemmer.nil?
      options[:stopper] = @index.stopper unless @index.stopper.nil?
      options
    end

    def weighting_proc
      Proc.new { |key, value, fields| field_weighting(key, fields) }
    end

    def field_weighting(key, fields)
      @weights[key]
    end

    def database
      @database ||= open_database
    end

    def stemmer
      @index.stemmer
    end

    def stopper
      @index.stopper
    end

    def open_database
      XapianFu::XapianDb.new(xapian_options)
    end

    def add(page)
      if @index.include?(page)
        @weights = @index.weights(page)
        database << @index.indexable_content(page)
      end
    end

    def close
      database.flush
    end

    def search(query, options = {})
      xapian_results = database.search(query, options)
      autocorrect = options.delete(:autocorrect)
      corrected_query = xapian_results.corrected_query
      # don't know if this is the right way to deal with the corrected query suggestion
      # but I would prefer that any searches act more like google and return a set of
      # results for a spelling correction if none have been found with the current query
      if autocorrect and xapian_results.empty? and !corrected_query.blank?
        xapian_results = database.search(corrected_query, options)
      end
      Results.new(@index.model, xapian_results, corrected_query)
    end

    alias_method :<<, :add

    def directory
      @index.site.revision_dir(@revision) / "indexes" / @index.name
    end
  end # Database
end
