/*
 *	EasyScout Boy Scouts of America tracking software.
 *	http://www.easyscout.org/
 *
 *	Copyright (C) 2000 Conan C. Albrecht
 *	conan@warp.cx
 *
 *	This program is released under the GNU license so tech-savvy
 *	Boy Scouts and others can enhance the program for the use
 *	of all.  Please e-mail changes to my address above so I can
 *	reintegrate into the main program at http://www.easyscout.org/.
 *	This way, all users mutually benefit one another in the spirit of
 *	scouting.
 *
 *	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.
 *
 * 	Any and all changes to the program code must be documented with
 *  date, author name and e-mail, and a short description.
 *
 *	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.
 */

package cx.warp.scout.lookup;

import cx.warp.scout.*;
import cx.warp.scout.file.*;
import net.sourceforge.nanoxml.*;
import java.util.*;
import java.io.*;

/** Static class to create lookup objects (such as the standard list of merit badges, etc) from XML files */
public class XMLLookup {

	public static final String PROPERTIES_FILE = "properties.xml";

	private static boolean initted = false;
	private static Vector meritBadges = null;
	private static Hashtable requiredBadges = null; // which merit badges are required
	private static Vector requiredBadgesVec = null;
	private static Vector leadership = null; // the list of scout leadership positions
	private static Vector leaders = null; // the list of leader's positions
	private static Vector ranknames = null; // the rank names (Scout, Tenderfoot, ...)
	private static Vector versions = null; // the advancement versions
	private static Hashtable directories = null; // the directories list
	
	/////////////////////
	///   Utilities   ///
	/////////////////////

	/** Returns a Reader reference to the given filename in the cx/warp/scout/lookup directory */
	public static Reader getReader(String filename) throws IOException {
		return new InputStreamReader(new XMLLookup().getClass().getResourceAsStream(filename));
	}//main

	/** Initializes all of the lists based upon the properties file */
	protected static synchronized void init() throws DataException {
		// short circuit if we already initialized
		if (initted) {
			return;
		}//if
		
		try {
			Reader xml = getReader(PROPERTIES_FILE);
			XMLElement root = new XML(xml);
			if (root != null) {
				for (Enumeration enum = root.enumerateChildren(); enum.hasMoreElements(); ) {
					XMLElement node = (XMLElement)enum.nextElement();
						
					if (node.getTagName().equals("Directories")) { 				// web-root, image dir, data dir, etc.
						directories = new Hashtable();
						for (Enumeration enum2 = node.enumerateChildren(); enum2.hasMoreElements(); ) {
							XMLElement n = (XMLElement)enum2.nextElement();
							directories.put(n.getTagName(), n.getContents());
						}//for
						
					}else if (node.getTagName().equals("Advancement")) {   // advancement requirements xml files
						versions = new Vector();
						populateVector(node, versions);
						
					}else if (node.getTagName().equals("Ranks")) {         // scout, tenderfoot, etc.
						ranknames = new Vector();
						populateVector(node, ranknames);
					
					}else if (node.getTagName().equals("Leadership")) {    // patrol leader, quartermaster, etc.
						leadership = new Vector();
						populateVector(node, leadership);
						
					}else if (node.getTagName().equals("Leaders")) {       // scoutmaster, den chief, etc.
						leaders = new Vector();
						populateVector(node, leaders);
					
					}else if (node.getTagName().equals("MeritBadges")) {   // list of all merit badges
						meritBadges = new Vector();
						requiredBadges = new Hashtable();
						requiredBadgesVec = new Vector();

						for (Enumeration enum2 = node.enumerateChildren(); enum2.hasMoreElements(); ) {
							XMLElement n = (XMLElement)enum2.nextElement();
							boolean required = false;
							String req = n.getProperty("required");
							String name = n.getContents();
							if (req != null && (req.equals("true") || req.equals("1") || req.equals("yes") || req.equals("on"))) {
								requiredBadges.put(name, name);
								requiredBadgesVec.addElement(name);
							}//if
							meritBadges.addElement(name);
						}//for
						
					}//if
				}//for
			}//if
		
			initted = true;
			
		}catch (Exception e) {
			throw new DataException("Error loading properties XML file.", e);
		}//try
		
	}//init
	
	/** Populates a vector with strings from the XML file */
	public static void populateVector(XMLElement node, Vector vec) {
		if (node != null) {
			for (Enumeration enum = node.enumerateChildren(); enum.hasMoreElements(); ) {
				XMLElement n = (XMLElement)enum.nextElement();
				vec.addElement(n.getContents());
			}//for
		}//if
	}//populateVector
	
	////////////////////////
	///  Getter methods  ///
	////////////////////////
	
	/** Returns an array of Strings listing the possible ranks */
	public static Vector getRankNames() throws DataException {
		init();
		
		return ranknames;
	}//getRankNames
	
	/** Returns an array of Strings listing the possible leadership positions */
	public static Vector getLeadershipPositions() throws DataException {
		init();
				
		return leadership;
	}//getLeadershipPositions
	
	/** Returns an array of Strings listing the possible leadership positions */
	public static Vector getAdultLeadership() throws DataException {
		init();

		return leaders;
	}//getAdultLeadership
	
	/** Returns the given directory */
	public static String directory(String key) throws DataException {
		init();
		
		return (String)directories.get(key);
	}//directory
	
	
	///////////////////////////////
	///  Rank builder methods   ///
	///////////////////////////////
	
	/** Returns the XML definition files */
	public static Vector getRankVersions() throws DataException {
		init();
		
		return versions;
	}//getRankDefinitions
	
	/** Returns a rank Vector with the given xml definition file.  This object is created anew each time the
			method is run, so it's instance is unique and can be modified.  */
	public static Vector getRanks(String filename) throws DataException {
		Vector ranks = new Vector();
		
		try {
			// init the input stream
			Reader xml = getReader(filename.replace(' ','_'));
			XMLElement root = new XML(xml);
			if (root != null) {
				for (Enumeration enum = root.enumerateChildren(); enum.hasMoreElements(); ) {
					XMLElement rank = (XMLElement)enum.nextElement();
					if (rank.getTagName().equals("Rank")) {
						String name = rank.getProperty("name");
						if (name != null) {
							// create the new rank object and add to the vector
							FileRankObject rankObject = new FileRankObject(name);
							ranks.addElement(rankObject);
									
							// populate the new rank object with the sub-requirements
							populateRank(rankObject, rank.enumerateChildren()); 
						}//if
					}//if
				}//for
			}//if
			
		}catch (Exception e) {
			throw new DataException("Error populating new Scout's requirements!", e);
		}//try
		
		return ranks;
	}//init
	
	/** Populates a specific rank with all sub-requirements */
	public static void populateRank(FileRankObject rankObject, Enumeration requirements) throws Exception {
		if (requirements != null) {
			while (requirements.hasMoreElements()) {
				XMLElement requirement = (XMLElement)requirements.nextElement();
				if (requirement.getTagName().equals("Requirement")) {
					String index = requirement.getProperty("index");
					String text = requirement.getContents();
					if (index != null && !index.equals("") && text != null) {
						FileRequirement reqObject = new FileRequirement(index, text);
						rankObject.addElement(reqObject);
					}//if
						
				}else if (requirement.getTagName().equals("MeritBadgeCount")) {
					try {
						rankObject.setMeritBadgeCount(Integer.parseInt(requirement.getContents()));
					}catch (Exception e) { }
						
				}else if (requirement.getTagName().equals("RequiredCount")) {
					try {
						rankObject.setRequiredCount(Integer.parseInt(requirement.getContents()));
					}catch (Exception e) { }
						
				}//if
			}//while
		}//if
	}//populate
	
	////////////////////////////
	///   Merit badge list   ///
	////////////////////////////
	
	/** Returns a Vector of merit badge names.  This list is the same object each time (it must be cloned if changes
	    are to be made on it) */
	public static Vector getMeritBadges() throws DataException {
		init();
		
		return meritBadges;
	}//getMeritBadges
	
	/** Returns a Vector of required merit badge names */
	public static Vector getRequiredMeritBadges() throws DataException {
		init();
		
		return requiredBadgesVec;
	}//getRequiredMeritBages
	
	/** Returns whether a given merit badge is required or not */
	public static boolean isRequired(String badgename) throws DataException {
		init();
		
		if (requiredBadges.get(badgename) == null) {
			return false;
		}else{
			return true;
		}//if
	}//isRequired
	
	
	

}//XMLLookup
