#!/usr/bin/perl

use strict;
use warnings;

use XML::LibXML;
use XML::LibXML::NodeList::Iterator;

my $parser = XML::LibXML->new();

my $doc  = $parser->parse_file( $ENV{HOME} . '/Library/Safari/Bookmarks.plist' );
my $bar  = $doc->findnodes("//dict[string[text() = 'BookmarksBar']]")->shift;
my $menu = $doc->findnodes("//dict[string[text() = 'BookmarksMenu']]")->shift;

my $report = <<'REPORT';
BookmarksBar:
  
  Bookmarks : %5d 
  Folders   : %5d 
  Height    : %5d
  
BookmarksMenu:
  
  Bookmarks : %5d 
  Folders   : %5d 
  Height    : %5d

REPORT

printf( $report,
    $bar->findvalue("count(descendant::dict[string[text() = 'WebBookmarkTypeLeaf']])"),
    $bar->findvalue("count(descendant::dict[string[text() = 'WebBookmarkTypeList']])"),
    height($bar),
    $menu->findvalue("count(descendant::dict[string[text() = 'WebBookmarkTypeLeaf']])"),
    $menu->findvalue("count(descendant::dict[string[text() = 'WebBookmarkTypeList']])"),
    height($menu)
);

sub height {
    my ($node) = @_;

    my $nodelist = $node->findnodes("descendant::dict[string[text() = 'WebBookmarkTypeLeaf']]");

    my $iterator = XML::LibXML::NodeList::Iterator->new($nodelist);

    my $depth = 0;

    while ( my $leaf = $iterator->next() ) {

        my $ancestors = $leaf->findvalue("count(ancestor::dict[string[text() = 'WebBookmarkTypeList']])");

        if ( $ancestors > $depth ) {
            $depth = $ancestors;
        }
    }

    return $depth;
}
