package com.dbxml.util;

/*
 * dbXML - Native XML Database
 * Copyright (C) 1999-2004  The dbXML Group, L.L.C.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: Configuration.java,v 1.2 2004/02/12 00:17:58 bradford Exp $
 */

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

import org.w3c.dom.*;

/**
 * Configuration is a utility class that allows Configurable objects to
 * easily manage configuration information in a simple and consistent
 * fashion.
 *
 * @see com.dbxml.util.Configurable
 */

public final class Configuration {
   private static final Configuration[] EmptySet = new Configuration[0];

   private Element config;

   public Configuration(Element config) {
      this.config = config;
   }

   public Configuration(Document config) {
      this(config.getDocumentElement());
   }

   /**
    * getElement returns the Element being managed by this
    * Configuration.
    *
    * @return The Configuration Element
    * @throws ReadOnlyException If the Configuration is Read-only
    */
   public Element getElement() {
      return config;
   }

   /**
    * getName returns the name of the Configuration node.
    *
    * @return The Node name
    */
   public String getName() {
      return config.getTagName();
   }

   /**
    * hasAttributes returns whether or not the Configuration node has any
    * attributes associated with it.
    *
    * @return Whether or not attributes exist
    */
   public boolean hasAttributes() {
      return config.getAttributes().getLength() > 0;
   }

   /**
    * getAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public String getAttribute(String name, String defValue) {
      if ( config.hasAttribute(name) )
         return config.getAttribute(name);
      else
         return defValue;
   }

   /**
    * getAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public String getAttribute(String name) {
      return getAttribute(name, null);
   }

   /**
    * getBooleanAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public boolean getBooleanAttribute(String name, boolean defValue) {
      try {
			String defString;
			if ( defValue )
				defString = "1";
			else
				defString = "0";
			
         return "[true][yes][1][y][on]".indexOf("[" + getAttribute(name, defString).toLowerCase() + "]") != -1;
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getBooleanAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public boolean getBooleanAttribute(String name) {
      return getBooleanAttribute(name, false);
   }

   /**
    * getIntAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public int getIntAttribute(String name, int defValue) {
      try {
         return Integer.parseInt(config.getAttribute(name));
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getIntAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public int getIntAttribute(String name) {
      return getIntAttribute(name, 0);
   }

   /**
    * getShortAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public short getShortAttribute(String name, short defValue) {
      try {
         return Short.parseShort(config.getAttribute(name));
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getShortAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public short getShortAttribute(String name) {
      return getShortAttribute(name, (short)0);
   }

   /**
    * getLongAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public long getLongAttribute(String name, long defValue) {
      try {
         return Long.parseLong(config.getAttribute(name));
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getLongAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public long getLongAttribute(String name) {
      return getLongAttribute(name, (long)0);
   }

   /**
    * getFloatAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public float getFloatAttribute(String name, float defValue) {
      try {
         return Float.parseFloat(config.getAttribute(name));
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getFloatAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public float getFloatAttribute(String name) {
      return getFloatAttribute(name, (float)0.0);
   }

   /**
    * getDoubleAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public double getDoubleAttribute(String name, double defValue) {
      try {
         return Double.parseDouble(config.getAttribute(name));
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getDoubleAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public double getDoubleAttribute(String name) {
      return getDoubleAttribute(name, 0.0);
   }

   /**
    * getByteAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public byte getByteAttribute(String name, byte defValue) {
      try {
         return Byte.parseByte(config.getAttribute(name));
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getByteAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public byte getByteAttribute(String name) {
      return getByteAttribute(name, (byte)0);
   }

   /**
    * getCharAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @param defValue The default value
    * @return The attribute value
    */
   public char getCharAttribute(String name, char defValue) {
      try {
         return config.getAttribute(name).charAt(0);
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getCharAttribute returns an attribute from the Configuration node.
    *
    * @param name The attribute name
    * @return The attribute value
    */
   public char getCharAttribute(String name) {
      return getCharAttribute(name, '\0');
   }

   /**
    * listAttributes returns a list of the attribute names that exist for
    * this Configuration node.
    *
    * @return The Attribute names
    */
   public String[] listAttributes() {
      NamedNodeMap map = config.getAttributes();
      String[] result = new String[map.getLength()];
      int size = map.getLength();
      for ( int i = 0; i < size; i++ )
         result[i] = ((Attr)map.item(i)).getName();
      return result;
   }

   /**
    * hasValue returns whether or not the Configuration node has a textual
    * value associated with it.
    *
    * @return Whether or not the node has a text value
    */
   public boolean hasValue() {
      NodeList list = config.getChildNodes();
      return (list.getLength() > 0 && list.item(0).getNodeType() == Node.TEXT_NODE);
   }

   /**
    * getValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public String getValue(String defValue) {
      NodeList list = config.getChildNodes();
      if ( list.getLength() == 1 ) {
         Node n = list.item(0);
         if ( n.getNodeType() == Node.TEXT_NODE || n.getNodeType() == Node.CDATA_SECTION_NODE ) {
            CharacterData cd = (CharacterData)n;
            return cd.getData();
         }
      }
      return defValue;
   }

   /**
    * getValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public String getValue() {
      return getValue(null);
   }

   /**
    * getBooleanValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public boolean getBooleanValue(boolean defValue) {
      try {
         return "[true][yes][1][y][on]".indexOf("[" + getValue().toLowerCase() + "]") != -1;
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getBooleanValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public boolean getBooleanValue() {
      return getBooleanValue(false);
   }

   /**
    * getIntValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public int getIntValue(int defValue) {
      try {
         return Integer.parseInt(getValue());
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getIntValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public int getIntValue() {
      return getIntValue(0);
   }

   /**
    * getShortValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public short getShortValue(short defValue) {
      try {
         return Short.parseShort(getValue());
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getShortValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public short getShortValue() {
      return getShortValue((short)0);
   }

   /**
    * getLongValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public long getLongValue(long defValue) {
      try {
         return Long.parseLong(getValue());
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getLongValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public long getLongValue() {
      return Long.parseLong(getValue());
   }

   /**
    * getFloatValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public float getFloatValue(float defValue) {
      try {
         return Float.parseFloat(getValue());
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getFloatValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public float getFloatValue() {
      return getFloatValue((float)0.0);
   }

   /**
    * getDoubleValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public double getDoubleValue(double defValue) {
      try {
         return Double.parseDouble(getValue());
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getDoubleValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public double getDoubleValue() {
      return getDoubleValue(0.0);
   }

   /**
    * getByteValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public byte getByteValue(byte defValue) {
      try {
         return Byte.parseByte(getValue());
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getByteValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public byte getByteValue() {
      return getByteValue((byte)0);
   }

   /**
    * getCharValue returns the value from the Configuration node.
    *
    * @param defValue The default value
    * @return The value
    */
   public char getCharValue(char defValue) {
      try {
         return getValue().charAt(0);
      }
      catch ( Exception e ) {
         return defValue;
      }
   }

   /**
    * getCharValue returns the value from the Configuration node.
    *
    * @return The value
    */
   public char getCharValue() {
      return getCharValue('\0');
   }

   /**
    * hasChildren returns whether or not the Configuration node has child
    * Configuration elements.
    *
    * @return Whether or not children exist
    */
   public boolean hasChildren() {
      NodeList list = config.getChildNodes();
      int size = list.getLength();
      for ( int i = 0; i < size; i++ )
         if ( list.item(i).getNodeType() == Node.ELEMENT_NODE )
            return true;
      return false;
   }

   /**
    * getChildren returns the child Configuration nodes for this Configuration
    * node.
    *
    * @return The children
    */
   public Configuration[] getChildren() {
      NodeList list = config.getChildNodes();
      if ( list == null )
         return EmptySet;
      List tmp = new ArrayList();
      int size = list.getLength();
      for ( int i = 0; i < size; i++ )
         if ( list.item(i).getNodeType() == Node.ELEMENT_NODE )
            tmp.add(new Configuration((Element)list.item(i)));
      return (Configuration[])tmp.toArray(EmptySet);
   }

   /**
    * processChildren runs through the children of this Configuration and
    * performs prcessing callbacks to the ConfigurationCallback object.
    *
    * @param callback The callback object
    */
   public void processChildren(ConfigurationCallback callback) {
      NodeList list = config.getChildNodes();
      if ( list == null )
         return;
      int size = list.getLength();
      try {
         for ( int i = 0; i < size; i++ )
            if ( list.item(i).getNodeType() == Node.ELEMENT_NODE )
               callback.process(new Configuration((Element)list.item(i)));
      }
      catch ( Exception e ) {
         e.printStackTrace(System.err);
      }
   }

   /**
    * processChildren runs through the children of this Configuration and
    * performs prcessing callbacks to the ConfigurationCallback object.
    *
    * @param callback The callback object
    * @param name The Configuration name to process
    */
   public void processChildren(String name, ConfigurationCallback callback) {
      NodeList list = config.getChildNodes();
      if ( list == null )
         return;

      Node[] nl = new Node[list.getLength()];
      for ( int i = 0; i < nl.length; i++ )
         nl[i] = list.item(i);

      int size = nl.length;

      try {
         for ( int i = 0; i < size; i++ ) {
            Node n = nl[i];
            if ( n.getNodeType() == Node.ELEMENT_NODE ) {
               Element e = (Element)n;
               if ( e.getTagName().equals(name) )
                  callback.process(new Configuration(e));
            }
         }
      }
      catch ( Exception e ) {
         e.printStackTrace(System.err);
      }
   }

   /**
    * getChild returns the first child Configuration node that matches the
    * specified name.
    *
    * @param name The Configuration node name
    * @param create Create Configuration if it doesn't exist
    * @return The child Configuration
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public Configuration getChild(String name, boolean create) {
      NodeList list = config.getChildNodes();
      int size = list.getLength();

      for ( int i = 0; i < size; i++ ) {
         Node n = list.item(i);
         if ( n.getNodeType() == Node.ELEMENT_NODE ) {
            Element e = (Element)n;
            if ( e.getTagName().equals(name) )
               return new Configuration(e);
         }
      }
      
      if ( create )
         return add(name);
      else
         return null;
   }

   /**
    * getChild returns the first child Configuration node that matches the
    * specified name.
    *
    * @param name The Configuration node name
    * @return The child Configuration
    */
   public Configuration getChild(String name) {
      try {
         return getChild(name, false);
      }
      catch ( Exception e ) {
         return null;
      }
   }

   /**
    * add adds a new Configuration node to this Configuration node.
    *
    * @param name The name of the Configuration node
    * @return The new Configuration node
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public Configuration add(String name) {
      Element elem = config.getOwnerDocument().createElement(name);
      config.appendChild(elem);
      return new Configuration(elem);
   }

   /**
    * add adds an existing Configuration node to this Configuration node.
    * Note!  This method does NOT perform a deep copy on the DOM Node that
    * newConfig manages.
    *
    * @param config The Configuration node to add
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void add(Configuration newConfig) {
      Node imported = config.getOwnerDocument().importNode(newConfig.config, true);
      config.appendChild(imported);
      newConfig.config = (Element)imported;
   }

   /**
    * delete deletes this Configuration node from its parent Configuration.
    *
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void delete() {
      if ( config.getParentNode() != null )
         config.getParentNode().removeChild(config);
   }

   /**
    * removeAttribute removes the named attribute from this Configuration.
    *
    * @param name The attribute name
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void removeAttribute(String name) {
      config.removeAttribute(name);
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, String value) {
      config.setAttribute(name, value);
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, boolean value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, int value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, short value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, long value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, float value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, double value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, byte value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setAttribute sets the attribute value for this Configuration.
    *
    * @param name The attribute name
    * @param value The attribute value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setAttribute(String name, char value) {
      config.setAttribute(name, String.valueOf(value));
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(String value) {
      NodeList list = config.getChildNodes();
      if ( list.getLength() == 1 && list.item(0).getNodeType() == Node.TEXT_NODE )
         list.item(0).setNodeValue(value);
      else {
         Text text = config.getOwnerDocument().createTextNode(value);
         config.appendChild(text);
      }
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(boolean value) {
		if ( value )
      	setValue("true");
		else
			setValue("false");
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(int value) {
      setValue(String.valueOf(value));
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(short value) {
      setValue(String.valueOf(value));
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(long value) {
      setValue(String.valueOf(value));
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(float value) {
      setValue(String.valueOf(value));
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(double value) {
      setValue(String.valueOf(value));
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(byte value) {
      setValue(String.valueOf(value));
   }

   /**
    * setValue sets the value of the Configuration node.
    *
    * @param value The New Value
    * @throws ReadOnlyException if the Configuration is read-only
    */
   public void setValue(char value) {
      setValue(String.valueOf(value));
   }
}

