#!/usr/bin/env perl
use strict;
use warnings;
use SMT::Agent::Utils;
use XML::Writer;
use XML::XPath;
use XML::XPath::XMLParser;

sub jobhandler
{
  my ($jobtype, $jobid, $args, $verbose) =  @_;

  SMT::Agent::Utils::logger("jobhandler for inventory called", $jobid);
  SMT::Agent::Utils::logger("inventory runs jobid \"$jobid\"", $jobid);
  SMT::Agent::Utils::error("wrong job handler: \"inventory\" cannot handle \"$jobtype\"", $jobid) if ( $jobtype ne "inventory" );


  my $jobParser = XML::XPath::XMLParser->new(xml => $args);
  my $jobTree;
  eval { $jobTree = $jobParser->parse(); };
  SMT::Agent::Utils::error("xml data is not parsable", $jobid) if ($@);
  my $xp = XML::XPath->new(context => $jobTree);
  eval { SMT::Agent::Utils::error("no argument section found for this job", $jobid) unless ( $xp->exists('/arguments[1]', $jobParser)); };
  my $argSet;
  eval { $argSet = $xp->findnodes('/arguments[1]', $jobTree) };
  SMT::Agent::Utils::error("could not extract arguments section from job xml", $jobid) if ($@);
  SMT::Agent::Utils::error("too many argument sections found for this job", $jobid) unless ( (defined $argSet) && ($argSet->size() == 1) );
  my $arg = $argSet->pop();

  my $w = undef;
  my $resxml = '';
  $w = new XML::Writer( OUTPUT => \$resxml, DATA_MODE => 1, DATA_INDENT => 2 );
  SMT::Agent::Utils::error("Unable to create an result XML snippet for the current job.", $jobid) unless $w;
  $w->startTag('results');

  my $softwareSet;
  eval { $softwareSet = $xp->findnodes('/arguments[1]/refresh-software[@type]', $jobTree) };
  unless ($@ || not defined $softwareSet)
  {
      # handle the software types
      foreach my $_node ($softwareSet->get_nodelist()) {
          my $_type = $_node->getAttribute('type');
          if ( $_type eq 'packages' )
          {
              # search packages
              my $err = 0;
              open ALLPACKAGES, 'zypper -q -x se -s |' or $err = 1;
              if ($err)
              {
                  $w->emptyTag('software', ( type => $_type, error => "Error: Could not query $_type information."));
                  next;
              }
              my $allPackages = do { local $/; <ALLPACKAGES> };
              close ALLPACKAGES;
              my $packageParser = XML::XPath::XMLParser->new(xml =>  $allPackages);
              my $packageTree;
              eval { $packageTree = $packageParser->parse(); };
              SMT::Agent::Utils::error("could not parse zypper xml data about packages", $jobid) if ($@);
              my $packSet;
              eval { $packSet = $xp->findnodes('/stream[1]/search-result[1]/solvable-list[1]/solvable[@status="installed"]', $packageTree); };
              if ($@ || not defined $packSet)
              {
                  $w->emptyTag('software', ( type => $_type, error => "Error: Could not parse data for package type $_type."));
                  SMT::Agent::Utils::logger("Could not query $_type information for inventory job.", $jobid);
                  next;
              }

              $w->startTag('software', ( type => $_type ));
              foreach my $_n ($packSet->get_nodelist()) {
                  next unless defined $_n;
                  my $_s = 'unknown';
                  $_s = 'Installed'               if $_n->getAttribute('status') eq 'installed';
                  $_s = 'Not installed'           if $_n->getAttribute('status') eq 'not-installed';
                  $_s = 'Other version installed' if $_n->getAttribute('status') eq 'other-version';
                  $w->dataElement('package', $_n->getAttribute('name'), ( catalog => $_n->getAttribute('repository'),
                                                                          version => $_n->getAttribute('edition'),
                                                                          arch    => $_n->getAttribute('arch'),
                                                                          type    => $_n->getAttribute('kind'),
                                                                          status  => $_s ));
              }
              $w->endTag('software');
          }
          elsif ( $_type eq 'patches' )
          {
              # search patches
              my $err = 0;
              open ALLPATCHES, 'zypper -x list-patches --all |' or $err = 1;
              if ($err)
              {
                  $w->emptyTag('software', ( type => $_type, error => "Error: Could not query $_type information."));
                  SMT::Agent::Utils::logger("Could not query $_type information for inventory job.", $jobid);
                  next;
              }
              my $allPatches = do { local $/; <ALLPATCHES> };
              close ALLPATCHES;
              my $patchParser = XML::XPath::XMLParser->new(xml =>  $allPatches);
              my $patchTree;
              eval { $patchTree = $patchParser->parse(); };
              SMT::Agent::Utils::error("could not parse zypper xml data about patches", $jobid) if ($@);
              my $patchSet;
              eval { $patchSet = $xp->findnodes('/stream[1]/update-status[1]/update-list[1]/update', $patchTree); };
              if ($@ || not defined $patchSet)
              {
                  $w->emptyTag('software', ( type => $_type, error => "Error: Could not parse data for package type $_type."));
                  SMT::Agent::Utils::logger("Could not query $_type information for inventory job.", $jobid);
                  next;
              }

              $w->startTag('software', ( type => $_type ));
              foreach my $_n ($patchSet->get_nodelist()) {
                  next unless defined $_n;
                  my $_s = 'Unknown';
                  $_s = 'Needed'     if $_n->getAttribute('status') eq 'needed';
                  $_s = 'Not needed' if $_n->getAttribute('status') eq 'not needed';

                  my $_sourceSet = $xp->findnodes('source[1][@alias]', $_n);
                  my $_catalog = '';
                  if ($_sourceSet && $_sourceSet->size() > 0)
                  {
                      $_catalog = $_sourceSet->pop()->getAttribute('alias');
                  }

                  $w->dataElement('patch', $_n->getAttribute('name'), ( catalog  => $_catalog,
                                                                        version  => $_n->getAttribute('edition'),
                                                                        arch     => $_n->getAttribute('arch'),
                                                                        type     => $_n->getAttribute('kind'),
                                                                        category => $_n->getAttribute('category'),
                                                                        status   => $_s ));
              }
              $w->endTag('software');
          }
          else
          {
              $w->emptyTag('software', ( type => $_type, error => "Error: No handler to query software information of the type: $_type"));
          }
      }
  }
  $w->endTag('results');
  $w->end();

  return (
    stdout   => '',
    stderr   => '',
    exitcode => (defined $resxml) ? 0 : 1,
    success  => (defined $resxml) ? "true" : "false",
    result   => $resxml,
    message  => (defined $resxml) ? "inventory successfully finished" : "inventory failed"
  );

}

SMT::Agent::Utils::logger ("successfully loaded handler for jobtype \"inventory\"");

return 1;

