# RGen Framework
# (c) Martin Thiede, 2006

module RGen
  
module TemplateLanguage
  
  class OutputHandler
    attr_writer :indent
    attr_accessor :noIndentNextLine
    
    def initialize(indent=0, indentString="   ", mode=:explicit)
      self.mode = mode
      @indent = indent
      @indentString = indentString
      @state = :wait_for_nonws
      @output = ""
    end
    
    # ERB will call this method for every string s which is part of the
    # template file in between %> and <%. If s contains a newline, it will
    # call this method for every part of s which is terminated by a \n
    # 
    def concat(s)
      return @output.concat(s) if s.is_a? OutputHandler
      #puts [object_id, noIndentNextLine, @state, @output.to_s, s].inspect
      s = s.to_str.gsub(/^[\t ]*\r?\n/,'') if @ignoreNextNL
      s = s.to_str.gsub(/^\s+/,'') if @ignoreNextWS
      @ignoreNextNL = @ignoreNextWS = false if s =~ /\S/
      if @mode == :direct
        @output.concat(s)
      elsif @mode == :explicit
        while s.size > 0
          if @state == :wait_for_nl
            if s =~ /\A([^\r\n]*\r?\n)(.*)/m
              rest = $2
              @output.concat($1.gsub(/[\t ]+(?=\r|\n)/,''))
              s = rest || ""
              @state = :wait_for_nonws
            else
              @output.concat(s)
              s = ""
            end
          elsif @state == :wait_for_nonws
            if s =~ /\A\s*(\S+.*)/m
              s = $1 || ""
              if !@noIndentNextLine && !(@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0])
                @output.concat(@indentString * @indent)
              else
                @noIndentNextLine = false
              end
              @state = :wait_for_nl
            else
              s = ""
            end
          end
        end
      end
    end
    alias << concat
    
    def to_str
      @output
    end
    alias to_s to_str
    
    def direct_concat(s)
      @output.concat(s)
    end
    
    def ignoreNextNL
      @ignoreNextNL = true
    end
    
    def ignoreNextWS
      @ignoreNextWS = true
    end
    
    def mode=(m)
      raise StandardError.new("Unknown mode: #{m}") unless [:direct, :explicit].include?(m)
      @mode = m
    end
  end
  
end
  
end