package VCI::VCS::Svn::Commit;
use Moose;

use File::Temp;

use VCI::Abstract::Diff;
use VCI::VCS::Svn::FileOrDirectory;

extends 'VCI::Abstract::Commit';

sub x_from_log {
    my ($class, $project, $paths, $revno, $who, $when, $message) = @_;
    my (%copied, %moved);
    my %actions = ('A' => [], 'D' => [], 'M' => []);
    
    my $project_path = $project->name;
    foreach my $name (keys %$paths) {
        my $item = $paths->{$name};
        
        # Get just the "path" part of the path, without the Project path.
        # We do this directly with a regex instead of with Path::Abstract,
        # because Path::Abstract was a major performance bottleneck in tests
        # here.
        my $path = $name;
        # We don't track changes to other Projects.
        ($path =~ s|^/\Q$project_path\E/||) || next;
        
        my $from_path = $item->copyfrom_path;
        if ($from_path) {
            # We were either copied from this project or a different one.
            my ($project_from, $from_file);

            my $orig_from_path = $from_path;
            if ($from_path =~ s|^/\Q$project_path\E/||) {
                $from_file = Path::Abstract->new($from_path);
                $project_from = $project;
            }
            else {
                # We just use the very first directory as the name of the
                # project we copied from. There's no way to know what part
                # of the path represents the branch.
                my $full_path = Path::Abstract->new($from_path);
                my $proj_from_name = ($full_path->list)[0];
                $project_from =
                    $project->repository->get_project(name => $proj_from_name);
                $from_file = Path::Abstract->new(($full_path->list)[1..-1]);
            }
            
            # XXX We don't currently track moves, because we can't reliably
            #     tell if the file was modified or not!
            # If the copyfrom_path was deleted in this rev, then this is
            # a move.
            #if (exists $paths->{$orig_from_path}
            #    && $paths->{$orig_from_path}->action eq 'D')
            #{
            #    $moved{$path} = $from_file->stringify;
                # Don't tag it as deleted, just as moved.
            #    delete $paths->{$orig_from_path};
            #    $actions{'D'} = [grep { $_ ne $from_file->stringify }
            #                          @{$actions{'D'}}];
            #}
            # Otherwise it's a copy.
            #else {
                my $copied_from = VCI::VCS::Svn::FileOrDirectory->new(
                    path => $from_file, project => $project_from,
                    revision => $item->copyfrom_rev);
                $copied{$path} = $copied_from;
            #}
        }
        
        my $obj = VCI::VCS::Svn::FileOrDirectory->new(
            path => $path, project => $project,
            revision => $revno, time => $when);
        my $action = $paths->{$name}->action;
        if ($action eq 'R') {
            push(@{ $actions{'M'} }, $obj);
        }
        else {
            push(@{$actions{$action}}, $obj);
        }
    }
        
    chomp($message);
    return $class->new(
        revision  => $revno,
        time      => $when,
        committer => $who,
        message   => $message,
        added     => $actions{'A'},
        removed   => $actions{'D'},
        modified  => $actions{'M'},
        #moved     => \%moved,
        copied    => \%copied,
        project   => $project,
    );
}

sub build_as_diff {
    my $self = shift;
    my $path = $self->project->repository->root . $self->project->name;
    my $rev = $self->revision;
    my $previous_rev = $self->revision - 1;
    my $ctx = $self->project->repository->vci->x_client;
    # Diff doesn't work unless these have filenames, for some reason.
    my $out = File::Temp->new;
    my $err = File::Temp->new;
    $ctx->diff([], $path, $previous_rev, $path, $rev, 1, 0, 0,
               $out->filename, $err->filename);
    { local $/ = undef; $err = <$err>; $out = <$out> }
    confess($err) if $err;
    return VCI::Abstract::Diff->new(raw => $out, project => $self->project);
}

__PACKAGE__->meta->make_immutable;

1;
