require 'goliath/headers'
require 'goliath/request'
require 'goliath/http_status_codes'
require 'time'

module Goliath
  # Goliath::Response holds the information that will be sent back
  # to the client.
  #
  # @private
  class Response
    # The status code to send
    attr_accessor :status

    # The headers to send
    attr_accessor :headers

    # The body to send
    attr_accessor :body

    SERVER = 'Server'.freeze
    DATE = 'Date'.freeze

    # Used to signal that a response is a streaming response
    STREAMING = :goliath_stream_response

    def initialize
      @headers = Goliath::Headers.new
      @status = 200
    end

    # Creates the header line for the response
    #
    # @return [String] The HTTP header line
    def head
      "HTTP/1.1 #{status} #{HTTP_STATUS_CODES[status.to_i]}\r\n"
    end

    # Creats the headers to be returned to the client
    #
    # @return [String] The HTTP headers
    def headers_output
      headers[SERVER] = Goliath::Request::SERVER
      headers[DATE] = Time.now.httpdate

      "#{headers.to_s}\r\n"
    end

    # Sets a set of key value pairs into the headers
    #
    # @param key_value_pairs [Hash] The key/value pairs to set as headers
    # @return [Nil]
    def headers=(key_value_pairs)
      return unless key_value_pairs

      key_value_pairs.each do |k, vs|
        next unless vs

        if vs.is_a?(String)
          vs.each_line { |v| @headers[k] = v.chomp }

        elsif vs.is_a?(Time)
          @headers[k] = vs

        else
          vs.each { |v| @headers[k] = v.chomp }
        end
      end
    end

    # Used to signal that the response is closed
    #
    # @return [Nil]
    def close
      body.close if body.respond_to?(:close)
    end

    # Yields each portion of the response
    #
    # @yield [String] The header line, headers and body content
    # @return [Nil]
    def each
      yield head
      yield headers_output

      if body.respond_to?(:each)
        body.each { |chunk| yield chunk }
      else
        yield body
      end
    end
  end
end
