#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use MP3::Tag;
use Encode;
use Encode::Guess qw/ascii shiftjis euc-jp 7bit-jis utf8/;

my $output_encoding = 'utf8';
my $ask = 0;
my $dry_run = 0;
my $verbose = 0;

GetOptions("output-encoding=s" => \$output_encoding,
           "ask" => \$ask,
           "dry-run" => \$dry_run,
           "verbose" => \$verbose);

sub fixtag {
    my ($file, $tag) = @_;
    my $update = 0;

    $tag->get_tags;
    if (exists $tag->{ID3v2}) {
        print "File: $file\n";
        for my $id ('TIT2', 'TCON', 'TALB', 'TPE1', 'TPE2', 'TPUB') {
            my ($data) = $tag->{ID3v2}->get_frame($id);
            if ($data) {
                my @candidates;
                my $encoding = guess_encoding($data);
                if (ref($encoding)) {
                    push @candidates, $encoding->name;
                } else {
                    @candidates = split /\s+or\s+/, $encoding;
                    @candidates = () if @candidates == 1;
                }

                if (!@candidates) {
                    print STDERR "$id: Cannot guess encoding\n";
                    next;
                } elsif (@candidates == 1) {
                    if ($candidates[0] eq $output_encoding
                        || $candidates[0] eq 'ascii') {
                        print STDERR "$id: No need to convert encoding\n";
                    } elsif (!$ask) {
                        Encode::from_to($data, $candidates[0], $output_encoding);
                        print "$id: Convert to $data\n";
                        $tag->{ID3v2}->change_frame($id, $data);
                        $update = 1;
                    }
                    next;
                }

                my @examples = map {
                    my $example = $data;
                    Encode::from_to($example, $_, $output_encoding);
                    $example
                } @candidates;

                unshift @examples, $data;
                print "Convertion candidates for $id:\n";
                for (my $i = 0; $i < @examples; $i++) {
                    printf "% 2d: %s\n", $i, $examples[$i];
                }

                my $key;
                print "Select candidate: ";
                while (1) {
                    $key = <STDIN>;
                    last unless defined $key;
                    
                    chomp $key;
                    if ($key !~ /^\d+$/ || !exists $examples[$key]) {
                        print "Select candidate: ";
                        next;
                    }

                    $data = $examples[$key];
                    $tag->{ID3v2}->change_frame($id, $data);
                    $update = 1;
                    last;
                }
            }
        }
    }

    if ($update) {
        my $id3v2 = $tag->{ID3v2};
        my $id3v1 = $tag->{ID3v1} || $tag->new_tag('ID3v1');
        my %table = ('TIT2' => 'title',
                     'TCON' => 'genre',
                     'TALB' => 'album',
                     'TPE1' => 'artist',
                     'TRCK' => 'track',
                     'TYER' => 'year');
        for my $id ('TIT2', 'TCON', 'TALB', 'TPE1', 'TRCK', 'TYER') {
            my ($data) = $tag->{ID3v2}->get_frame($id);
            if ($data) {
                if ($id eq 'TIT2') {
                    $id3v1->title($data);
                } elsif ($id eq 'TCON') {
                    $id3v1->genre($data);
                } elsif ($id eq 'TALB') {
                    $id3v1->album($data);
                } elsif ($id eq 'TPE1') {
                    $id3v1->artist($data);
                } elsif ($id eq 'TYER') {
                    $id3v1->year($data);
                }
            }
        }
    }

    if (!$dry_run && $update) {
        $tag->{ID3v2}->write_tag;
    }
}

for my $file (@ARGV) {
    my $tag = MP3::Tag->new($file);
    if ($tag) {
        fixtag($file, $tag);
    } else {
        print STDERR "$file: $!\n";
    }
}
