/******************************************************************************
* Utils
* Utility class for operating on GedcomNodes
* 
* Author:       Mitchell Bowden <mitchellbowden AT gmail DOT com>
* License:      MIT License: http://creativecommons.org/licenses/MIT/
******************************************************************************/

package com.msbmsb.genealoj;

import com.msbmsb.genealoj.GedcomNode;

import java.util.List;
import java.util.ArrayList;

public class Utils {
  /**
   * List of tags often referred to
   */
  public static String INDIVIDUAL_TAG = "INDI";
  public static String FAMILY_TAG = "FAM";
  public static String HUSBAND_TAG = "HUSB";
  public static String WIFE_TAG = "WIFE";
  public static String CHILD_TAG = "CHIL";

  /**
   * This class is intended to contain static functions, so disable constructing
   */
  private Utils() { }

  /**
   * Get all the individuals found on the given root node
   * @param root the GedcomNode to use as a root for level=0 nodes
   * @return a List<GedcomNode> containing all individual nodes
   */
  public static List<GedcomNode> getIndividuals(GedcomNode root) {
    return root.getChildrenWithTag(INDIVIDUAL_TAG);
  }

  /**
   * Get all the families found on the given root node
   * @param root the GedcomNode to use as a root for level=0 nodes
   * @return a List<GedcomNode> containing all family nodes
   */
  public static List<GedcomNode> getFamilies(GedcomNode root) {
    return root.getChildrenWithTag(FAMILY_TAG);
  }

  /**
   * Is this token of a gedcom line a reference?
   * @param tok the token to check
   * @return true if token is a reference;
   *         false otherwise
   */
  public static boolean isReference(String tok) {
    return tok.startsWith("@") && tok.endsWith("@");
  }

  /**
   * Is this token of a gedcom line an individual?
   * @param tok the token to check
   * @return true if token is a individual;
   *         false otherwise
   */
  public static boolean isIndividual(String tok) {
    return tok.equals(INDIVIDUAL_TAG);
  }

  /**
   * Get a list of IndividualNodes using the references found in a family node
   * @param root the GedcomNode to use as a root for level=0 nodes
   * @param famRef list of GedcomNodes that are references in the family node
   */
  public static List<IndividualNode> getIndividualsFromFamRef(GedcomNode root,
                                                      List<GedcomNode> famRef) {
    List<IndividualNode> indis = new ArrayList<IndividualNode>();
    for(GedcomNode n : famRef) {
      String ref = n.data();
      if(isReference(ref)) {
        GedcomNode refNode = root.getReferencedNode(ref);
        if(refNode != null) {
          try {
            // attempt to cast to IndividualNode
            IndividualNode indi = (IndividualNode) refNode;
            indis.add(indi);
          } catch(ClassCastException cce) {
            // if the cast fails, just move on
            continue;
          }
        }
      }
    }

    return indis;
  }
}

@@ -757,16 +757,101 @@
  %22CHIL%22;
+%0A  public static String PLACE_TAG = %22PLAC%22;%0A  public static String NAME_TAG = %22NAME%22;
 %0A%0A  /**%0A
@@ -1277,32 +1277,1500 @@
 DUAL_TAG);%0A  %7D%0A%0A
+  /**%0A   * Get all the individuals from this root node that have no parents%0A   * @param root the GedcomNode to use as a root for level=0 nodes%0A   * @return a List%3CGedcomNode%3E containing all individual from root%0A   *          that do not have parents%0A   */%0A  public static List%3CIndividualNode%3E getRootIndividuals(GedcomNode root) %7B%0A    List%3CIndividualNode%3E roots = new ArrayList%3CIndividualNode%3E();%0A    List%3CGedcomNode%3E indis = getIndividuals(root);%0A    for(GedcomNode g : indis) %7B%0A      try %7B%0A        // attempt to cast to IndividualNode%0A        IndividualNode i = (IndividualNode) g;%0A        if(i.getParents().size() == 0) %7B%0A          roots.add(i);%0A        %7D%0A      %7D catch(ClassCastException cce) %7B%0A        // if the cast fails, just move on%0A        continue;%0A      %7D%0A    %7D%0A    return roots;%0A  %7D%0A%0A  /**%0A   * Get the farthest ancestor with the same surname from this node%0A   * Assumption: follow patrilineal family naming%0A   * @param node the node from which to search%0A   * @return IndividualNode for the ancestor%0A   *         return value will be equal to node param if %0A   *         there are no parents or no parents share the surname%0A   */%0A  public static IndividualNode getSurnameRoot(IndividualNode node) %7B%0A    IndividualNode anc = node;%0A%0A    List%3CIndividualNode%3E parents = node.getParents();%0A    for(IndividualNode p : parents) %7B%0A      if(p.getSurname() == node.getSurname()) %7B%0A        anc = getSurnameRoot(p);%0A        break;%0A      %7D%0A    %7D%0A%0A    return anc;%0A  %7D%0A%0A
   /**%0A   * Get a
@@ -3003,32 +3003,32 @@
 comNode root) %7B%0A
-
     return root.
@@ -3056,32 +3056,152 @@
 MILY_TAG);%0A  %7D%0A%0A
+  public static List%3CGedcomNode%3E getLocations(GedcomNode root) %7B%0A    return root.getDescendantsWithTag(PLACE_TAG);%0A  %7D%0A%0A
   /**%0A   * Is th

add methods to get root individuals & surname roots