require 'java'
module Jubilee
  class Response
    include Const
    include org.jruby.jubilee.RackResponse

    def initialize(array)
      @status, @headers, @body = *array
      @status                  = @status.to_i
      @content_length          = nil
      @chunked                 = false
      @hijack                  = nil
      if @body.kind_of? Array and @body.size == 1
        @content_length = @body[0].nil? ? 0 : @body[0].bytesize
      end
    end

    # See Rack::Utils::
    def respond(response)
      no_body = @status < 200 || STATUS_WITH_NO_ENTITY_BODY[@status]
      write_status(response)
      write_headers(response)
      if @hijack
        @hijack.call(response.net_socket)
        return
      end
      if no_body
        response.end
      else
        if @body.respond_to?(:to_path)
          response.send_file(@body.to_path)
        else
          write_body(response)
          response.end
        end
      end
    rescue NativeException => e
      puts e
    ensure
      @body.close if @body.respond_to?(:close)
    end

    private
    def write_status(response)
      response.status_code = @status
    end

    def write_headers(response)
      @headers.each do |key, values|
        case key
        when CONTENT_LENGTH
          @content_length = values
          next
        when TRANSFER_ENCODING
          if @chunked = (values == CHUNKED)
            @content_length = nil
          end
        when HIJACK
          @hijack = values
          next
        end
        # Multiple values are joined by \n
        response.put_header(key, values)
      end
    end

    def write_body(response)
      response.put_default_headers
      if @content_length
        response.put_header(CONTENT_LENGTH, @content_length.to_s)
      else
        response.chunked = true
      end

      @body.each do |part|
        if chunk = @chunked ? self.class.strip_term_markers(part) : part
          response.write(chunk)
        end
      end
    end

    def self.strip_term_markers(chunk)
      # Heavily copied from jruby-rack's rack/response.rb
      term = "\r\n"
      tail = "0#{term}#{term}".freeze
      term_regex = /^([0-9a-fA-F]+)#{Regexp.escape(term)}(.+)#{Regexp.escape(term)}/mo
      if chunk == tail
        # end of chunking, do nothing
        nil
      elsif chunk =~ term_regex
        # format is (size.to_s(16)) term (chunk) term
        # if the size doesn't match then this is some
        # output that just happened to match our regex
        if $1.to_i(16) == $2.bytesize
          $2
        else
          chunk
        end
      else
        chunk
      end
    end
  end
end
