# encoding: utf-8
#
require 'spec_helper'

describe 'range queries' do
  
  let(:index) do
    index = Picky::Index.new :range_queries do
      category :year
      category :alphabet
    end
    
    rangy = Struct.new :id, :year, :alphabet
    
    index.add rangy.new(1, 2000, 'g')
    index.add rangy.new(2, 1977, 'f')
    index.add rangy.new(3, 1989, 'a')
    index.add rangy.new(4, 2011, 'u')
    index.add rangy.new(5, 3000, 'v')
    index.add rangy.new(6, 1291, 'z')
    index.add rangy.new(7,  881, 'm')
    index.add rangy.new(8, 1984, 'l')
    
    index
  end
  let(:try) { Picky::Search.new index }

  it 'still works with exact queries' do
    try.search('1980').ids.should == []
    try.search('1989').ids.should == [3]
  end
  
  it 'works with misses' do
    try.search('900-1200').ids.should == []
  end
  
  it 'survives huge ranges' do
    try.search('0-10000 a').ids.should == [3]
    
    # Quote to make it non-partial.
    #
    try.search('0-3000"').ids.should == [7,6,2,8,3,1,4,5]
  end
  it 'is semi-reasonably fast with huge ranges' do
    # Quote to make it non-partial.
    #
    performance_of { try.search('0-3000"') }.should < 0.21
    
    # Note it is much much faster with an additional token.
    #
    performance_of { try.search('0-3000 a') }.should < 0.0085
  end
    
  it 'handles basic range queries' do
    try.search('1980-2001').ids.should == [8,3,1]
    try.search('f-u').ids.should == [2,1,8,7,4]
  end
  
  it 'can handle qualifiers' do
    try.search('year:1980-2001').ids.should == [8,3,1]
    try.search('alphabet:f-u').ids.should == [2,1,8,7,4]
  end
  
  it 'can be combined with other search words' do
    try.search('1980-2001 a').ids.should == [3]
    try.search('f-u 881').ids.should == [7]
  end
  
  it 'can handle multiple range queries' do
    try.search('1980-2001 a-h').ids.should == [3,1]
    try.search('f-u 881-1977').ids.should == [2,7]
  end
  
  it 'can be combined with partial queries' do
    try.search('198* a-h').ids.should == [3]
    try.search('a-h 198').ids.should == [3]
  end
  
  it 'works with nonsensical ranges' do
    try.search('h-a').ids.should == []
  end
  
  # it 'handles combined range/partial queries' do
  #   # TODO This still needs to be refined. It is madness.
  #   #
  #   try.search('198-200*').ids.should == [8,3,1,4,5,7,6,2]
  # end

  describe 'custom ranges' do
    class Wrap12Hours
      include Enumerable
        
      def initialize(min, max)
        @hours = 12
        @min   = min.to_i
        @top   = max.to_i
        @top   += @hours if @top < @min
      end

      def each
        @min.upto(@top).each do |i|
          yield (i % @hours).to_s
        end
      end
    end
    
    let(:index) do
      index = Picky::Index.new :range_queries do
        category :hour,
                 ranging: Wrap12Hours,
                 partial: Picky::Partial::None.new
      end
    
      rangy = Struct.new :id, :hour
      
      index.add rangy.new(1, 0)
      index.add rangy.new(2, 1)
      index.add rangy.new(3, 4)
      index.add rangy.new(4, 5)
      index.add rangy.new(5, 11)
      index.add rangy.new(6, 10)
      index.add rangy.new(7, 2)
      index.add rangy.new(8, 3)
      
      index
    end

    it 'allows injection of custom range classes' do
      try.search('hour:10-2').ids.should == [6, 5, 1, 2, 7]
    end
    
    it 'allows injection of custom range classes' do
      try.search('hour:0-11').ids.should == [1, 2, 7, 8, 3, 4, 6, 5]
    end
  end
  
end