package com.oreilly.jent.annotation.people.util;

/**
 * In general, you may use the code in this book in your programs and 
 * documentation. You do not need to contact us for permission unless 
 * you're reproducing a significant portion of the code. For example, 
 * writing a program that uses several chunks of code from this book does 
 * not require permission. Selling or distributing a CD-ROM of examples 
 * from O'Reilly books does require permission. Answering a question by 
 * citing this book and quoting example code does not require permission. 
 * Incorporating a significant amount of example code from this book into 
 * your product's documentation does require permission.
 * 
 * We appreciate, but do not require, attribution. An attribution usually 
 * includes the title, author, publisher, and ISBN. For example: 
 * 
 *   "Java Enterprise in a Nutshell, Third Edition, 
 *    by Jim Farley and William Crawford 
 *    with Prakash Malani, John G. Norman, and Justin Gehtland. 
 *    Copyright 2006 O'Reilly Media, Inc., 0-596-10142-2."
 *  
 *  If you feel your use of code examples falls outside fair use or the 
 *  permission given above, feel free to contact us at 
 *  permissions@oreilly.com.
 */

import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * A ConfigSet is used to read configuration information from an XML file
 * and provide an easy way for an application to query for specific elements
 * in the XML document that represent configuration information.
 */
public class ConfigSet {
  
  private Document mXMLConfig = null;

  /**
   * Constructor for ConfigReader with a resource reference to the XML config
   * file.
   */
  public ConfigSet(String fileSpec) throws IllegalArgumentException {
    InputStream xmlStr = getClass().getResourceAsStream(fileSpec);
    if (xmlStr != null) {
      try {
        DocumentBuilder docBuilder = 
          DocumentBuilderFactory.newInstance().newDocumentBuilder();
        mXMLConfig = docBuilder.parse(xmlStr);
      }
      catch (ParserConfigurationException pce) {
        throw new IllegalArgumentException("Failed parsing XML config file: " +
                                           pce.getMessage());
      }
      catch (SAXException se) {
        throw new IllegalArgumentException("Parsing error processing XML file: "
                                           + se.getMessage());
      }
      catch (IOException ioe) {
        throw new IllegalArgumentException("Failed loading XML config file: " +
                                           ioe.getMessage());
      }
    }
  }

  /** Constructor taking a pre-parsed Document as the source of the config
   *  data.
   * @param paramSpec
   * @return String
   */
  public ConfigSet(Document data) {
    mXMLConfig = data;
  }
  
  /** Find a named parameter in the loaded config file.  The 
   * <code>paramSpec</code> argument uses a dot-delimited format to indicate
   * the desired element from the XML config file.  For example, if the config 
   * file contains "<app-config><params><name>foobar</name></params>. . .", 
   * then the application can request the "name" element like so:
   * <pre>
   * 
   *     ConfigReader config = new ConfigReader(...);
   *     String name = config.getParameter("app-config.params.name");
   * 
   * </pre>
   * Note that this method is fairly limited in its capabilities.  It does not
   * support multiple paths through the document that match the given element.
   * Instead, it simply returns the value of first matching element that it 
   * finds in the document.  It also only supports element values that can be
   * converted directly to String values.  
   */
  public String getParameter(String paramSpec) {
    String paramVal = null;
    Element currNode = mXMLConfig.getDocumentElement();
    StringTokenizer tokenizer = new StringTokenizer(paramSpec, ".");
    boolean firstOne = true;
    while (tokenizer.hasMoreTokens()) {
      String elem = tokenizer.nextToken();
      if (firstOne) {
        firstOne = false;
        if (currNode.getNodeName().equals(elem)) {
          continue;
        }
        else {
          break;
        }
      }
      NodeList nodes = currNode.getElementsByTagName(elem);
      currNode = (Element)nodes.item(0);
    }
    if (currNode != null) {
      paramVal = currNode.getChildNodes().item(0).getNodeValue();
    }
    return paramVal;
  }
}
