package Module::CPANTS::Kwalitee::MetaYML;
use warnings;
use strict;
use File::Spec::Functions qw(catfile);
use YAML::Syck qw(Load LoadFile);
use Test::YAML::Meta::Version;

sub order { 20 }

my $CURRENT_SPEC = '1.4';

##################################################################
# Analyse
##################################################################

sub analyse {
    my $class=shift;
    my $me=shift;
    my $files=$me->d->{files_array};
    my $distdir=$me->distdir;
    if (grep {/^META\.yml$/} @$files) {
        eval {
            open(my $FH,'<',catfile($distdir,'META.yml')) || die "Cannot read META.yml: $!";
            my $yml=join('',<$FH>);
            close $FH;
            die "I do not want to handle stuff like version: !!perl/hash:version" if $yml=~/ !perl/;
            $me->d->{meta_yml}=Load($yml);
            $me->d->{metayml_is_parsable}=1;
        };
        if ($@) {
            $me->d->{error}{metayml_is_parsable}=$@;
            return;
        }
    }

    if (my $no_index = $me->d->{meta_yml}->{no_index}) {
        my @ignore;
        foreach my $type (qw(file directory)) {
            next unless $no_index->{$type};
            foreach (@{$no_index->{$type}}) {
                next if /^x?t/; # won't ignore t, xt
                next if /^lib/; # and lib
                push(@ignore,$_);
            }
        }
        $me->d->{no_index}=join(';',@ignore);
        my @old=@{$me->d->{files_array}};
        my @new; my @ignored;
        foreach my $file (@old) {
            
            # me wants smart match!!!!

            if (grep { $file=~/^$_/ } @ignore) {
                delete $me->d->{files_hash}{$file};
                $me->d->{files}--;
                push(@ignored,$file);
            }
            else {
                push(@new,$file);
            }
        }
        $me->d->{files_array}=\@new;
        $me->d->{files_list}=join(';',@new);
        $me->d->{ignored_files_array}=\@ignored;
        $me->d->{ignored_files_list}=join(';',@ignored);
    }

}

##################################################################
# Kwalitee Indicators
##################################################################

sub kwalitee_indicators{
    return [
        {
            name=>'metayml_is_parsable',
            error=>q{The META.yml file of this distributioncould not be parsed by the version of YAML.pm CPANTS is using.},
            remedy=>q{If you don't have one, add a META.yml file. Else, upgrade your YAML generator so it produces valid YAML.},
            code=>sub { shift->{metayml_is_parsable} ? 1 : 0 }
        },
        {
            name=>'metayml_has_license',
            error=>q{This distribution does not have a license defined in META.yml.},
            remedy=>q{Define the license if you are using in Build.PL. If you are using MakeMaker (Makefile.PL) you should upgrade to ExtUtils::MakeMaker version 6.31.},
            code=>sub { 
                my $d=shift;
                my $yaml=$d->{meta_yml};
                ($yaml->{license} and $yaml->{license} ne 'unknown') ? 1 : 0 }
        },
        {
            name=>'metayml_has_provides',
            is_experimental=>1,
            error=>q{This distribution does not have a list of provided modules defined in META.yml.},
            remedy=>q{Add all modules contained in this distribution to the META.yml field 'provides'. Module::Build does this automatically for you.},
            code=>sub { 
                my $d=shift;
                return 1 if $d->{meta_yml} && $d->{meta_yml}{provides};
                return 0;
            },
        },
        {
            name=>'metayml_conforms_to_known_spec',
            error=>q{META.yml does not conform to any recognised META.yml Spec. See 'metayml' in the dist error view for more info.},
            remedy=>q{Take a look at the META.yml Spec at http://module-build.sourceforge.net/META-spec-current.html and change your META.yml accordingly},
            code=>sub {
                my $d=shift;
                return check_spec_conformance($d);
            },
        },
    {
            name=>'metayml_conforms_spec_current',
            is_extra=>1,
            error=>qq{META.yml does not conform to the Current META.yml Spec ($CURRENT_SPEC). See 'metayml' in the dist error view for more info.},
            remedy=>q{Take a look at the META.yml Spec at http://module-build.sourceforge.net/META-spec-current.html and change your META.yml accordingly},
            code=>sub {
                my $d=shift;
                return check_spec_conformance($d,$CURRENT_SPEC,1);
            },
        },
        {
            name=>'metayml_declares_perl_version',
            error=>q{This distribution does not declare the minimum perl version in META.yml.},
            is_experimental=>1,
            remedy=>q{If you are using Build.PL define the {requires}{perl} = VERSION field. If you are using MakeMaker (Makefile.PL) you should upgrade ExtUtils::MakeMaker to a future version.},
            code=>sub { 
                my $d=shift;
                my $yaml=$d->{meta_yml};
                return $yaml->{requires}{perl} ? 1 : 0;
            },
        },
    ];
}

sub check_spec_conformance {
    my ($d,$version,$check_current)=@_;
    
    my $yaml=$d->{meta_yml};
    my %hash=(
        yaml=>$yaml,
    );

    if (!$version) {
        if (my $from_yaml=$yaml->{'meta-spec'}{version}) {
            $version = $from_yaml;
        }
        else {
            $version='1.0';
        }
    }
    $hash{spec} = $version;
    my $spec = Test::YAML::Meta::Version->new(%hash);
    if ($spec->parse()) {
        my $report_version= $version || 'known';
        my @errors;
        foreach my $e ($spec->errors) {
            next if $e=~/specification URL/ && $check_current;
            push @errors,$e;
        }
        if (@errors) {
            my $errorname='metayml_conforms_'.($check_current?'spec_current':'to_known_spec');
            $d->{error}{$errorname} = [$report_version, @errors];
            return 0;
        }
    }
    return 1;
}

q{Barbies Favourite record of the moment:
  Nine Inch Nails: Year Zero};

__END__

=pod

=head1 NAME

Module::CPANTS::Kwalitee::MetaYML - Checks data availabe in META.yml

=head1 SYNOPSIS

Checks various pieces of information in META.yml

=head1 DESCRIPTION

=head2 Methods

=head3 order

Defines the order in which Kwalitee tests should be run.

Returns C<11>.

=head3 analyse

C<MCK::MetaYML> checks C<META.yml>.

=head3 kwalitee_indicators

Returns the Kwalitee Indicators datastructure.

=over

=item * metayml_is_parsable

=item * metayml_has_license

=item * metayml_conforms_spec_1_0

=item * metayml_conforms_known_spec

=item * metayml_conforms_spec_current

=item * metayml_declares_perl_version

=back

=head3 check_spec_conformance

    check_spec_conformance($d,$version);

Validates META.yml using Test::YAML::Meta.

=head1 SEE ALSO

L<Module::CPANTS::Analyse>

=head1 AUTHOR

Thomas Klausner, <domm@cpan.org>, http://domm.zsi.at
and Gabor Szabo, <gabor@pti.co.il>, http://www.szabgab.com

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2003-2009  Thomas Klausner
Copyright (C) 2006-2008  Gabor Szabo

You may use and distribute this module according to the same terms
that Perl is distributed under.

=cut
