#!/usr/bin/perl
#
# Catorise - create and maintain menus corresponding to
# ~~~~~~~~   package sections.            (c) Andrew Flegg 2010.
#                                         Released under the Artistic Licence.

BEGIN { use lib '/opt/catorise/lib'; }

use strict;
use warnings;
use Config::Tiny;


# -- Read pre-stored menu...
#
my %overrides = ();
if (open(IN, "</opt/catorise/menu")) {
  %overrides = map { chomp; split /:\s*/ } grep { !/: other$/ } <IN>;
  close(IN);
}


# -- Valid sections...
#
my %validSections = map { $_ => 1} qw(
  desktop development education games graphics other ovi
  multimedia navigation network office science system utilities
);


# -- Section overrides...
#
my %sectionOverrides = (
  'web'              => 'network',
  'audiovideo'       => 'multimedia',
  'game'             => 'games',
  'settings'         => 'system',
  'utility'          => 'utilities',
);


# -- Find current theme and copy icons...
#
my $theme = '/etc/hildon/theme';
my @icons = keys(%validSections);
push @icons, 'all';
foreach my $s (@icons) {
  my $icon = "app_install_$s.png";
  my $src  = "$theme/backgrounds/$icon";
  $src = "/usr/share/themes/alpha/backgrounds/$icon" unless -f $src;
  system("cp", $src, "/usr/share/icons/hicolor/64x64/hildon/$icon");
}


# -- Back-up hildon.menu if necessary...
#
my $needRestart = 0;
unless (-f '/etc/xdg/menus/hildon.catorise') {
  system('cp', '/etc/xdg/menus/hildon.menu',
               '/etc/xdg/menus/hildon.catorise');
  $needRestart = 1;
}


# -- Loop over all desktop files...
#
my %sections = ();
open(OUT, ">/opt/catorise/menu") or die "Unable to store new menu: $!";
foreach my $desktop (</usr/share/applications/hildon/*.desktop>) {
  $desktop = readlink($desktop) || $desktop;

  # Check it's a launcher icon
  my $config = Config::Tiny->read($desktop)->{'Desktop Entry'};
  next unless $config;
  next if lc($config->{'Type'} || '') ne 'application';
  next if lc($config->{'NoDisplay'} || 'false') eq 'true';

  # Check if there's an override...
  my ($name)  = $desktop =~ /([^\/]+)\.desktop$/;
  my $section = $overrides{$name};

  # -- Check categories in .desktop...
  #
  if (!$section) {
    foreach my $category (split /\;/, lc($config->{'Categories'} || '')) {
      $category = $sectionOverrides{$category} || $category;
      if ($validSections{$category}) {
        $section = $category;
        last;
      }
    }
  }

  # -- Find using dpkg...
  #
  if (!$section) {
    # ...find by package, then
    chomp(my $package = `dpkg -S "$desktop"`);
    if (!$package) {
      print STDERR "Unknown desktop file: $desktop\n";
      next;
    }
    $package =~ s/: .*//;
    $section = (grep { /^Section: / } `apt-cache show "$package"`)[0];
    $section =~ s/.*?: (.+?\/)?//;
    chomp($section);
 
    # Is it Ovi?
    $section = 'ovi' if $section eq 'hidden' &&
                        `apt-cache policy "$package"` =~
                        m!https://downloads.maemo.nokia.com!;
  }


  # -- Additional heuristics...
  #
  $section = $sectionOverrides{$section} || $section || '';
  $section = 'other' unless $validSections{$section};

  # Now we've got the section, store it...
  push @{ $sections{$section} }, $name;
  print OUT "$name: $section\n";
}
close(OUT) or die "Unable to close new menu: $!";


# -- Output the menu...
#
open(OUT, ">/etc/xdg/menus/hildon.menu") or die "Unable to write to menu: $!";
print OUT <<EOH;
<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
 "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">

<Menu>

  <Name>Main</Name>

  <AppDir>/usr/share/applications/hildon</AppDir>
  <DirectoryDir>/opt/catorise/share</DirectoryDir>

  <Layout>
    <Menuname>all</Menuname>
EOH
my $menus = '';
foreach my $s (sort keys %sections) {
  print OUT "    <Menuname>$s</Menuname>\n" unless $s eq 'other';

  $menus .= "  <Menu>\n    <Name>$s</Name>\n".
            "    <Directory>$s.directory</Directory>\n    <Include>\n";
  $menus .= "      <Filename>ovi.desktop</Filename>\n" if $s eq 'ovi';
  foreach my $v (@{ $sections{$s} }) {
    $menus .= "      <Filename>$v.desktop</Filename>\n" unless $s eq 'ovi' and $v eq 'ovi';
  }
  $menus .= "    </Include>\n  </Menu>\n";
}
print OUT <<EOF;
    <Menuname>other</Menuname>
  </Layout>
$menus
  <Menu>
    <Name>all</Name>
     <Directory>all.directory</Directory>
     <Include>              
       <All/>               
     </Include>
  </Menu>
</Menu>                    
EOF
close(OUT) or die "Unable to close menu: $!";


# -- Restart hildon-desktop if necessary...
#
system("killall", "hildon-desktop") if $needRestart;
exit;

