#/usr/bin/ruby

require 'erb'
erb = ERB.new(open('php2ruby.erb') {|f| f.read})
code = cleanup = data = file = mode = ''

require 'yaml'
pecl_dir = open('config.yml') {|f| YAML::parse f}.select('source/pecl_dir')[0]

Dir[pecl_dir.value + '/ibm_db2/tests/test_*.phpt'].each do |file|
  code = open(file) {|f| f.read}.scan(/<\?php(.*?)\?>/m)[-1][0].strip
  data = open(file) {|f| f.read}.scan(/\n--EXPECTF?--\n(.*)/m)[-1][0].chomp
  mode = open(file) {|f| f.read}.scan(/\n--(EXPECTF?)--\n/m)[-1][0].downcase

  # whitespace
  code.gsub! /;\s+$/, ';'
  code.gsub! /\t/, '    '

  # comments
  code.gsub!(/\/\*(.*?)\*\//m) {$1.gsub(/^(\s* ) (\S)/, '\1# \2')}

  # administrivia
  code.gsub! /require_once\('(prepare_t_string).inc'\)/, '\1 conn'
  code.gsub! /require_once\('(prepare_\w+.inc)'\)/ do
    open("#{pecl_dir.value}/ibm_db2/tests/#{$1}") {|f|
      f.read.split("\n")[1..-2].join("\n")
    }
  end
  code.gsub! /require_once\('.*?'\);\s*/, ''

  # db2
  code.gsub! /db2_/i, 'DB2::'
  data.gsub! /db2_/i, 'DB2::'

  # control structures
  code.gsub! /(\s*)if\s*(\(\s*.*?\s*\))\s*(\n\s*.*?;)/, '\1if \2 {\3\1}'
  code.gsub! /if\s*\(\s*(.*?)\s*\)\s*\{?/, 'if \1'
  code.gsub! /else\s*\{(\s*)(.*?)\}/m, 'else {\1\2end'
  code.gsub! /(\s*)else\s*(\n\s*.*?);/m, '\1else\2\1end'
  code.gsub! /\s*\{\s*$/, ''
  code.gsub! /\}\s*else/, 'else'
  code.gsub! /^(\s*)\}/, '\1end'
  code.gsub! /foreach\s*\(\s*\$(.*?) as (.*?)\s*\)/, 'for \2 in \1'
  code.gsub! /for \(\$(\w+)\s*=\s*(.*); \$\w+\s*<=\s*(.*); \$\w+\+\+\)/,
    'for \1 in (\2 .. \3)'
  code.gsub! /for \(\$(\w+)\s*=\s*(.*); \$\w+\s*<\s*(.*); \$\w+\+\+\)/,
    'for \1 in (\2 ... \3)'

  # data structures
  code.gsub! /\barray\s*\((\s*\S+\s*=>.*?)\)/m, '{\1}'
  code.gsub! /\barray\s*\((\s*\S+,.*?)\)/m, '[\1]'
  code.gsub! /\barray\s*\((\s*\S+,.*?)\)/m, '[\1]'
  code.gsub! /\barray\s*\((\s*\d+\s*)\)/m, '[\1]'

  # printing
  code.gsub! /\{(\$.*?)\}/, '\1'
  code.gsub! /^(\s*)echo /, '\1print '
  code.gsub! 'printf (', 'printf('
  code.gsub! '."\n"', ' . "\n"'
  code.gsub! '".$', '" . $'
  code.gsub! '$j ."', '$j . "'
  code.gsub! /^(\s*)print (.*);/ do
    pre,chunks = $1, $2.split(' . ')
    chunks = chunks.map do |chunk|
       if chunk[0] == ?" and chunk[-1] == ?"
        chunk[1..-2]
       elsif chunk[0] == ?' and chunk[-1] == ?'
        chunk[1..-2]
      else
        '#{' + chunk.gsub('$','') + '}'
      end
    end
    pre + 'print "' + chunks.join('') + '";'
  end
  code.gsub! /(\s*)print\s+"#\{([^}]*)\}";$/, '\1print \2;'
  code.gsub! /(\s*)print(\s+".*)\\n";$/, '\1puts\2";'
  code.gsub! /(\s*)puts(\s+".*\\n)";$/, '\1print\2\n";'

  # string interpolation
  chunks = code.split('"')
  (1..(chunks.length-1)/2).each {|i| chunks[i*2-1].gsub!(/\$([\w\[\]]+)/,'#{\1}')}
  code = chunks.join('"')
  
  # concatenation
  code.gsub! ']."', '] + "'
  code.gsub! '."/".', '+ "/" +'
  code.gsub! '." "', ' + " "'
  code.gsub! ' . ', ' + '
  code.gsub! "'. ", "' + "

  # optional parens
  code.gsub! /^(\s*DB2::\w+)\s*\(\s*(.*?)\s*\);$/, '\1 \2'
  code.gsub! /^(\s*\$\w+\s*=\s*DB2::\w+)\s*\(\s*(.*?)\s*\);$/, '\1 \2'

  # php => ruby
  code.gsub! /die\s*\(\s*(.*)\s*\)\s*;/, 'throw \1'
  code.gsub! /file_get_contents\s*\(\s*(.*)\s*\)\s*;/, 'open(\1) {|f| f.read}'
  code.gsub! /strlen\s*\(\s*(.*)\s*\)/, '\1.length'
  code.gsub! /strtoupper\s*\(\s*(.*)\s*\)/, '\1.upcase'
  code.gsub! /exit\(?\)?;/, 'next'
  code.gsub! /&\$/, ''
  code.gsub! '.=', '+='
  code.gsub! '++;', '+=1'
  code.gsub! '++)', '+=1)'
  code.gsub! '--;', '-=1'
  code.gsub! '->', '.'
  code.gsub! '<<<', '<<-'
  code.gsub! '//', '#'
  code.gsub! /@(.*);/, '\1 rescue nil'
  code.gsub! /;$/, ''
  code.gsub! '$', ''

  # indentation
  code.gsub!(/^( *)/) {' ' * (6 + ($1.length+1)/2)}

  # coercing
  code.gsub! /row\['(\d+)'\]/, 'row[\1]'

  # hacks
  code.gsub! 'row[2]', 'row[2].to_s' if file =~ /045/
  code.gsub! /size\(result,i\)/, '\& || 0' if file =~ /21[13]/
  data.gsub! 'done', 'PHP Warning:  : done in %stest_' if file =~ /124/
  data.gsub! /:$/, ':false' if file =~ /2[34]\d/
  data.gsub! /^:/, 'false:' if file =~ /232/

  # exceptions
  if data =~ /^(.*?)PHP Warning:  .*?: (.*?) in %s\/?test_/m
    data,throws = $1,$2
    code = "    assert_throws :'#{throws}' do\n#{code}\n    end"
    code.gsub! /^/, '  '
  end

  # output code
  if file.gsub! /.*?(\w+)\.\w+$/, '\1.rb'
    open("tests/#{file}",'w') {|$stdout| erb.run} 
  end
end
