#!/usr/bin/ruby
# encoding: utf-8
#
# This file, gist, is generated code.
# Please DO NOT EDIT or send patches for it.
#
# Please take a look at the source from
# http://github.com/defunkt/gist
# and submit patches against the individual files
# that build gist.
#

module Gist
  module Manpage
    extend self

    def display(name)
      puts manpage(name)
    end

    def manpage(name)
      return "** Can't find groff(1)" unless groff?

      require 'open3'
      out = nil
      Open3.popen3(groff_command) do |stdin, stdout, _|
        stdin.puts raw_manpage(name)
        stdin.close
        out = stdout.read.strip
      end
      out
    end

    def raw_manpage(name)
      if File.exists? file = File.dirname(__FILE__) + "/../../man/#{name}.1"
        File.read(file)
      else
        DATA.read.split("__CACERT__").first
      end
    end

    def groff?
      system("which groff > /dev/null")
    end

    def groff_command
      "groff -Wall -mtty-char -mandoc -Tascii"
    end

    def puts(*args)
      page_stdout
      super
    end

    def page_stdout
      return unless $stdout.tty?

      read, write = IO.pipe

      if Kernel.fork
        $stdin.reopen(read)
        read.close
        write.close

        ENV['LESS'] = 'FSRX'

        Kernel.select [STDIN]

        pager = ENV['PAGER'] || 'less -isr'
        pager = 'cat' if pager.empty?

        exec pager rescue exec "/bin/sh", "-c", pager
      else
        $stdout.reopen(write)
        $stderr.reopen(write) if $stderr.tty?
        read.close
        write.close
      end
    end
  end
end
module Gist
  VERSION = Version = '2.0.3.pre'
end
require 'open-uri'
require 'net/https'
require 'optparse'

require 'gist/manpage' unless defined?(Gist::Manpage)
require 'gist/version' unless defined?(Gist::Version)

module Gist
  extend self

  GIST_URL   = 'https://gist.github.com/%s.txt'
  CREATE_URL = 'https://gist.github.com/gists'

  PROXY = ENV['HTTP_PROXY'] ? URI(ENV['HTTP_PROXY']) : nil
  PROXY_HOST = PROXY ? PROXY.host : nil
  PROXY_PORT = PROXY ? PROXY.port : nil

  def execute(*args)
    private_gist = defaults["private"]
    gist_filename = nil
    gist_extension = defaults["extension"]
    browse_enabled = defaults["browse"]

    opts = OptionParser.new do |opts|
      opts.banner = "Usage: gist [options] [filename or stdin] [filename] ...\n" +
        "Filename '-' forces gist to read from stdin."

      opts.on('-p', '--[no-]private', 'Make the gist private') do |priv|
        private_gist = priv
      end

      t_desc = 'Set syntax highlighting of the Gist by file extension'
      opts.on('-t', '--type [EXTENSION]', t_desc) do |extension|
        gist_extension = '.' + extension
      end

      opts.on('-o','--[no-]open', 'Open gist in browser') do |o|
        browse_enabled = o
      end

      opts.on('-m', '--man', 'Print manual') do
        Gist::Manpage.display("gist")
      end

      opts.on('-v', '--version', 'Print version') do
        puts Gist::Version
        exit
      end

      opts.on('-h', '--help', 'Display this screen') do
        puts opts
        exit
      end
    end

    opts.parse!(args)

    begin
      if $stdin.tty? && args[0] != '-'

        if args.empty?
          puts opts
          exit
        end

        files = args.inject([]) do |files, file|
          abort "Can't find #{file}" unless File.exists?(file)

          files.push({
            :input     => File.read(file),
            :filename  => file,
            :extension => (File.extname(file) if file.include?('.'))
          })
        end

      else
        input = $stdin.read
        files = [{:input => input, :extension => gist_extension}]
      end

      url = write(files, private_gist)
      browse(url) if browse_enabled
      puts copy(url)
    rescue => e
      warn e
      puts opts
    end
  end

  def write(files, private_gist = false)
    url = URI.parse(CREATE_URL)

    if PROXY_HOST
      proxy = Net::HTTP::Proxy(PROXY_HOST, PROXY_PORT)
      http  = proxy.new(url.host, url.port)
    else
      http = Net::HTTP.new(url.host, url.port)
    end

    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_PEER
    http.ca_file = ca_cert

    req = Net::HTTP::Post.new(url.path)
    req.form_data = data(files, private_gist)

    response = http.start{|h| h.request(req) }
    case response
    when Net::HTTPRedirection
      response['Location']
    else
      puts "Creating gist failed: #{response.code} #{response.message}"
      exit(false)
    end
  end

  def read(gist_id)
    open(GIST_URL % gist_id).read
  end

  def browse(url)
    if RUBY_PLATFORM =~ /darwin/
      `open #{url}`
    elsif ENV['OS'] == 'Windows_NT' or
      RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw|wince/i
      `start "" "#{url}"`
    end
  end

  def copy(content)
    cmd = case true
    when system("type pbcopy > /dev/null 2>&1")
      :pbcopy
    when system("type xclip > /dev/null 2>&1")
      :xclip
    when system("type putclip > /dev/null 2>&1")
      :putclip
    end

    if cmd
      IO.popen(cmd.to_s, 'r+') { |clip| clip.print content }
    end

    content
  end

private
  def data(files, private_gist)
    data = {}
    files.each do |file|
      i = data.size + 1
      data["file_ext[gistfile#{i}]"]      = file[:extension] ? file[:extension] : '.txt'
      data["file_name[gistfile#{i}]"]     = file[:filename]
      data["file_contents[gistfile#{i}]"] = file[:input]
    end
    data.merge(private_gist ? { 'action_button' => 'private' } : {}).merge(auth)
  end

  def auth
    user  = config("github.user")
    token = config("github.token")

    if user.to_s.empty? || token.to_s.empty?
      {}
    else
      { :login => user, :token => token }
    end
  end

  def defaults
    extension = config("gist.extension")
    extension = nil if extension && extension.empty?

    return {
      "private"   => config("gist.private"),
      "browse"    => config("gist.browse"),
      "extension" => extension,
    }
  end

  def config(key)
    env_key = ENV[key.upcase.gsub(/\./, '_')]
    return env_key if env_key and not env_key.empty?

    str_to_bool `git config --global #{key}`.strip
  end

  def str_to_bool(str)
    if str.size > 0 and str[0].chr == '!'
      command = str[1, str.length]
      value = `#{command}`
    else
      value = str
    end

    case value.downcase.strip
    when "false", "0", "nil", "", "no", "off"
      nil
    when "true", "1", "yes", "on"
      true
    else
      value
    end
  end

  def ca_cert
    cert_file = [
      File.expand_path("../gist/cacert.pem", __FILE__),
      "/tmp/gist_cacert.pem"
    ].find{|l| File.exist?(l) }

    if cert_file
      cert_file
    else
      File.open("/tmp/gist_cacert.pem", "w") do |f|
        f.write(DATA.read.split("__CACERT__").last)
      end
      "/tmp/gist_cacert.pem"
    end
  end

end
Gist.execute(*ARGV)
