#!/usr/bin/env ruby

# httpclient shell command.
#
# Usage: 1) % httpclient get https://www.google.co.jp/ q=ruby
# Usage: 2) % httpclient
#
# For 1) it issues a GET request to the given URI and shows the wiredump and
# the parsed result.  For 2) it invokes irb shell with the binding that has a
# HTTPClient as 'self'.  You can call HTTPClient instance methods like;
# > get "https://www.google.co.jp/", :q => :ruby
require 'httpclient'
require 'json'
 
module HTTP
  class Message
    # Returns JSON object of message body
    alias original_content content
    def content
      if JSONClient::CONTENT_TYPE_JSON_REGEX =~ content_type
        JSON.parse(original_content)
      else
        original_content
      end
    end
  end
end
 
 
# JSONClient provides JSON related methods in addition to HTTPClient.
class JSONClient < HTTPClient
  CONTENT_TYPE_JSON_REGEX = /(application|text)\/(x-)?json/i
 
  attr_accessor :content_type_json
 
  class JSONRequestHeaderFilter
    attr_accessor :replace
 
    def initialize(client)
      @client = client
      @replace = false
    end
 
    def filter_request(req)
      req.header['content-type'] = @client.content_type_json if @replace
    end
 
    def filter_response(req, res)
      @replace = false
    end
  end
 
  def initialize(*args)
    super
    @header_filter = JSONRequestHeaderFilter.new(self)
    @request_filter << @header_filter
    @content_type_json = 'application/json; charset=utf-8'
  end
 
  def post(uri, *args, &block)
    @header_filter.replace = true
    request(:post, uri, jsonify(argument_to_hash(args, :body, :header, :follow_redirect)), &block)
  end
 
  def put(uri, *args, &block)
    @header_filter.replace = true
    request(:put, uri, jsonify(argument_to_hash(args, :body, :header)), &block)
  end
 
private
 
  def jsonify(hash)
    if hash[:body] && hash[:body].is_a?(Hash)
      hash[:body] = JSON.generate(hash[:body])
    end
    hash
  end
end

METHODS = ['head', 'get', 'post', 'put', 'delete', 'options', 'propfind', 'proppatch', 'trace']
if ARGV.size >= 2 && METHODS.include?(ARGV[0])
  client = JSONClient.new
  client.debug_dev = STDERR
  $DEBUG = true
  require 'pp'
  pp client.send(*ARGV)
  exit
end

require 'irb'
require 'irb/completion'

class Runner
  def initialize
    @httpclient = HTTPClient.new
  end

  def method_missing(msg, *a, &b)
    debug, $DEBUG = $DEBUG, true
    begin
      @httpclient.send(msg, *a, &b)
    ensure
      $DEBUG = debug
    end
  end

  def run
    IRB.setup(nil)
    ws = IRB::WorkSpace.new(binding)
    irb = IRB::Irb.new(ws)
    IRB.conf[:MAIN_CONTEXT] = irb.context

    trap("SIGINT") do
      irb.signal_handle
    end

    begin
      catch(:IRB_EXIT) do
        irb.eval_input
      end
    ensure
      IRB.irb_at_exit
    end
  end

  def to_s
    'HTTPClient'
  end
end

Runner.new.run
