#!/usr/bin/env ruby

# A workaround to upgrade installed casks
# Update Homebrew Cask and verify installed applications versions with Casks to perform an upgrade
# The app prompts you to update only if the Cask contain a version number and the installed app version can be retrieved.
# Therefore casks that use "latest" will not be updated
#
# NOTE: THIS SCRIPT COMPLETELY REMOVES OUT-OF-DATE CASKS & ADDS THE LATEST VERSION.

require 'optparse'

options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: #{opts.program_name()} <options> <package name>"

  opts.on("-y", "Assume yes") do |y|
    options[:auto] = y
  end
end.parse!

options[:package] = ARGV[0]

# UPGRADE SPECIFIC APP
if options[:package]
  app = options[:package]
  if system("brew cask info #{app} &>/dev/null")
    print "Do you want to reinstall #{app}? " + '[y/N]'
    if options[:auto]
        update = 'y'
    else
        update = STDIN.gets.strip
    end
    if update =~ /[yY]/
      puts "Upgrading #{app}"
      system("brew cask uninstall #{app} --force && brew cask install #{app} --force")
    else
      puts 'Cancelling update...'
    end
  else
    puts 'Unknown app to update'
  end
  exit!
end

# UPDATE HOMEBREW
puts 'Updating homebrew cask, please wait...'
system('brew cask update')
if $CHILD_STATUS == 1
  puts 'Cask update failed'
  exit!
end

# BREW CASK LIST
IO.popen('brew cask list') do |apps|
  apps.each do |app|
    app.chomp!
    infosstr = app
    infos = `brew cask info #{app}`
    if vmatch = /: ([A-z0-9\._]+)/.match(infos.lines.first)
      version, build = vmatch[1].split(/[_-]/)
      infosstr += " version: #{version}"
      infosstr += " (#{build})" if build

      print infosstr.to_s
      column1length = 80 - infosstr.gsub(/\e\[[0-9;]+[m]?/, '').length

      if appname = /(.+) \(app\)/.match(infos)
        # APPLICATION FILENAME
        appname = appname[1].strip

        fullpath = `mdfind -onlyin /opt/homebrew-cask/Caskroom -onlyin /Applications -onlyin ~/Applications "#{appname}" | grep "#{appname}"`.strip
        if File.exist?(fullpath)
          # GET APPLICATION VERSION WITH SPOTLIGHT
          if currentmatch = /([A-z0-9\.]+)/.match(`mdls "#{fullpath}" -name kMDItemVersion -raw`)
            current = currentmatch[1].chomp

            # COMPARE INSTALLED VERSION WITH CASK VERSION
            begin
              if Gem::Version.new(version) <= Gem::Version.new(current)
                puts 'Up-to-date'.rjust(column1length)
              elsif current != '(null)' && version != 'latest'
                puts 'Update available'.rjust(column1length)
                print "Do you want to update #{app} to version #{version} (current #{current})? " + '[y/N] '
                if options[:auto]
                  update = 'y'
                else
                  update = STDIN.gets.strip
                end
                # UPDATE CURRENT APPLICAION
                if update =~ /[yY]/
                  puts "Updating #{app} to version #{version}"
                  system("brew cask uninstall #{app} --force && brew cask install #{app} --force")
                else
                  puts 'Cancelling update'
                end
              else
                puts 'Update undefined'.rjust(column1length)
              end
            rescue
              puts 'Cannot determine latest version'.rjust(column1length)
            end
          else
            puts 'Unknown installed version'.rjust(column1length)
          end
        else
          puts 'Not found'.rjust(column1length)
        end
      else
        puts 'Unknown app'.rjust(column1length)
      end
    else
      print infosstr.to_s
      column1length = 80 - infosstr.length
      puts 'Unknown version'.rjust(column1length)
    end
  end
end