/**********************************************************
 * ContactReport accepts a first name and last name 
 * as command-line parameters. The class then parses the AddressBook.xml file,
 * creating the DOM object (Document) and searches through the DOM for the
 * entered first name and last name node combination. If they're found, the
 * program then traverses backward up the node tree and prints out the relevant
 * content from the nodes that comprise that contact.
 * 
 * 16-Oct-2004 Works but I don't like the output--not very readable. I also
 * want to output the info not necessarily in the order that it's input. 
 * 
 * 28-OCT-2004 Updated to use two different methods to process the subnodes.
 * One method uses the element tags to display some info, the 
 * other method doesn't display the element tag. The order of the output
 * is deliberately different than the structure of the tree, to make a more
 * readable report.
 * 
 * Kelli Wiseth
 *
 *
 * XML and Web Services class | NDNU 
 *
 ***********************************************************
 */
 
// Java core packages
import java.io.*;
import java.util.regex.*;

// Java standard extensions
import javax.xml.parsers.*;
import javax.xml.transform.*;

// third-party libraries
import org.w3c.dom.*;
import org.w3c.dom.traversal.*; 
import org.xml.sax.*;

public class ContactReport 
{
   String findFirstname = "";
   String findLastname = "";
   String filename = "AddressBook.xml";
   String nodeValue = " ";
   String textToPrint = "";
   
   boolean lastNameExists = false;
   boolean firstNameExists = false;

   DocumentBuilder addressBookParser;
   Document addressBook;
   Element contact;
   int nodeType;
      
   public ContactReport( String findFirstname, String findLastname )
   {
   
   // parse XML, create DOM tree, and find the contact
   try 
   {

   // obtain default parser
   DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
   dbf.setValidating( false );

   DocumentBuilder addressBookParser = dbf.newDocumentBuilder();
   Document addressBook = addressBookParser.parse( new File( filename ) );
   addressBook.getDocumentElement().normalize();
   String firstnameLookup = findFirstname;
   String lastnameLookup = findLastname;
   String spouseName = "";
   NodeList contactsAll = addressBook.getElementsByTagName("Contact");
   NodeList namesAll = addressBook.getElementsByTagName("Name");
   
   for (int ctr1 = 0; ctr1 < contactsAll.getLength(); ctr1++) 
    {
     /*Setup the Nodes in the DOM that we need to get to in order to find the 
      * last name element and subsequently, the first name element.  Cast to 
      * Element as required in to obtain Element tag names and create NodeLists
      * within our found object that comprise the nodes of interest
     */
      

     Node contactName = namesAll.item(ctr1);
     Element names = (Element)namesAll.item(ctr1);
     NodeList lastNameList = names.getElementsByTagName("Last");
     Node lastNameElement =  lastNameList.item(0);
     Node lastNameTextNode = lastNameElement.getFirstChild();
     String lastNameText = lastNameTextNode.getNodeValue().trim();
     NodeList firstNameList = names.getElementsByTagName("First");
     Element firstNameElement = (Element)firstNameList.item(0);
     Node firstNameTextNode = firstNameElement.getFirstChild();
     String firstNameText = firstNameTextNode.getNodeValue().trim();
     if ( lastNameText.equalsIgnoreCase(lastnameLookup) )
        {
        lastNameExists=true;
           if ( firstNameText.equalsIgnoreCase( firstnameLookup ) ) 
              {
              firstNameExists=true;
              Node foundContactName = contactName;
              String foundNickname = names.getAttribute("Nickname");
              Node foundPrimaryInfo = foundContactName.getParentNode();
              Node foundContactRootNode = foundPrimaryInfo.getParentNode();
              Node foundPersonalInfo = foundContactRootNode.getNextSibling();
              Element contactSpecsSubDoc = (Element)foundContactRootNode;
            
              NodeList contactHomeAddress = contactSpecsSubDoc.getElementsByTagName("HomeAddress");
              NodeList contactEmail = contactSpecsSubDoc.getElementsByTagName("Email");
              NodeList contactPhones = contactSpecsSubDoc.getElementsByTagName("Phones");
              NodeList contactWebsitePers = contactSpecsSubDoc.getElementsByTagName("Website");
              NodeList contactWorkAddress = contactSpecsSubDoc.getElementsByTagName("WorkAddress");
              NodeList contactWorkPhones = contactSpecsSubDoc.getElementsByTagName("WorkPhones");
              NodeList contactWebsiteWork = contactSpecsSubDoc.getElementsByTagName("WorkWebsite");
              NodeList contactDates = contactSpecsSubDoc.getElementsByTagName("Dates");
              NodeList contactNotes = contactSpecsSubDoc.getElementsByTagName("Notes");
              NodeList contactSpouse = contactSpecsSubDoc.getElementsByTagName("Spouse");
              NodeList contactChildren = contactSpecsSubDoc.getElementsByTagName("Children");
              NodeList contactcNames = contactSpecsSubDoc.getElementsByTagName("cName");
              
              /* Search through all the nodes of our foundContact node and then call the
               * method to iterate through that sub-structure and print out what we want.
               * In some cases, we call the method to print the element tags as well, but 
               * in many cases, I don't want to see the element tags.
               */
              
              
              if (foundNickname.equals(""))
                 {
                 System.out.println("\n\tContact report from address book for " + 
                                 firstNameText + " " + lastNameText + ":");
                 }
              else
                 {
                 System.out.println("\n\tContact report from address book for " + 
                                 firstNameText + " " + lastNameText + ", aka \"" + foundNickname + "\" :");
                 }
             
                    
              if (contactHomeAddress.getLength() > 0)
                 {
                 System.out.print("\n\tPersonal address and phone lines: \n" );
                 for (int a = 0; a < contactHomeAddress.getLength(); a++)
                      {
                      Element homeAddress = (Element)contactHomeAddress.item(a);
                      System.out.println("\t"+ getNodeTextNoElements(homeAddress));
                      }
                  }
                  
              if (contactPhones.getLength() > 0)
                 {
                  for (int p = 0; p < contactPhones.getLength(); p++)
                     {
                     Node homePhones = contactPhones.item(p);
                     System.out.println("\t"+ getNodeTextWithElements(homePhones));
                     }
                 }
      
               
              if (contactDates.getLength() > 0)
                 {
                 System.out.print("\n\tDates to remember: \n");
                 
                 for (int d = 0; d < contactDates.getLength(); d++)
                     {
                     Node dates = contactDates.item(d);
                     System.out.println("\t" + getNodeTextWithElements(dates));
                     } 
                  }
                 
              if (contactSpouse.getLength() > 0)
                 {
                 System.out.print("\n\tSpouse's name and birthday: ");
               
                 for (int s = 0; s < contactSpouse.getLength(); s++)
                     {
                     Element spouse = (Element)contactSpouse.item(s);
                     String spousesBirthday = spouse.getAttribute("sBirthday");
                     spouseName += getNodeTextNoElements(spouse);
                     System.out.print(spouseName + " " + spousesBirthday);
                     }
                 	
                 }
              if (contactChildren.getLength() > 0)
                 {
                 
                  System.out.print("\n\t" + foundNickname +  " and" + spouseName + 
                        "have " + contactChildren.getLength() + " children:\n");
                         
                   for (int y = 0; y < contactChildren.getLength(); y++)
                      {
                       
                       // in this loop get each Children node element
                       
                       Element offspringChild = (Element)contactChildren.item(y);
                       Element cNameElement = (Element)contactcNames.item(y);
                       Node cNameNode = contactcNames.item(y);
                       NodeList cFirstNameList = cNameElement.getElementsByTagName("First");
                       NodeList cLastNameList = cNameElement.getElementsByTagName("Last");
                      
                       Element cFirstName = (Element)cFirstNameList.item(0);
                       Element cLastName = (Element)cLastNameList.item(0);
                       String cFirstNameText = cFirstName.getNodeValue();
                       String cLastNameText = cLastName.getNodeValue();
                       String childsBirthday = offspringChild.getAttribute("cBirthday");
                       System.out.println("\t" + getNodeTextNoElements(cNameNode) + " " + "\t[Born " + childsBirthday + "]");
                      }
              
                   }
                                   
              System.out.println("\n\n\tBusiness address and phones: ");

              if (contactWorkAddress.getLength() >0)
                 {
                 for (int w = 0; w < contactWorkAddress.getLength(); w++)
                     {
                     Node workAddress = contactWorkAddress.item(w);
                     System.out.println("\t"+ getNodeTextNoElements(workAddress));
                     }
                 }
              
               
              if (contactWorkPhones.getLength() > 0)
                 {
                 for (int wP = 0; wP < contactWorkPhones.getLength(); wP++)
                     {
                     Node workPhones = contactWorkPhones.item(wP);
                     System.out.println("\t"+ getNodeTextWithElements(workPhones));
                     }
                  }
                  
                 
               if (contactEmail.getLength() > 0)
                  {
                   System.out.print("\n\tInternet points of contact:");
                   Element emailAddresses = (Element)contactEmail.item(0);
                   String alternateEmail = emailAddresses.getAttribute("AlternativeEmail");
                   NodeList workOrHome = emailAddresses.getChildNodes();
                   
                   if (workOrHome.getLength() > 0)
                       {
                       System.out.print("\n\tPrimary email address:");
                       for (int e = 0; e < workOrHome.getLength(); e++)
                         {
                         Node mainEmail = workOrHome.item(e);
                         System.out.print(getNodeTextNoElements(mainEmail));
                         }
                       }

                     if (alternateEmail=="");

                     else
                        System.out.print("\n\tAlternate email: " + alternateEmail);
                   }
                  
             
               if (contactWebsitePers.getLength() > 0) 
                   {
                   	System.out.print("\n\tPersonal website: " );
                   	for (int b = 0; b < contactWebsitePers.getLength(); b++)
                   	    {
                   	  	 Node contactWebsite1 = contactWebsitePers.item(b);
                   	     System.out.print(getNodeTextNoElements(contactWebsite1));
                   	     }
                   }
                   
               if (contactWebsiteWork.getLength() > 0)
                  {
                  System.out.print("\n\tBusiness website: ");
                  for (int ws = 0; ws < contactWebsiteWork.getLength(); ws++)
                      {
                       Node contactWebsite2 = contactWebsiteWork.item(ws);
                       System.out.print(getNodeTextNoElements(contactWebsite2));
                   	   }
                   
                  }
       
               
               if (contactNotes.getLength() > 0)
                 {
                 System.out.print("\n\n\tNotes:\n");
                 
                 for (int d = 0; d < contactNotes.getLength(); d++)
                     {
                     Node notes = contactNotes.item(d);
                     System.out.println("\t" + getNodeTextNoElements(notes));
                     } 
                  }
               else
                  {
                  System.out.print("\n\n\tNo other information about " + firstNameText + " " + lastNameText +
                               " in the AddressBook. \n");
                  }                  
        
              } // if firstNameText equals firstnameLookup
                     
        } // if lastName.equals lastnameLookup
           
    } //for-loop ctr1
              

    if ((!lastNameExists) || (lastNameExists) && (!firstNameExists))
      System.out.println("Contact named " + findFirstname + " " + findLastname + 
                " not found in the address book \nor is not a primary contact.");

   
   } //close try block
   
   /* The parser exceptions aren't needed, since we're not creating a 
    * DOM structure except by passing in a pre-validated XML file, and
    * we've turned off validation. However, the IOException will be raised
    * when there are problems with the XML filename being passed. 
   */
   
   
   // handle exception thrown by DocumentBuilder
   catch ( ParserConfigurationException parserException ) 
   {
   parserException.printStackTrace();
   }
      
   // handle exception thrown by Parser
   catch ( SAXException saxException ) 
   {
   saxException.printStackTrace();         
   }
      
   // handle exception thrown when reading data from file
   catch ( IOException ioException ) 
   {
    System.out.print("Syntax: java ContactReport <firstname> <lastname> \n");
    System.out.print("Please enter contact's first name and last name, as in: \n\n");
    System.out.print("              java ContactReport marie sklodowska \n");
    System.exit( 1 );
    }
 
  } //close constructor
  
   public String getNodeTextNoElements(Node node)
  {
   String textToPrint = "";
   
   if (node.hasChildNodes())
      {
      NodeList children = node.getChildNodes();
        for (int i =0; i < children.getLength(); i++)
           {
            Node child = children.item(i);
            child.normalize();
            int nodeType = child.getNodeType();
              if (nodeType == Node.TEXT_NODE)
                 if((child.getNodeValue()==null) || (child.getNodeValue().equals("\t")) || (child.getNodeValue().trim().equals("\n")))
                 {
                 //do nothing textToPrint += "";
                 }
                 else 
                 {
                 textToPrint += child.getNodeValue().trim() + " ";
                 }

               textToPrint += getNodeTextNoElements(child);
              
             } //close for loop
       
       }  // close topmost if
       
    return textToPrint;
   
  } // close getNodeTextNoElements method
  
  
   public String getNodeTextWithElements(Node node)
  {
   String textToPrint = "";
 
    if (node.hasChildNodes())
      {
      NodeList children = node.getChildNodes();
        for (int i = 0; i < children.getLength(); i++)
           {
            Node child = children.item(i);
            child.normalize();
            int nodeType = child.getNodeType();
            if (nodeType == Node.ELEMENT_NODE)
               {
               	textToPrint += child.getNodeName().trim() + ": ";
               }
            
            if (nodeType == Node.TEXT_NODE)
               if((child.getNodeValue()==null) || (child.getNodeValue().equals("\t")) || (child.getNodeValue().trim().equals("\n")))
                 {
                 //do nothing textToPrint += "";
                 }
                 else 
                 {
                 textToPrint += child.getNodeValue().trim() + " ";
                 }

               textToPrint += getNodeTextWithElements(child);
              
             } //close for loop
       
       }  // close topmost if
       
    return textToPrint;
   
  } // close getNodeTextwithElements method
  
 
   public static void main( String args[] )
   {
    if ( args.length < 2 ) 
       {
        System.out.print("Syntax: java ContactReport <firstname> <lastname> \n");
        System.out.print("Please enter contact's first name and last name, as in: \n\n");
        System.out.print("              java ContactReport marie sklodowska \n");
        System.exit( 1 );
        }
    ContactReport report = new ContactReport( args[0], args[1] );
  
   }//close main method
   
} //close class ContactReport
