module Alf
  module Support
    #
    # Specialization of Scope for working on a tuple specifically.
    #
    # This class works hand-in-hand with TupleExpression as it provides a scope for their
    # evaluation on tuples. It also provides a handle for implementing a flyweight design
    # pattern on tuples through the `__set_tuple` method.
    #
    # Example:
    #
    #   scope = TupleScope.new
    #   expr  = TupleExpression["status > 10"]
    #   relation.each do |tuple|
    #     expr.evaluate(scope.__set_tuple(tuple))
    #   end
    #
    class TupleScope < Scope

      module OwnMethods

        # Returns true if the decorated tuple has `name` as key.
        def respond_to?(name)
          return true if @tuple && @tuple.has_key?(name)
          super
        end

        # Sets the next tuple to use.
        #
        # On first call, this method installs the scope as a side effect unless a tuple
        # has already been provided at construction.
        #
        # @param [Tuple] tuple the current iterated tuple
        # @return [TupleScope] self
        def __set_tuple(tuple)
          __build(tuple) if @tuple.nil?
          @tuple = tuple
          self
        end

        # Builds this scope with a tuple.
        #
        # This method should be called only once and installs instance methods on
        # the scope with keys of _tuple_.
        def __build(tuple)
          tuple.keys.each do |k|
            (class << self; self; end).send(:define_method, k) do
              @tuple[k]
            end
          end
          self
        end

        def [](what)
          @tuple[what]
        end

        def to_tuple
          Tuple(@tuple)
        end

        def to_relation
          Relation(@tuple)
        end

        def to_s
          @tuple.to_s
        end

        def inspect
          @tuple.inspect
        end

      end # module OwnMethods

      # Creates a scope instance
      def initialize(tuple = nil, extensions = [], parent = nil)
        super [ OwnMethods, ::Alf::Dsl ] + extensions, parent
        __build(@tuple = tuple) if tuple
      end

    end # class TupleScope
  end # module Support
end # module Alf
