#!/usr/pkg/bin/ruby193 -w

require "optparse"
require "rubygems"
require "hoe"
require "fileutils"
require "erb"

XIF = "FI" + "X" # prevents extra hits on my TAG reporter

option = {
  :style  => "default",
  :subdir => nil,
}

def check_subdir option
  return unless option[:subdir]

  warn "ERROR: you can't specify multiple subdirs"
  abort opts.to_s
end

def make_sub_modules klass
  last = nil
  result = ""
  klass.split("::")[0..-2].each do |part|
    last = [last, part].compact.join("::")
    result << "module #{last}; end\n"
  end
  result << "\n" unless result.empty?
end

op = OptionParser.new do |opts|
  opts.banner = "Usage: sow [options] project_name"

  opts.separator "Standard options:"

  opts.on("-t", "--trunk", "Add project to subdir under 'trunk'.") do
    check_subdir option
    option[:subdir] = "trunk"
  end

  opts.on("-d", "--dev", "Add project to subdir under 'dev'.") do
    check_subdir option
    option[:subdir] = "dev"
  end

  opts.on("-s style", "--style style", String, "Use template <style>.") do |s|
    option[:style] = s
  end

  opts.on("-h", "--help", "Show this message.") do
    puts opts
    exit
  end
end

op.parse!

include FileUtils::Verbose

# variables for erb:
template_dir  = File.expand_path("~/.hoe_template")
template_path = File.join template_dir, option[:style]
source_path   = File.join(File.dirname(File.dirname(__FILE__)), "template")
default_dir   = File.join template_dir, "default"

if File.directory? template_dir and not File.directory? default_dir then
  warn "Detected old #{template_dir}"
  warn "Moving to #{default_dir}"
  tmp = "#{template_dir}.#{$$}"
  File.rename template_dir, tmp
  FileUtils.mkdir template_dir
  File.rename tmp, default_dir
end

unless File.directory? template_path then
  warn "Creating missing #{option[:style]} template."
  FileUtils.mkdir_p File.dirname(template_path)
  FileUtils.cp_r source_path, template_path
  paths = (Dir["#{template_path}/**/*"] +
           Dir["#{template_path}/**/.*"]).select { |f| File.file? f }
  FileUtils.chmod 0644, paths
  FileUtils.chmod 0755, paths.grep(/bin\//)
end

project = ARGV.shift

abort op.to_s unless project
abort "Project #{project} seems to exist" if File.directory? project

_, file_name, klass, test_klass = Hoe.normalize_names project
ext_name = File.basename file_name # minitest/plugin => plugin

klass = klass           # quell unused warnings if they're not used in templates
test_klass = test_klass # ditto

FileUtils.cp_r template_path, project

Dir.chdir project do
  dirs = Dir["**/*"].select { |f| File.directory? f }.sort.reverse
  dirs.grep(/file_name$/).each do |file|
    FileUtils.mv file, file.sub(/file_name$/, file_name)
  end

  dirs = Dir["**/*"].select { |f| File.directory? f }.sort.reverse
  dirs.grep(/ext_name$/).each do |file|
    FileUtils.mv file, file.sub(/ext_name$/, ext_name)
  end

  paths = (Dir["**/*"] + Dir["**/.*"]).select { |f| File.file? f }.sort
  paths.each do |path|
    file = File.read path

    warn "erb: #{path}"

    File.open path, "w" do |io|
      erb = ERB.new file, nil, "<>"
      erb.filename = path
      io.puts erb.result(binding)
    end
  end

  paths.grep(/(file|ext)_name|\.erb$/).each do |file|
    new_file = file.
      sub(/(test_)?file_name/, file_name).
      sub(/(test_)?ext_name/, ext_name).
      sub(/\.erb$/, "")

    case file
    when /^bin/ then
      dir, *rest = new_file.split File::SEPARATOR

      new_file = File.join dir, rest.join("_")
    when /^test/ then
      dir, *rest = new_file.split File::SEPARATOR

      rest.last.sub!(/^/, "test_")

      new_file = File.join dir, *rest
    end

    FileUtils.mkdir_p File.dirname new_file
    FileUtils.mv file, new_file
  end
end

if option[:subdir] then
  temp_dir = "#{project}.#{$$}"
  FileUtils.mv project, temp_dir
  FileUtils.mkdir project
  FileUtils.mv temp_dir, "#{project}/#{option[:subdir]}"
end

puts
puts "... done, now go fix all occurrences of '#{XIF}':"
if Hoe::WINDOZE then
  puts `findstr /N /S /C:#{XIF} #{project}\\*`
else
  puts `find #{project} -type f | xargs grep -n #{XIF}`.gsub(/\A|\n/, "\n  ")
end
