module Blendris

  # RedisSortedSet is a wrapper to the Redis ZSET data type.

  class RedisSortedSet < RedisNode

    include Enumerable

    def initialize(key, options = {})
      @key = key.to_s
      @options = options
      @on_change = options[:on_change]
    end

    def each(min = "-inf", max = "+inf", mode = :score)
      case mode
      when :rank  then redis.zrange key, min, max
      when :score then redis.zrangebyscore key, min, max
      else             raise "unknown zset mode #{mode}"
      end.each do |value|
        yield value
      end

      self
    end

    def each_with_scores(min = "-inf", max = "+inf", mode = :score)
      flat_pairs =
        case mode
        when :rank  then redis.zrange key, min, max, :with_scores => true
        when :score then redis.zrangebyscore key, min, max, :with_scores => true
        else             raise "unknown zset mode #{mode}"
        end

      pairify(flat_pairs).each do |value, score|
        yield score.to_f, value
      end

      self
    end

    def set(*pairs)
      tempkey = "#{key}:::TEMP:::#{rand}"
      redis.del tempkey

      pairify(pairs).each do |score, value|
        redis.zadd tempkey, score, value
      end

      redis.rename tempkey, key

      self
    ensure
      notify_changed
    end

    def <<(pairs)
      tempkey = "#{key}:::TEMP:::#{rand}"
      redis.del tempkey

      pairify(pairs).each do |score, value|
        redis.zadd tempkey, score, value
      end

      redis.zunionstore key, [ key, tempkey ]
      redis.del tempkey

      self
    ensure
      notify_changed
    end

    def get
      self
    end

    def delete(value)
      redis.zrem key, value
    ensure
      notify_changed
    end

    def delete_by_score(min, max)
      redis.zremrangebyscore key, min, max
    ensure
      notify_changed
    end

    # Set this zset's members to the intersection of this set and the given set.
    def intersect!(other)
      redis.zinterstore key, [ key, other.key ]
    ensure
      notify_changed
    end

    # Set this zset's members to the union of this set and the given set.
    def union!(other)
      redis.zunionstore key, [ key, other.key ]
    ensure
      notify_changed
    end

  end

end