module HttpUtils
  def get_chunk path, params={}
    submit do |http|
      http.get(create_url(path), convert_params(params)) do |chunk|
        puts chunk
      end
    end
    ""
  end

  def get path, params={}
    get_with_headers path, params, headers()
  end

  def get_with_headers path, params={}, headers={}
    submit do |http|
      http.get(create_url(path), convert_params(params), headers)
    end
  end

  def post path, params={}
    self.post_body(path, params.to_json)
  end

  def post_body path, body
    post_body_with_headers path, body, self.headers
  end

  def post_chunk_body path, body, json=true
    h = (json ? self.headers : self.headers("Content-Type", "Accept"))
    submit do |http|
      buf = ""
      http.force_basic_auth = true
      resp = http.post(create_url(path), body: body, header: h) do |chunk|
        puts chunk
        buf = chunk
      end
      if resp.ok?
        status = check_status(buf)
        exit(status) unless status == 0
      end
      resp
    end
    ""
  end

  def post_chunk path, params={}
    self.post_chunk_body path, params.to_json
  end

  def post_body_with_headers path, body='', headers={}
    submit do |http|
      http.post(create_url(path), body, headers)
    end
  end

  def delete path, params={}
    delete_body path, params.to_json
  end

  def delete_body path, body
    submit do |http|
      http.delete(create_url(path), body, self.headers)
    end
  end

  def put path, params={}
    put_body path, params.to_json
  end

  def put_body path, body
    submit do |http|
      http.put(create_url(path), body, self.headers)
    end
  end

  protected

    def update_object_from_file object_class, object_id, file
      unless File.exists?(file)
        @options_parser.invalid_update_command
        abort I18n.t("handler.error.file.not_exist", :file => file)
      end
      update_object_from_json object_class, object_id, File.read(file)
    end

    def update_object_from_json object_class, object_id, json
      put_body "/#{object_class}/#{object_id}", json
    rescue NotFound => e
      post_body "/#{object_class}", json
    end

    def create_url path
      a = [self.options[:api], path]
      a.unshift(self.options[:prefix]) unless self.options[:prefix].nil?
      p = ""
      a.each{|e| p << (e.start_with?("/") ? e : "/" + e)}
      URI.join(self.host, p).to_s
    end

    def submit
      http = HTTPClient.new
      http.receive_timeout = 0
      http.send_timeout = 0
      http.set_auth(nil, self.username, self.password)
      res = yield http
      if res.ok?
        return (res.contenttype.include?("application/json") ? JSON.parse(res.body) : res.body)
      end
      case res.status
      when 422
        puts res.body
        raise InvalidQuery.new(extract_message(res))
      when 404
        raise NotFound.new(extract_message(res))
      when 400
        raise InvalidQuery.new(extract_message(res))
      when 401
        e = extract_message(res)
        e = I18n.t("handler.error.unauthorized") if (e.nil? or e.strip.empty?)
        raise DevopsException.new(e)
      else
        raise DevopsException.new(extract_message(res))
      end
    end

    def headers *exclude
      h = {
        "Accept" => "application/json",
        "Content-Type" => "application/json; charset=UTF-8"
      }

      h["Accept-Language"] = I18n.locale
      exclude.each do |key|
        h.delete(key)
      end
      h
    end

    def extract_message result
      return nil if result.body.nil?
      result.contenttype.include?("application/json") ? JSON.parse(result.body)["message"] : result.body
    end

    def convert_params params
      params_filter(params.select{|k,v| k != :cmd and !v.nil?}).join("&")
    end

    def params_filter params
      r = []
      return params if params.kind_of?(String)
      params.each do |k,v|
        key = k.to_s
        if v.kind_of?(Array)
          v.each do |val|
            r.push "#{key}[]=#{val}"
          end
        elsif v.kind_of?(Hash)
          buf = {}
          v.each do |k1,v1|
            buf["#{key}[#{k1}]"] = v1
          end
          r = r + params_filter(buf)
        else
          r.push "#{key}=#{v}"
        end
      end
      r
    end

end
