require 'time'

# an extesion to http responses
module Restfulie::Client::HTTP::ResponseStatus
  
  attr_accessor :previous
        
  # determines if this response code was successful (according to http specs: 200~299)
  def is_successful?
    code.to_i >= 200 && code.to_i <= 299
  end
    
  # determines if this response code was successful (according to http specs: 100~199)
  def is_informational?
    code.to_i >= 100 && code.to_i <= 199
  end
    
  # determines if this response code was successful (according to http specs: 300~399)
  def is_redirection?
    code.to_i >= 300 && code.to_i <= 399
  end
    
  # determines if this response code was successful (according to http specs: 400~499)
  def is_client_error?
    code.to_i >= 400 && code.to_i <= 499
  end
    
  # determines if this response code was successful (according to http specs: 500~599)
  def is_server_error?
    code.to_i >= 500 && code.to_i <= 599
  end
  
  def etag
    self['Etag']
  end

  def last_modified
    self['Last-Modified']
  end
  
end
  
module Restfulie::Client::HTTP::ResponseCacheCheck

  def cache_max_age
    val = header_value_from('cache-control', /^\s*max-age=(\d+)/)
    if val
      val.to_i
    else
      0
    end
  end
  
  def header_value_from(header, expression)
    h = value_for(headers[header], expression)
    return nil if h.nil?
    h.match(expression)[1]
  end
  
  def has_expired_cache?
    return true if headers['date'].nil?
    max_time = Time.rfc2822(headers['date'][0]) + cache_max_age.seconds
    Time.now > max_time
  end

  # checks if the header's max-age is available and no no-store if available.
  def may_cache?
    may_cache_method? && may_cache_field?(headers['cache-control'])
  end
  
  # Returns whether this cache control field allows caching
  #
  # may_cache_field(['max-age=2000', 'no-store']) == false
  # may_cache_field('max-age=2000,no-store') == false
  # may_cache_field('max-age=2000') == true
  def may_cache_field?(field)
    return false if field.nil?
    
    if field.kind_of? Array
      field.each do |f|
        return false if !may_cache_field?(f)
      end
      return true
    end

    max_age_header = value_for(field, /^max-age=(\d+)/)
    return false if max_age_header.nil?
    
    return !value_for(field, /^no-store/)
  end

  # extracts the header value for an specific expression, which can be located at the start or in the middle
  # of the expression
  def value_for(value, expression)
    value = value[0] if value.kind_of? Array
    value.split(",").find { |obj| obj.strip =~ expression }
  end
  
  # extracts all header values related to the Vary header from this response, in order
  # to implement Vary support from the HTTP Specification
  # 
  # example
  # if the response Vary header is 'Accept','Accept-Language', we have
  # vary_headers_for({'Accept'=>'application/xml', 'Date' =>'...', 'Accept-Language'=>'de'}) == ['application/xml', 'de']
  # vary_headers_for({'Date' => '...', 'Accept-Language'=>'de'}) == [nil, 'de']
  def vary_headers_for(request)
    return nil if headers['vary'].nil?
    headers['vary'].split(',').map do |key|
      request[key.strip]
    end
  end
    
  private
  def may_cache_method?
    verb == :get || verb == :post
  end
end

class Net::HTTPResponse
  include Restfulie::Client::HTTP::ResponseStatus
  include Restfulie::Client::HTTP::ResponseCacheCheck

end
