package Perl::Metrics2::Parse;

# Delegatable PPI caching parser.
# Takes a PPI::Cache directory and a list of files to parse.

use strict;
use warnings;
use Process              ();
use Process::Storable    ();
use Process::Delegatable ();
use PPI::Util            ();
use PPI::Cache           ();
use PPI::Document        ();
use Params::Util         '_ARRAY';

our $VERSION = '0.05';
our @ISA     = qw{
	Process::Delegatable
	Process::Storable
	Process
};

sub new {
	my $class = shift;
	my $self  = bless { @_ }, $class;

	# Check params
	unless ( -d $self->cache ) {
		die "Missing or invalid cache directory";
	}
	unless ( _ARRAY($self->files) ) {
		die "Missing or invalid file list";
	}

	return $self;
}

sub cache {
	$_[0]->{cache};
}

sub files {
	$_[0]->{files};
}

sub ok {
	$_[0]->{ok};
}

sub prepare {
	my $self = shift;

	# Set the default PPI document cache
	$self->{ppi_cache} = PPI::Cache->new(
		path => $self->cache,
	);
	unless ( PPI::Document->set_cache( $self->{ppi_cache} ) ) {
		die "Failed to set PPI parser cache";
	}

	return 1;
}

sub run {
	my $self  = shift;
	my @files = @{$self->files};

	# Prepare the accounting
	$self->{stats}->{files}  = scalar @files;
	$self->{stats}->{parsed} = 0;
	$self->{stats}->{error}  = 0;
	$self->{messages}        = [];

	# Process the files
	foreach my $file ( @files ) {
		# Skip if already cached
		my $md5 = PPI::Util::md5hex_file($file);
		my (undef, $path) = $self->{ppi_cache}->_paths($md5);
		next if -f $path;

		# Parse and cache the file, ignoring errors
		my $document = eval {
			PPI::Document->new($file)
		};
		if ( $@ ) {
			push @{$self->{messages}}, "CRASHED while parsing $file";
			$self->{stats}->{error}++;
		} elsif ( ! $document ) {
			my $errstr = PPI::Document->errstr;
			push @{$self->{messages}}, "Failed to parse $file";
			$self->{stats}->{error}++;
		} else {
			push @{$self->{messages}}, "Parsed $file";
			$self->{stats}->{parsed}++;
		}
	}

	# Success means we ran without errors, EVEN if we
	# didn't actually need to parse anything.
	if ( $self->{stats}->{error} ) {
		$self->{ok} = 0;
	} else {
		$self->{ok} = 1;
	}

	return 1;
}

1;
