#!/usr/bin/perl

use strict;

require File::Spec::Unix;

my $do_symlink = 0;

my $map_files = 0;
my $map_paths = 0;
my %mapping;

sub do_rename($$$) {
  my $src = shift;
  my $destdir = shift;
  my $destname = shift;
  my $dest = "$destdir/$destname";
  if ($do_symlink) {
    # Ignore errors, which occur on case insensitive file systems
    symlink(File::Spec::Unix->abs2rel($src, $destdir), "$dest");
  } else {
    rename("$src", "$dest") || die("Rename: $!\n");
  }
}

sub remapName($) {
  my $path = shift;
  $path =~ s/\/$//; # Trim the trailing slash, for directories
  my $name = $path;
  $name =~ s/.*\///;
  $name = lc($name);
  if ($map_paths) {
    if (exists $mapping{lc($path)}) { return $mapping{lc($path)}; }
  } elsif ($map_files) {
    if (exists $mapping{$name}) { return $mapping{$name}; }
  }
  return $name;
}

sub mergedir($$) {
  my $src = shift;
  my $dest = shift;

  opendir(IN, $src) || die("$src: $!\n");
  my @dir = readdir IN;
  closedir IN;

  foreach my $i (@dir) {
    next if($i eq ".");
    next if($i eq "..");
    if(-d "$src/$i") {
      if(-e "$dest/$i") {
        mergedir("$src/$i", "$dest/$i");
      } else {
        do_rename("$src/$i", $dest, $i);
      }
    } else {
      do_rename("$src/$i", $dest, $i);
    }
  }
  rmdir($src) if (!$do_symlink);
  return 1;
}

sub dodir($$) {
  my $dir = shift;
  my $relpath = shift;

  opendir(IN, $dir) || die("$dir: $!\n");
  my @dir = readdir IN;
  closedir IN;

  foreach my $i (@dir) {
    next if($i eq ".");
    next if($i eq "..");
    my $relname = "$relpath$i";
    if(-d "$dir/$i") {
      dodir("$dir/$i", "$relname/");
    } else {
      my $new = remapName($relname);
      if($i ne $new) {
        #print "FILE: $i -> $new\n";
        do_rename("$dir/$i", $dir, $new);
      }
    }
  }

  my @dirs = split('/', $dir);
  my $ldir = pop(@dirs);
  my $newname = remapName($relpath);
  $newname = lc($ldir) if ($relpath eq "");
  if($ldir ne $newname) {
    my $ndir = join('/', @dirs);
    my $parent = $ndir;
    if($ndir) {
      $ndir .= "/" . $newname;
    } else {
      $parent = ".";
      $ndir = $newname;
    }
    #print "DIR:  $dir -> $ndir\n";
    if(-d $ndir) {
      mergedir($dir, $ndir) || die("Merge: $!\n");
    } else {
      do_rename("$dir", $parent, $newname);
    }
  }
}

sub readMapping($) {
  my $file = shift;
  open FILE, $file;
  foreach my $line (<FILE>) {
    chomp $line;
    my $name = $line;
    $name =~ s/.*\///;
    next if (exists $mapping{lc($line)});
    $mapping{lc($line)} = $name;
  }
  close FILE;
}

my @paths;
for (my $i = 0; $i < @ARGV; $i++) {
	my $arg = $ARGV[$i];
        if ($arg eq "-symlink") {
                $do_symlink = 1;
        } elsif ($arg eq "-map_paths") {
		if ($i + 1 < @ARGV) { readMapping($ARGV[$i+1]); }
		$map_paths = 1;
                $i += 1;
        } elsif ($arg eq "-map_files") {
		if ($i + 1 < @ARGV) { readMapping($ARGV[$i+1]); }
		$map_files = 1;
                $i += 1;
        } else {
                push @paths, $arg;
        }
}
die("Usage: lowercase dir\n") if(@paths != 1);
dodir($paths[0], "");
