#!/usr/bin/perl -w

use strict;

=head1 NAME

make-zsh-urls -- create F<~/.zsh/urls> hierarchy

=head1 SYNOPSIS

% make-zsh-urls [B<OPTION>] ...

=head1 DESCRIPTION

make-zsh-urls creates a hierarchy of files and directories under
F<~/.zsh/urls> for use by the _urls completion function in the new
completion system of zsh 3.1.6 and higher.

It needs the B<URI::Bookmarks> suite of modules to run, which are
available from CPAN, the Comprehensive Perl Archive Network.
See B<http://www.perl.com/cpan> or L<CPAN> for more information.

The following options are available:

B<--output-dir>, B<-o>   Specify the output directory for the 
                   hierarchy.  Defaults to F<~/.zsh/urls>.

B<--input-file>, B<-i>   Specify the input bookmarks file.
                   Defaults to F<~/.netscape/bookmarks.html>.

B<--root-node>, B<-r>    Specify which folder contains the
                   bookmarks which the hierarchy will be
                   created from.  Defaults to the root
                   of the bookmark collection tree.

=cut

use Getopt::Long;
use URI::Bookmarks::Netscape;
use URI;

my ($out_dir, $input_file, $root_name, $help);
GetOptions('output-dir|o=s' => \$out_dir,
           'input-file|i=s' => \$input_file,
            'root-node|r=s' => \$root_name,
                   'help|h' => \$help)
  or usage();

usage() if $help;

$out_dir ||= "$ENV{HOME}/.zsh/urls";
$input_file ||= "$ENV{HOME}/.netscape/bookmarks.html";

my $bookmarks =
  new URI::Bookmarks(file => $input_file);

my $root = $bookmarks->tree_root();
if ($root_name) {
  my @root_nodes = $bookmarks->name_to_nodes($root_name);
  if (@root_nodes == 0) {
    die "Couldn't find any nodes with name `$root_name'; aborting.\n";
  }
  else {
    if (@root_nodes > 1) {
      warn "Found more than one node with name `$root_name'; " .
           "taking first occurrence.\n";
    }
    $root = $root_nodes[0];
  }
}    

my @bookmark_path = ();
$root->walk_down({callback     => \&pre_callback,
                  callbackback => \&post_callback});

sub pre_callback {
  my ($node, $options) = @_;

  my $depth = $options->{_depth} || 0;
  my $name = $node->name;
  my $type = $node->type;

  if ($type eq 'bookmark') {
    my $url = $node->attribute->{'HREF'};

    # Type A
    my $full = $url;
    $full =~ s@^(https?|ftp|gopher)://@"\L$1/"@ei;
    $full =~ s@file:@@i;
    my ($path, $file) = $full =~ m@(.+)/(.*)@;
    # This is horribly inefficient but I'm too lazy to reimplement mkdir -p
    # Why isn't there a CPAN module for it?
    system '/bin/mkdir',  '-p', "$out_dir/$path" unless -d "$out_dir/$path";
    system 'touch', "$out_dir/$path" unless $full eq "$path/";

    # Type B
    $name =~ s@/@-@g;
    my $bookmark_file = "$out_dir/bookmark/" .
                        (join '/', @bookmark_path) .
                         "/$name";
    open(BOOKMARK, ">$bookmark_file") or die "open >$bookmark_file: $!";
    print BOOKMARK $url, "\n";
    close(BOOKMARK) or die $!;
  }
  elsif ($type eq 'folder' && $depth > 0) {
    print +('  ' x ($depth - 1)), "Processing folder `$name' ...\n";
    push @bookmark_path, $name;

    # Type B
    system '/bin/mkdir',
             '-p',
             "$out_dir/bookmark/" .
             (join '/', @bookmark_path);
  }    

  return 1;
}

sub post_callback {
  my ($node, $options) = @_;

  my $type = $node->type;

  if ($type eq 'folder') {
    my $name = pop @bookmark_path;
  }    
}

sub usage {
  print <<EOF;
Usage: make-zsh-urls [OPTION] ...
  --help, -h         Display this help.
  --output-dir, -o   Specify the output directory for the hierarchy.
                     Defaults to ~/.zsh/urls.
  --input-file, -i   Specify the input bookmarks file.
                     Defaults to ~/.netscape/bookmarks.html.
  --root-node, -r    Specify which folder contains the bookmarks which
                     the hierarchy will be created from.  Defaults to
                     the root of the bookmark collection tree.  
EOF
  exit 0;
}


=head1 AUTHOR

  Adam Spiers <adam@spiers.net>

=head1 COPYRIGHT

  Copyright (c) 1999 Adam Spiers <adam@spiers.net>. All rights
  reserved. This program is free software; you can redistribute it and/or
  modify it under the same terms as Perl or zsh.

=cut
