#!/usr/bin/perl -w
use strict;
use XML::DOM;
use Sort::Key qw(keysort rkeysort);
require "Contact.pm";


# create parser and DOM document
my $parser = new XML::DOM::Parser;
my $doc = $parser->parsefile('address-book.xml');


# For each <contact> element use its info to make a new contact
# object and put it into a list of contacts.
my($i, @info, $contact, @contacts, $val, $elName);
my(@elNames) = qw(first_name middle_name last_name street1 street2 city
                  state zip country email_addr mobile home_phone);
foreach $i ($doc->getElementsByTagName('contact')) {
   @info = ();
   foreach $elName (@elNames) {
      $val = '';
      if (defined $i->getElementsByTagName($elName)->item(0)
             ->getFirstChild) {
         $val = $i->getElementsByTagName($elName)->item(0)
                   ->getFirstChild->getNodeValue();
      }
      push @info, $val;
   }
   $contact = new Contact($info[0], $info[1], $info[2]);
   $contact->setAllInfo(@info);
   push @contacts, $contact;
}


# Do a "Before & After" printing of contacts. The address-book.xml file
# is likely to be sorted already, but sorting would be neccessary when
# adding new contacts and making changes to existing contacts by means
# of a user interface.
print "Possibly unsorted list of contacts:\n";
foreach (@contacts) {print $_->toString() . "\n";}
print "\n";

print "Reverse-sorted list of contacts:\n";
@contacts = rkeysort {$_->getKey()} @contacts;
foreach (@contacts) {print $_->toString() . "\n";}
print "\n";

print "Sorted list of contacts, with all their info:\n";
@contacts = keysort {$_->getKey()} @contacts;
foreach (@contacts) {
   foreach ($_->getAllInfo()) {
      print $_ . "\n";
   }
   print "\n";
}


#---------------------------------------------------------------------
# Everything above is about parsing an XML file and getting a list
# of contacts. Everything below is for doing the opposite.
#---------------------------------------------------------------------


# Create DOM doc, mainly for use as a factory (which is a bit weird).
$doc = new XML::DOM::Document;
my $xmlDecl = $doc->createXMLDecl('1.0', 'UTF-8');
# The next line creates problems. I'll have to work it out later.
#my $dt = $doc->createDocumentType('contacts', 'address-book.dtd');
my $root = $doc->createElement('contacts');


# For each contact object, use its info to create equivalent XML
# nodes with some help from the DOM Document factory methods.
foreach $contact (@contacts) {
   my $newConEl = $doc->createElement('contact');
   $root->appendChild($newConEl);
   @info = ();
   @info = $contact->getAllInfo();
   foreach $elName (@elNames) {
      my $newEl = $doc->createElement($elName);
      my $text = $doc->createTextNode(shift @info);
      $newEl->appendChild($text);
      $newConEl->appendChild($newEl);
   }
}


# Print the XML data to a file.
# XML::DOM::Document::createDocumentType is problematic, so for now I
# have to print the file in a less elegant way than I could otherwise.
$doc->setXMLDecl($xmlDecl);
open XMLFILE, ">output.xml" or die "Cannot open file: $!";
$doc->printToFileHandle(\*XMLFILE);
print XMLFILE "<!DOCTYPE contacts SYSTEM \"address-book.dtd\">\n";
$root->printToFileHandle(\*XMLFILE);
close XMLFILE;


# garbage collection
$doc->dispose;
