# -*- encoding : utf-8 -*-

require_dependency File.expand_path( '../reference', __FILE__ )

module Card::Chunk

  # This should find +Alfred+ in expressions like
  # 1) {"name":"Alfred"}
  # 2a) {"name":["in","Alfred"]}
  # 3a) {"plus_right":["Alfred"]}
  # but not in
  # 2b) "content":"foo", "Alfred":"bar"
  # 3b) {"name":["Alfred", "Toni"]}      ("Alfred" is an operator here)
  # It's not possible to distinguish between 2a) and 2b) or 3a) and 3b) with a simple regex
  # hence we use a too general regex and check for query keywords after the match
  # which of course means that we don't find references with query keywords as name
  class QueryReference < Reference

    QUERY_KEYWORDS = ::Set.new(
      (
        Card::Query::MODIFIERS.keys                +
        Card::Query::OPERATORS.keys                +
        Card::Query::ATTRIBUTES.keys   +
        Card::Query::CONJUNCTIONS.keys +
        ['desc', 'asc', 'count']
      ).map(&:to_name)
    )
    word = /\s*([^"]+)\s*/

    Card::Chunk.register_class self, {
      prefix_re: '(?<=[:,\\[])\\s*"',  # we check for colon, comma or square bracket before a quote
                                          # we have to use a lookbehind, otherwise
                                          # if the colon matches it would be
                                          # identified mistakenly as an URI chunk
      full_re:   /"([^"]+)"/,
      idx_char:  '"'
    }
    # OPTIMIZE: instead of comma or square bracket check for operator followed by comma or "plus_right"|"plus_left"|"plus" followed by square bracket
    # something like
    # prefix_patterns = [
    #     "\"\\s*(?:#{Card::Query::OPERATORS.keys.join('|')})\"\\s*,",
    #     "\"\\s*(?:#{Card::Query::PLUS_ATTRIBUTES}.keys.join('|')})\\s*:\\s*\\[\\s*",
    #     "\"\\s*(?:#{(QUERY_KEYWORDS - Card::Query::PLUS_ATTRIBUTES).join('|')})\"\\s*:",
    #   ]
    # prefix_re: '(?<=#{prefix_patterns.join('|')})\\s*"'
    # But: What do we do with the "in" operator? After the first value there is no prefix which we can use to detect the following values as QueryReference chunks

    class << self
      def full_match content, prefix
        match, offset = super(content,prefix)
        if match && !QUERY_KEYWORDS.include?(match[1].to_name)
          [match, offset]
        end
      end
    end

    def interpret match, content
      @name = match[1]
    end

    def process_chunk
      @process_chunk ||= @text
    end

    def inspect
      "<##{self.class}:n[#{@name}] p[#{@process_chunk}] txt:#{@text}>"
    end

    def replace_reference old_name, new_name
      replace_name_reference old_name, new_name
      @text = "\"#{@name.to_s}\""
    end
  end
end