# duck - check for upstream metadata files
# Copyright (C) 2016 Simon Kainz <skainz@debian.org>
# Copyright (C) 2022 Baptiste Beauplat <lyknode@cilg.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# he Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# On Debian GNU/Linux systems, the complete text of the GNU General
# Public License can be found in `/usr/share/common-licenses/GPL-2'.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, you can find it on the World Wide
# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.

package DUCK::appstream;

use strict;
use warnings;
use autodie;
use Path::Class;
use XML::XPath;
use XML::XPath::XMLParser;

my @xmlfiles;
my @elements = (
    '//screenshots/screenshot',
    '//url',
    '//icon[@type="remote"]',
    '//updatecontact'
);

# mappings for element -> check method
my $defaultmethod = "URL";
my $mapping       = {
    "updatecontact" => "Email"
};

sub proc($;$;$;$;$);
sub guess_type($);

my %options = (
    "A" => "  -A\t\tskip processing of appstream file"
);

sub opts() {
    return keys %options;
}

sub desc() {
    my $r;

    foreach (sort keys %options) {
        $r .= $options{$_} . "\n";
    }

    return $r;
}

sub run() {
    my ($sname, $params, $entries_ref) = @_;
    my %opt = %$params;

    if (!$opt{A}) {
        # get list of all *appstream* files
        dir('.')->recurse(
            callback => sub {
                my $file = shift;

                if ($file =~ /\.appdata/) {
                    push @xmlfiles, $file;
                }
            }
        );
    }

    foreach my $f (@xmlfiles) {
        foreach my $ex (@elements) {
            my $xp;

            undef $@;
            eval {$xp = XML::XPath->new(filename => $f);};

            if ($@) {
                next;
            }

            my $nodeset;

            eval {$nodeset = $xp->find($ex);};

            if ($@) {
                next;
            }

            if (!$nodeset) {
                next;
            }

            foreach my $node ($nodeset->get_nodelist) {
                my $parent = $node->getParentNode();
                my @pfad;

                push @pfad, $node->getName();

                while ($parent->getName()) {
                    push @pfad, $parent->getName();

                    $parent = $parent->getParentNode();
                }

                my @childNodes = $node->getChildNodes();

                foreach my $cn (@childNodes) {
                    my $s      = DUCK->extract_url($cn->string_value);
                    my $method = $defaultmethod;

                    if ($mapping->{$node->getName()}) {
                        $method = $mapping->{$node->getName()};
                    }

                    if ($s && $cn->getName()) {
                        push(
                            @$entries_ref,
                            [
                                $f . ": "
                                    . join("->", $method, reverse @pfad) . "->"
                                    . $cn->getName(),
                                $method,
                                $s,
                                $s,
                                {
                                    filename  => $f,
                                    certainty => "certain",
                                    url       => $s,
                                    verbose   => $f . ": "
                                        . join("->", $method, reverse @pfad)
                                        . "->"
                                        . $cn->getName(),
                                    checkmethod => $method
                                }
                            ]
                        );
                    }
                }
            }
        }
    }

    return;
}

1;
