#!/usr/bin/ruby

# Attempts to rename variables from the funky [O0]+ pattern into something
# more useful.  In addition, the variables that are global are renamed to
# "$g_XXXX" where XXXX is the prefix + final number, while other vars are
# just "$var_XXXX".  After that, we attempt to assign a more meaningful name
# to global vars that are assigned to a string literal and not assigned to
# anything else afterward.
#
# TODO: Similarly, function names that match the pattern are also fixed up, but
# they're also stripped of a leading "S" if it's present.
#
# Finally, any leftover strings of at least 6 occurrences of O/0 are printed
# out to let one know if a given file has something funky I can't deal with.
#
# There's a lot of "magic" going on here.  I hope it doesn't break things.

# Various methods for cleaning up this code a tiny bit
require 'lib'

help = false
flags = {
  :help => (ARGV.delete('-h') || ARGV.delete('--help') )
}
file = ARGV.shift
outfile = ARGV.shift
errors = []
unless file && File.exists?(file)
  help = true
  errors.push("Unable to read file: '#{file}'")
end
unless outfile && (!File.exists?(outfile) || File.writable?(outfile))
  help = true
  errors.push("Unable to write to file: '#{outfile}'")
end
if flags[:help]
  help = true
  errors = []
end

if help
  unless errors.empty?
    puts errors.join(", ")
    puts
  end
  puts "Usage: ruby fix_names.rb <input_file> <output_file>"
  exit
end

in_data = File.open(file) {|f| f.read}

# TODO: combine multilines if necessary

# Renumber all variables via a horrific gsub! call.  We have to set up this
# global counter so the vars can still have unique names.
$varnum = 0
vars = Hash.new
var_usage = Hash.new
rgx = /(global\s*|)\$(\w*?)([O0]{6,})(\w*)/i
in_data.gsub!(rgx) do
  replace_vars($1, $2, $3, $4, vars, var_usage)
end

# Find variable assignments next.  Strings should rename the variable, and for
# short strings or strings used just once or twice, replace the var inline.
# Obviously variables shouldn't be messed with if they're assigned to two or
# more different values.  Also, globals are the only safe things to fix here,
# since the same local var name can be used multiple times.
rgx = /\$(g_\d+_)\s*=([^=].*?)[\r\n]/i
var_assigns = Hash.new
in_data.scan(rgx) do |varname, assign|
  assign.strip!
  gather_assigns(varname, assign, var_assigns)
end

# Go through each var and see what we can do with it - rename it?  Replace it
# with data inline?
$varnum = 0
var_renames = Hash.new
for (name, val) in var_assigns
  next if val == :invalid

  if val =~ /((['"])(.*?)\2)/
    full_assign = $1
    string = $3

    if (string.length < 25 || var_usage['$' + name] <= 1)
      var_renames[name] = full_assign
    else
      friendly_name = string.gsub(' ', '_').gsub(/\W/, '')[0..24]
      var_renames[name] = '$g_%d%s' % [$varnum, friendly_name]
      $varnum += 1
    end
  elsif val =~ /(true|false)\b/i
    var_renames[name] = '$g_%s%d' % [$1.downcase, $varnum]
    $varnum += 1
  end
end

for (old, new) in var_renames
  in_data.gsub!('$%s' % [old], new)
end

# Now we need to fix all the globals that are no longer valid - delete any
# line that's bad due to search and replace
lines = in_data.split(/[\r\n]+/)
lines.delete_if {|line| line =~ /^\s*global\s*(.)/i && $1 != '$'}
lines.delete_if {|line| line =~ /^\s*"[^"]*"\s*=\s*"[^"]*"\s*$/i}

File.open(outfile, 'w') {|f| f.write(lines.join("\n")) }
