###############################################################################
# Codestriker: Copyright (c) 2001, 2002, 2003 David Sitsky.
# All rights reserved.
# sits@users.sourceforge.net
#
# This program is free software; you can redistribute it and modify it under
# the terms of the GPL.

# Parser object for reading patch diffs in basic form.

package Codestriker::FileParser::PatchBasicDiff;

use strict;
use Codestriker::FileParser::BasicDiffUtils;

# Return the array of filenames, revision number, linenumber and the diff text.
# Return () if the file can't be parsed, meaning it is in another format.
sub parse ($$) {
    my ($type, $fh, $uploaded_filename) = @_;

    # Array of results found.
    my @result = ();

    # The current revision and filename being processed.
    my $revision = $Codestriker::PATCH_REVISION;
    my $filename = $uploaded_filename;

    # Ignore any whitespace at the start of the file.
    my $line = <$fh>;
    while (defined($line)) {

        # Values associated with the diff.
        my $old_linenumber = -1;
        my $new_linenumber = -1;
        my $binary = 0;

        # Skip any heading or trailing whitespace contained in the review
        # text.
        while (defined($line) && $line =~ /^\s*$/) {
            $line = <$fh>;
        }
        return @result unless defined $line;

        # For basic diffs, the diff line may appear first, but is optional,
        # depending on how the diff was generated.  In any case, the line
        # is ignored.
        if (defined $line && $line =~ /^(diff.*)$/o) {
            # This isn't right, but it provides some information at least on
            # the derivative file.
            $filename = $1;

            # Read the next line.
            $line = <$fh>;
        }
        return () unless defined $line;

        # Need to check for binary file differences.
        # Unfortunately, when you provide the "-N" argument to diff,
        # it doesn't indicate new files or removed files properly.  Without
        # the -N argument, it then indicates "Only in ...".
        if ($line =~ /^Binary files .* and (.*) differ$/ ||
            $line =~ /^Files .* and (.*) differ$/) {
            $filename = $1;
            $binary = 1;
        } elsif ($line =~ /^Only in (.*): (.*)$/) {
            $filename = "$1/$2";
            $binary = 1;
        }

        if ($binary == 0) {
            my $chunk =
              Codestriker::FileParser::BasicDiffUtils->read_diff_text(
                                                                      $fh, $line, $filename, $revision, 0);
            return () unless defined $chunk;
            push @result, $chunk;
        } else {
            # Binary file changed.
            my $chunk = {};
            $chunk->{filename} = $filename;
            $chunk->{revision} = $revision;
            $chunk->{old_linenumber} = -1;
            $chunk->{new_linenumber} = -1;
            $chunk->{binary} = 1;
            $chunk->{text} = "";
            $chunk->{description} = "";
            $chunk->{repmatch} = 0;
            push @result, $chunk;
        }

        # Read the next line.
        $line = <$fh>;
    }

    # Return the found diff chunks.
    return @result;
}

1;


