#require 'uri/common'

# A chunk is a pattern of text that can be protected
# and interrogated by a renderer. Each Chunk class has a 
# +pattern+ that states what sort of text it matches.
# Chunks are initalized by passing in the result of a
# match by its pattern. 

module Chunk
  class Abstract

# Rails's default utf-8 support causes problems here. So, for Chunk::Abstract class, turn off
# multibyte character support.
    $KCODE = 'n' unless ''.respond_to?(:force_encoding)

    # automatically construct the array of derivatives of Chunk::Abstract
    @derivatives = [] 

    class << self 
      attr_reader :derivatives 
    end 
    
    def self::inherited( klass ) 
      Abstract::derivatives << klass 
    end 
    
    # the class name part of the mask strings
    def self.mask_string
      self.to_s.delete(':').downcase
    end

    # a regexp that matches all chunk_types masks
    def Abstract::mask_re(chunk_types)
      chunk_classes = chunk_types.map{|klass| klass.mask_string}.join("|")
      /chunk(-?\d+)(#{chunk_classes})chunk/
    end
    
    attr_reader :text, :unmask_text, :unmask_mode

    def initialize(match_data, content) 
      @text = match_data[0] 
      @content = content
      @unmask_mode = :normal
    end

    # Find all the chunks of the given type in content
    # Each time the pattern is matched, create a new
    # chunk for it, and replace the occurrence of the chunk
    # in this content with its mask.
	def self.apply_to(content)
	  text = content.to_str
	  text.gsub!( self.pattern ) do |match|
        new_chunk = self.new($~, content)
        content.add_chunk(new_chunk)
        new_chunk.mask
       end
       content.replace text
    end

    # should contain only [a-z0-9]
    def mask
      @mask ||= "chunk#{self.object_id}#{self.class.mask_string}chunk"
    end

    def unmask
      @content.replace  @content.sub(mask){|s| s.replace @unmask_text}
    end

    def rendered?
      @unmask_mode == :normal
    end

    def escaped?
      @unmask_mode == :escape
    end

    def revert
      @content.replace  @content.sub(mask){|s| s.replace @text}
      # unregister
      @content.delete_chunk(self)
    end

  end

end
