//Preferences file class
//Created for Building XML Applications
//By Ethan Cerami and Simon St.Laurent
//Updated 25 July 1999 for Sun Technology Release 2


import java.io.*;
import java.util.*;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.InputSource;
import com.sun.xml.tree.*;
import com.sun.xml.parser.Resolver;
import org.w3c.dom.*;

public class prefs {
	private static	String	fileLocation;
	private static 	String	uri;
	private static	XmlDocument	doc;
	private 		InputSource	input;


public prefs (String fileName){

try { 
	    // turn the filename into an input source
	    input = Resolver.createInputSource (new File (fileName));

	    // build the tree-false means don't validate
	    doc = XmlDocument.createXmlDocument (input, false);

		uri="file:"+new File (fileName).getAbsolutePath();
		fileLocation=fileName;

//Note: using try and catch in modules that use this code is
//recommended.  You may want to turn off the stack tracing for
//production code.

//error handling for parse errors - to console.
  } catch (SAXParseException err) {
	System.out.println ("** Parsing error" 
	   + ", line " + err.getLineNumber ()
	   + ", uri " + err.getSystemId ());
	System.out.println("   " + err.getMessage ());
	err.printStackTrace ();

  } catch (SAXException e) {
	Exception	x = e;
	if (e.getException () != null)
	  x = e.getException ();
	x.printStackTrace ();

//error handling for file I/O, other errors
  } catch (Throwable t) {
	t.printStackTrace ();
	}
}

public String getValue(String path){
Node currentElement;
Node testNode;
Node	prefNode;
NodeList childElements;
int 	nodeCounter;
String tokenName;
String prefValue;

//start by collecting the root element
currentElement=doc.getDocumentElement();

//walk through the document structure to find leaf
//element info.  Note that the root element is treated
//as a container and ignored.

StringTokenizer tokens=new StringTokenizer(path,".");
tokenName=tokens.nextToken();
tokens=new StringTokenizer(path,".");
while (tokens.hasMoreTokens())
  {
	tokenName=tokens.nextToken();
	childElements=currentElement.getChildNodes();
	for (nodeCounter=0; 
		nodeCounter<childElements.getLength(); 
		nodeCounter++) {
//check through all nodes for one matching the 
//appropriate element name
		testNode=childElements.item(nodeCounter);

	if (tokenName.equals(testNode.getNodeName())) {

		currentElement=testNode;
	} //endif
   }//endfor
//break to avoid false positives
if (!tokenName.equals(currentElement.getNodeName())) {break;}

}//endwhile
	if (tokenName.equals(currentElement.getNodeName())) {
	//extract data value - should only be one child
		prefNode=currentElement.getFirstChild();
		prefValue=prefNode.getNodeValue();
	}else{
	//not found; return empty string	
		prefValue="";
	}
	
return prefValue;
}

public void setValue(String path, String newValue){
//Most of this code is from getValue.  It would be nice to pull out
//the node-finding code, but I'm not sure what to return
//if no node is found.

Node currentElement;
Node testNode;
Node	prefNode;
NodeList childElements;
int 	nodeCounter;
String tokenName;

//start by collecting the root element
currentElement=doc.getDocumentElement();

//walk through the document structure to find leaf
//element info.  Note that the root element is treated
//as a container and ignored.

StringTokenizer tokens=new StringTokenizer(path,".");
tokenName=tokens.nextToken();
tokens=new StringTokenizer(path,".");
while (tokens.hasMoreTokens())
  {
	tokenName=tokens.nextToken();
	childElements=currentElement.getChildNodes();
	for (nodeCounter=0; 
		nodeCounter<childElements.getLength(); 
		nodeCounter++) {
//check through all nodes for one matching the 
//appropriate element name
		testNode=childElements.item(nodeCounter);
	if (tokenName.equals(testNode.getNodeName())) {
		currentElement=testNode;
	}
   }
//break to avoid false positives
if (!tokenName.equals(currentElement.getNodeName())) {break;}
}
	if (tokenName.equals(currentElement.getNodeName())) {
	//extract data value - should only be one child
		prefNode=currentElement.getFirstChild();
		prefNode.setNodeValue(newValue);
	}else {
	//create the value!  Build more tree!
	System.out.println(currentElement.getNodeName()+","+tokenName);
	Node newElement=doc.createElement(tokenName);
	currentElement.appendChild(newElement);
	currentElement=newElement;
	while (tokens.hasMoreTokens())
	  {
		tokenName=tokens.nextToken();
		newElement=doc.createElement(tokenName);
		currentElement.appendChild(newElement);
		currentElement=newElement;
	}
	prefNode=doc.createTextNode(newValue);
	currentElement.appendChild(prefNode);
}}

public void write() {
//this method is here because finalize() doesn't seem to do anything.
//must be called to save values to prefs file.

	DataOutputStream output;
try	{
	output=new DataOutputStream(new FileOutputStream(fileLocation));
	doc.write(output);
	}
catch (IOException e)	{
	System.err.println ("File problem\n" + e.toString());
	System.exit(1);
	}
}


public static void main (String argv[]) {
	prefs	Preferences;
	String Response;
	switch (argv.length){
	case 1:
		Preferences=new prefs(argv[0]);
		Response="If you get this far, it read the file "+argv[0]+".";
		break;
	case 2:
		Preferences=new prefs(argv[0]);
		Response="The path " +argv[1] +" led to " + Preferences.getValue(argv[1])+".";
		break;
		
	case 3:
		Preferences=new prefs(argv[0]);
		Preferences.setValue(argv[1],argv[2]);
		Response="The value "+argv[2]+" was written to "+argv[1]+" and its current value is "+ Preferences.getValue(argv[1])+". Check the file "+argv[0]+" to see what happened.";
		Preferences.write();
		break;
	default:
		Response="Need the right number (1-3) of arguments!";	
	}
	System.out.println(Response);
}

}


