/*
 ******************************************************************************
 * Copyright (C) 2004-2008 International Business Machines Corporation and    *
 * others. All Rights Reserved.                                               *
 ******************************************************************************
 */
package org.unicode.cldr.icu;

//CLDR imports
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.MissingResourceException;
import java.util.StringTokenizer;

import org.unicode.cldr.ant.CLDRConverterTool;
import org.unicode.cldr.util.CLDRFile;
import org.unicode.cldr.util.SimpleFactory;
import org.unicode.cldr.util.XPathParts.Comments;

import com.ibm.icu.dev.tool.UOption;
import com.ibm.icu.impl.ICUData;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceTypeMismatchException;

/**
 * This class is a user runnable class intended to create LDML documents by
 * calling the appropriate ICU API functions and retrieving the data.
 * 
 * @author Brian Rower - IBM - August 2009
 *
 */
public class ICU2LDMLWriter extends CLDRConverterTool
{
	private static final UOption[] options = new UOption[] {
        UOption.HELP_H(),
        UOption.HELP_QUESTION_MARK(),
        UOption.DESTDIR(),
        UOption.VERBOSE(),
        UOption.create("main", 'm', UOption.NO_ARG),
        UOption.create("trans", 't', UOption.NO_ARG),
        UOption.create("coll", 'c', UOption.NO_ARG)
    };
	
	//******************** ENUMS *************************

	//For command line options
	private static final int OP_HELP1 = 0;
	private static final int OP_HELP2 = 1;
	private static final int OP_DESTDIR = 2;
	private static final int OP_VERBOSE = 3;
	private static final int OP_MAIN = 4;
	private static final int OP_TRANS = 5;
	private static final int OP_COLL = 6;
	
	private static final String FILE_SEPERATOR = "\\";
	private static final String LDML_FILE_EXTENSION = ".xml";
	
	private static final String MAIN_FOLDER = "main";
	private static final String COLLATION_FOLDER = "collation";
	private static final String TRANSFORMS_FOLDER = "transforms";
	
	private static final char SEP = '/';
	
	private boolean verbose = false;
	private boolean doMain = false;
	private boolean doTrans = false;
	private boolean doColl = false;
	
	private String outDir = "./";
	
	private String currentLocaleName = null;

	private Hashtable theHash = null;
	
	private static final String COMMENT = "This ldml file was generated by the ICU2LDMLWriter"
										+ " from ICU resource bundle data.\nIf you are looking for the"
										+ " full CLDR version of this document please look in the CLDR repository.";
	
	
	
	public static void main(String[] args)
	{
       	ICU2LDMLWriter w = new ICU2LDMLWriter();
       	w.processArgs(args);
	}

	public void processArgs(String[] args)
	{
		int remainingArgc = 0;
        // for some reason when 
        // Class classDefinition = Class.forName(className);
        // object = classDefinition.newInstance();
        // is done then the options are not reset!!
        for(int i = 0; i < options.length; i++)
        {
            options[i].doesOccur = false;
        }
        try
        {
            remainingArgc = UOption.parseArgs(args, options);
        }
        catch (Exception e)
        {
            printError("(parsing args): "+ e.toString());
            e.printStackTrace();
            usage();
        }
        
        if(options[OP_HELP1].doesOccur || options[OP_HELP2].doesOccur || args.length == 0)
        {
        	usage();
        }
        
        if(options[OP_VERBOSE].doesOccur)
        {
        	verbose = true;
        }
        
        if(options[OP_DESTDIR].doesOccur)
        {
        	outDir = options[OP_DESTDIR].value;
        }
        
        if(options[OP_MAIN].doesOccur)
        {
        	doMain = true;
        }
        if(options[OP_TRANS].doesOccur)
        {
        	doTrans = true;
        }
        if(options[OP_COLL].doesOccur)
        {
        	doColl = true;
        }
        
        //if they specified files, we'll generate those, otherwise we'll generate all possible locale files
        if(remainingArgc > 0)
        {
        	for (int i = 0; i < remainingArgc; i++) 
            {
        		String localeName = args[i];
        		if(localeName.indexOf(".") > 0)
        		{
        			localeName = localeName.substring(0,localeName.indexOf("."));
        			
        		}
        		currentLocaleName = localeName;
                processLocale(args[i]);
            }
        }
        else
        {
        	ULocale[] locales = ULocale.getAvailableLocales();
        	for(int i = 0; i < locales.length; i++)
        	{
        		currentLocaleName = locales[i].getName();
        		processLocale(locales[i]);
        	}
        	ULocale r = new ULocale("root");
        	currentLocaleName = r.getName();
        	processLocale(r);
        }
        
        
        
	}
	 
	private void processLocale(String localeID)
	{
		ULocale temp = new ULocale(localeID);
		if(temp.getName() == null)
		{
			//the localeID given was not valid, exit
			printError("Invalid locale ID: " + localeID);
			System.exit(-1);
		}
		processLocale(temp);
	}
	
	private void processLocale(ULocale locale)
	{
		printInfo("Processing " + locale.getName());
				
		//process each type of possible file...
		//****************************** Main ********************************
		if(doMain || (!(doMain || doTrans || doColl)))
		{
			try
			{
				processMain(locale);
			}
			catch(Exception e)
			{
				printError("Could not produce main locale file: " + getMainPath(locale));
			}
		}
	
		//****************************** Collation *****************************
		if(doColl || (!(doMain || doTrans || doColl)))
		{
			try
			{
				processCollation(locale);
			}
			catch(Exception e)
			{
				printError("Could not produce collation file: " + getCollationPath(locale));
			}
		}
		//**************************** Transforms *******************************
		if(doTrans || (!(doMain || doTrans || doColl)))
		{
			try
			{
				processTransforms(locale);
			}
			catch(Exception e)
			{
				printError("Could not produce transforms file: " + getTransformsPath(locale));
			}
		}
	}
	
	private void processMain(ULocale locale) throws Exception
	{
		CLDRFile xfile = SimpleFactory.makeFile(locale.getName());
		
		final String baseName = "com/ibm/icu/impl/data/icudt41b";
		ClassLoader loader = ICUData.class.getClassLoader();
		
        if (loader == null) { // boot class loader
            loader = ClassLoader.getSystemClassLoader();
        }
		
        ICUResourceBundle.resetBundleCache();
		ICUResourceBundle bund = (ICUResourceBundle)ICUResourceBundle.getBundleInstance(baseName, locale.getName(), loader, true);
		String curXPath = "//";
		curXPath += LDMLConstants.LDML;
		xfile.addComment(curXPath, COMMENT, Comments.PREBLOCK);
		
		addLocaleDisplayNames(xfile, curXPath, bund);
		addCharacters(xfile, curXPath, bund);
		addDelimiters(xfile, curXPath, bund);
		addDates(xfile, curXPath, bund);
		addNumbers(xfile, curXPath, bund);
		addUnits(xfile, curXPath, bund);
		addLayout(xfile, curXPath, bund);
		
		PrintWriter out = createPrinter(getMainPath(locale));
		xfile.write(out);
	}
	
	private void processCollation(ULocale locale) throws Exception
	{
		//TODO create a "collation" LDML Locale data file
		//PrintWriter out = createPrinter(getCollationPath(locale));
		//printError("processCollation is not yet implemented.");
		printError("Collation is not currently implemented.");
		
	}
	
	private void processTransforms(ULocale locale) throws Exception
	{
		//TODO create a "transforms" LDML Locale data file
		//PrintWriter out = createPrinter(getTransformsPath(locale));
		//printError("processTransforms is not yet implemented.");
		printError("Transliteration is not currently implemented.");
	}
	
	
	//******************** Methods to write different types of tags ****************************
	
	
	//***************************Methods for the localeDisplayNames tag and tags inside it **********
	private void addLocaleDisplayNames(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.LDN;
		
		addLocaleDisplayPattern(xfile, curXPath, bund);
		addLanguages(xfile, curXPath, bund);
		addScripts(xfile, curXPath, bund);
		addTerritories(xfile, curXPath, bund);
		addVariants(xfile, curXPath, bund);
		addTypes(xfile, curXPath, bund);
		addMeasurementSystemNames(xfile, curXPath, bund);
		addCodePatterns(xfile, curXPath, bund);
	}
	
	private void addLocaleDisplayPattern(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String innerTagPreName = LDMLConstants.LOCALE;
		final String resourceName = LDMLConstants.LOCALEDISPLAYPATTERN;
		curXPath += SEP + LDMLConstants.LOCALEDISPLAYPATTERN;
		
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + translateICUtoLDMLName(resourceName), bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle varTable = (ICUResourceBundle)bund.get(resourceName);
				Enumeration keys = varTable.getKeysSafe();
				Object temp;
				String curKey;
				String curValue;
				int x = 0;
				while(keys.hasMoreElements())
				{
					temp = keys.nextElement();
					if(temp instanceof String)
					{
						curKey = (String) temp;
						if(varTable.isAlias(curKey))
						{
							addAlias(xfile, curXPath + SEP + translateICUtoLDMLName(resourceName), varTable.getAliasPath(curKey), varTable.getResPath());
						}
						else
						{
							curValue = varTable.getString(curKey);
							
							String myXPath = curXPath + SEP + innerTagPreName + firstToUpper(curKey);
							xfile.add(myXPath, curValue);
						}
					}
					x++;
				}
			}
		}
		catch(MissingResourceException e)
		{
			printInfo("Did not find " + resourceName + " in the ICU bundle.");
		}
	}
	
	/*
	 * Has to do an inner loop to read the strings in, cannot use generic printer
	 */
	private void addTypes(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String resourceName = "Types";
		final String outerTagName = translateICUtoLDMLName(resourceName);
		
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + outerTagName, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle table = (ICUResourceBundle)bund.get(resourceName);
				Enumeration keys = table.getKeysSafe();
				Object temp;
				String curKey;
				String curType;
				String curValue = "";
				
				curXPath += SEP + outerTagName;
				while(keys.hasMoreElements())
				{
					temp = keys.nextElement();
					if(temp instanceof String)
					{
						curKey = (String) temp;
						if(table.isAlias(curKey))
						{
							addAlias(xfile, curXPath + SEP + translateICUtoLDMLName(curKey), table.getAliasPath(curKey), table.getResPath());
						}
						else
						{
							ICUResourceBundle curTable = (ICUResourceBundle)table.get(curKey);
							Enumeration types = curTable.getKeysSafe();
							
							while(types.hasMoreElements())
							{
								temp = types.nextElement();
								if(temp instanceof String)
								{
									curType = (String)temp;
									if(curTable.isAlias(curType))
									{
										addAlias(xfile, curXPath + SEP + translateICUtoLDMLName(curType), curTable.getAliasPath(curType), curTable.getResPath());
									}
									else
									{
										ICUResourceBundle meep = (ICUResourceBundle)curTable.get(curType);
										curValue = meep.getString();
										
										String myXPath = curXPath + SEP 
											+ LDMLConstants.TYPE + addXType(curType) + addXKey(curKey);
										
										xfile.add(myXPath, curValue);
									}
								}
							}
						}
					}
				}
			}
		}
		catch(MissingResourceException e)
		{
			printInfo("Did not find " + resourceName + " in the ICU bundle.");
		}
	}
	
	private void addScripts(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String innerTagName = LDMLConstants.SCRIPT;
		final String resourceName = "Scripts";
		final String outerTagName = translateICUtoLDMLName(resourceName);
		addGenericTagSet(xfile, curXPath, bund, resourceName, outerTagName, innerTagName);
	}
	
	private void addVariants(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String innerTagName = LDMLConstants.VARIANT;
		final String resourceName = "Variants";
		final String outerTagName = translateICUtoLDMLName(resourceName);
		addGenericTagSet(xfile, curXPath, bund, resourceName, outerTagName, innerTagName);
	}
	
	private void addLanguages(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		
		final String innerTagName = LDMLConstants.LANGUAGE;
		final String resourceName = "Languages";
		final String outerTagName = translateICUtoLDMLName(resourceName);
		addGenericTagSet(xfile, curXPath, bund, resourceName, outerTagName, innerTagName);
	}
	
	private void addTerritories(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String innerTagName = LDMLConstants.TERRITORY;
		final String resourceName = "Countries";
		final String outerTagName = translateICUtoLDMLName(resourceName);
		addGenericTagSet(xfile, curXPath, bund, resourceName, outerTagName, innerTagName);
	}

	private void addMeasurementSystemNames(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String innerTagName = LDMLConstants.MSN;
		final String resourceName = LDMLConstants.MSNS;
		final String outerTagName = translateICUtoLDMLName(resourceName);
		addGenericTagSet(xfile, curXPath, bund, resourceName, outerTagName, innerTagName);
	}
	
	private void addCodePatterns(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String innerTagName = LDMLConstants.CODE_PATTERN;
		final String resourceName = LDMLConstants.CODE_PATTERNS;
		final String outerTagName = LDMLConstants.CODE_PATTERNS;
		addGenericTagSet(xfile, curXPath, bund, resourceName, outerTagName, innerTagName);
	}

	//*************************** Method for writing characters **********************
	
	private void addCharacters(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		
		final String outerTagName = LDMLConstants.CHARACTERS;
		final String auxType = LDMLConstants.AUXILIARY;
		final String exempCharResName = "ExemplarCharacters";
		final String innerTagName = translateICUtoLDMLName(exempCharResName);
		final String auxExempCharResName = "AuxExemplarCharacters";

		curXPath += SEP + outerTagName;
		
		try
		{
			if(bund.isAlias(exempCharResName))
			{
				addAlias(xfile, curXPath + SEP + innerTagName, bund.getAliasPath(exempCharResName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle b = (ICUResourceBundle)bund.get(exempCharResName);
				xfile.add(curXPath + SEP + innerTagName, b.getString());
			}
		}
		catch(MissingResourceException e){} //No problem, just doesn't have it
		try
		{
			if(bund.isAlias(auxExempCharResName))
			{
				addAlias(xfile, curXPath + SEP + innerTagName, bund.getAliasPath(auxExempCharResName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle b = (ICUResourceBundle)bund.get(auxExempCharResName);
				xfile.add(curXPath + SEP + innerTagName + addXType(auxType), b.getString());
			}
		}
		catch(MissingResourceException e){} //No problem, just doesn't have it

	}
	
	/*
	 * Cannot use generic printer method on write delimiters
	 */
	private void addDelimiters(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String resourceName = LDMLConstants.DELIMITERS;
		final String outerTagName = LDMLConstants.DELIMITERS;
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + outerTagName, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle table = (ICUResourceBundle)bund.get(resourceName);
				Enumeration keys = table.getKeysSafe();
				Object temp;
				String curKey;
				String curValue = "";
				curXPath += SEP + outerTagName;
				while(keys.hasMoreElements())
				{
					temp = keys.nextElement();
					
					if(temp instanceof String)
					{
						curKey = (String) temp;
						curValue = table.getString(curKey);
						String myXPath = curXPath + SEP + curKey;
						xfile.add(myXPath, curValue);
					}
				}
			}
		}
		catch(MissingResourceException e)
		{
			printInfo("Did not find " + resourceName + " in the ICU bundle.");
		}
	}
	
	//************************* Methods for Date *********************************
	
	private void addDates(CLDRFile xfile,String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.DATES;
		addCalendars(xfile, curXPath, bund);
		addTimeZones(xfile, curXPath, bund);
	}
	
	private void addCalendars(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		//<!ELEMENT calendars (alias | (default*, calendar*, special*)) >
		final String resourceName = LDMLConstants.CALENDAR;
		Object temp = null;
		String curKey = null;
		ICUResourceBundle curBund = null;
		Enumeration keys = null;
		
		curXPath += SEP + LDMLConstants.CALENDARS;
		
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.CALENDARS, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(resourceName);
				
				//list of all types of calendars
				keys = bund.getKeysSafe();
				
				//loop through all types of calendars
				while(keys.hasMoreElements())
				{
					temp = keys.nextElement();
					
					if(temp instanceof String)
					{
						//the name of this type of calendar
						curKey = (String)temp; 
						
						if(bund.isAlias(curKey))
						{
							addAlias(xfile, curXPath + SEP + LDMLConstants.CALENDAR + addXType(curKey), bund.getAliasPath(curKey), bund.getResPath());
						}
						else if(curKey.equals(LDMLConstants.DEFAULT))
						{
							addDefault(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
						}
						else
						{
							curBund = (ICUResourceBundle)bund.get(curKey);
							String myXPath = curXPath + SEP + LDMLConstants.CALENDAR + addXType(curKey);
							addCalendar(xfile, myXPath, curBund);
						}
					}
				}
			}
		}
		catch(MissingResourceException e)
		{
			printInfo("Did not find " + resourceName + " in the ICU bundle.");
		}
	}
	
	
	private static final int ID_MONTHS = 0;
	private static final int ID_DAYS = 1;
	private static final int ID_QUARTERS = 2;
	
	private void addCalendar(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		//<!ELEMENT calendar (alias | (months?, monthNames?, monthAbbr?, days?, 
		//dayNames?, dayAbbr?, quarters?, week?, am*, pm*, eras?, dateFormats?, 
		//timeFormats?, dateTimeFormats?, fields*, special*))>

		addMDorQs(xfile, curXPath, bund, ID_MONTHS);
		addMDorQs(xfile, curXPath, bund, ID_DAYS);
		addMDorQs(xfile, curXPath, bund, ID_QUARTERS);
		addAMPM(xfile, curXPath, bund);
		addEras(xfile, curXPath, bund);
		addDateFormats(xfile, curXPath, bund);
		addTimeFormats(xfile, curXPath, bund);
		addDateTimeFormats(xfile, curXPath, bund);
		addFields(xfile, curXPath, bund);
		addSpecial(xfile, curXPath, bund);
	}
		
	//for adding months dates and quarters
	private void addMDorQs(CLDRFile xfile, String curXPath, ICUResourceBundle bund, int id)
	{
		String resourceName = "";
		String tagName = "";
		switch(id)
		{
			case ID_MONTHS:
				resourceName = "monthNames";
				tagName = LDMLConstants.MONTHS;
				break;
			case ID_DAYS:
				resourceName = "dayNames";
				tagName = LDMLConstants.DAYS;
				break;
			case ID_QUARTERS:
				resourceName = LDMLConstants.QUARTERS;
				tagName = LDMLConstants.QUARTERS;
				break;
			default:
				printError("Unknown ID code: " + id);
				System.exit(-1);
				break;
		}
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + tagName, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(resourceName);
				curXPath += SEP + tagName;
				
				Enumeration keys = bund.getKeysSafe();
				String curKey = null;
				while(keys.hasMoreElements())
				{
					curKey = (String)keys.nextElement();
					if(curKey.equals(LDMLConstants.FORMAT) || curKey.equals(LDMLConstants.STAND_ALONE))
					{
						addMDorQContext(xfile, curXPath, (ICUResourceBundle)bund.get(curKey), id);	
					}
					else if(curKey.equals(LDMLConstants.DEFAULT))
					{
						addDefault(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));	
					}
					else
					{
						printError("Did not know how to handle " + resourceName + " resource: " + curKey);
					}
					
					//addSpecial(xfile, curXPath, bund);	
				}
			}
		}
		catch(MissingResourceException e){}	//doesn't have data for this one
	}
	
	private void addMDorQContext(CLDRFile xfile, String curXPath, ICUResourceBundle bund, int id)
	{
		String tagName = "";
		String subTagName = "";
		switch(id)
		{
			case ID_MONTHS:
				tagName = LDMLConstants.MONTH_CONTEXT;
				subTagName = LDMLConstants.MONTH_WIDTH;
				break;
			case ID_DAYS:
				tagName = LDMLConstants.DAY_CONTEXT;
				subTagName = LDMLConstants.DAY_WIDTH;
				break;
			case ID_QUARTERS:
				tagName = LDMLConstants.QUARTER_CONTEXT;
				subTagName = LDMLConstants.QUARTER_WIDTH;
				break;
			default:
				printError("Unknown ID code: " + id);
				System.exit(-1);
				break;
		}
		String type = bund.getKey();
		curXPath += SEP + tagName + addXType(type);
		String curKey = null;
		Enumeration keys = bund.getKeysSafe();
		while(keys.hasMoreElements())
		{
			curKey = (String)keys.nextElement();
			if(bund.isAlias(curKey))
			{
				addAlias(xfile, curXPath + SEP + subTagName + addXType(curKey), bund.getAliasPath(curKey), bund.getResPath());
			}
			else if(curKey.equals(LDMLConstants.DEFAULT))
			{
				addDefault(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
			}
			else
			{
				addMDorQWidth(xfile, curXPath, (ICUResourceBundle)bund.get(curKey), id);
			}
		}
	}
	
	private void addMDorQWidth(CLDRFile xfile, String curXPath, ICUResourceBundle bund, int id)
	{
		String tagName = "";
		String subTagName = "";
		switch(id)
		{
			case ID_MONTHS:
				tagName = LDMLConstants.MONTH_WIDTH;
				subTagName = LDMLConstants.MONTH;
				break;
			case ID_DAYS:
				tagName = LDMLConstants.DAY_WIDTH;
				subTagName = LDMLConstants.DAY;
				break;
			case ID_QUARTERS:
				tagName = LDMLConstants.QUARTER_WIDTH;
				subTagName = LDMLConstants.QUARTER;
				break;
			default:
				printError("Unknown ID code: " + id);
				System.exit(-1);
				break;
		}
		
		curXPath += SEP + tagName + addXType(bund.getKey());
		
		String curKey;
		Enumeration keys = bund.getKeysSafe();
		while(keys.hasMoreElements())
		{
			curKey = (String)keys.nextElement();
			if(bund.isAlias(curKey))
			{
				addAlias(xfile, curXPath + SEP + subTagName + addXType(plusOne(curKey)), bund.getAliasPath(curKey), bund.getResPath());
			}
			else
			{
				addMDorQ(xfile, curXPath, (ICUResourceBundle)bund.get(curKey), id);
			}
		}
	}
	
	private void addMDorQ(CLDRFile xfile, String curXPath, ICUResourceBundle bund, int id)
	{
		String tagName = "";
		String type = "";
		switch(id)
		{
			case ID_MONTHS:
				tagName = LDMLConstants.MONTH;
				type = plusOne(bund.getKey());
				break;
			case ID_DAYS:
				tagName = LDMLConstants.DAY;
				type = getDayOfWeek(bund.getKey());
				break;
			case ID_QUARTERS:
				tagName = LDMLConstants.QUARTER;
				type = plusOne(bund.getKey());
				break;
			default:
				printError("Unknown ID code: " + id);
				System.exit(-1);
				break;
		}
		curXPath += SEP + tagName + addXType(type);
		xfile.add(curXPath, bund.getString());
	}

	private void addAMPM(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String ampmResourceName = "AmPmMarkers";
		String amXPath = curXPath + SEP + LDMLConstants.AM;
		String pmXPath = curXPath + SEP + LDMLConstants.PM;
		try
		{
			if(bund.isAlias(ampmResourceName))
			{
				addAlias(xfile, curXPath + SEP + ampmResourceName, bund.getAliasPath(ampmResourceName), bund.getResPath());
				//TODO AM/PM is a single resource in ICU, alias's will not occur? Most likely duplicates the data from the pointed to location
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(ampmResourceName);
				xfile.add(amXPath, bund.getString(0));
				xfile.add(pmXPath, bund.getString(1));	
			}
		}
		catch(MissingResourceException e){}
	}
	
	private void addEras(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String erasResourceName = LDMLConstants.ERAS;
		try
		{
			if(bund.isAlias(erasResourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.ERAS, bund.getAliasPath(erasResourceName), bund.getResPath());
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(erasResourceName);
				curXPath += SEP + LDMLConstants.ERAS;
				
				addErasAbbr(xfile, curXPath, bund);
				addErasNames(xfile, curXPath, bund);
				addErasNarrow(xfile, curXPath, bund);	
			}
		}
		catch(MissingResourceException e){}
	}
	
	private void addErasAbbr(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		if(bund.isAlias(LDMLConstants.ABBREVIATED))
		{
			addAlias(xfile, curXPath + SEP + LDMLConstants.ERAABBR, bund.getAliasPath(LDMLConstants.ABBREVIATED), bund.getResPath());
		}
		else
		{	
			bund = (ICUResourceBundle)bund.get(LDMLConstants.ABBREVIATED);
			curXPath += SEP + LDMLConstants.ERAABBR;
			Enumeration keys = bund.getKeys();
			String curKey;
			while(keys.hasMoreElements())
			{
				curKey = (String)keys.nextElement();
				if(bund.isAlias(curKey))
				{
					//addAlias(xfile, curXPath + SEP + curKey, bund.getAliasPath(curKey), bund.getResPath());
					printError("Found alias in Era Abbr.");
				}
				else
				{
					addEra(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
				}
			}
		}
	}
	
	private void addErasNames(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		if(bund.isAlias(LDMLConstants.WIDE))
		{
			addAlias(xfile, curXPath + SEP + LDMLConstants.ERANAMES, bund.getAliasPath(LDMLConstants.WIDE), bund.getResPath());
		}
		else
		{	
			bund = (ICUResourceBundle)bund.get(LDMLConstants.WIDE);
			curXPath += SEP + LDMLConstants.ERANAMES;
			Enumeration keys = bund.getKeys();
			String curKey;
			while(keys.hasMoreElements())
			{
				curKey = (String)keys.nextElement();
				if(bund.isAlias(curKey))
				{
					//addAlias(xfile, curXPath + SEP + curKey, bund.getAliasPath(curKey), bund.getResPath());
					printError("Found alias in Era Names.");
				}
				else
				{
					addEra(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
				}
			}
		}
	}
	
	private void addErasNarrow(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		if(bund.isAlias(LDMLConstants.NARROW))
		{
			addAlias(xfile, curXPath + SEP + LDMLConstants.ERANARROW, bund.getAliasPath(LDMLConstants.NARROW), bund.getResPath());
		}
		else
		{	
			bund = (ICUResourceBundle)bund.get(LDMLConstants.NARROW);
			curXPath += SEP + LDMLConstants.ERANARROW;
			Enumeration keys = bund.getKeys();
			String curKey;
			while(keys.hasMoreElements())
			{
				curKey = (String)keys.nextElement();
				if(bund.isAlias(curKey))
				{
					//addAlias(xfile, curXPath + SEP + curKey, bund.getAliasPath(curKey), bund.getResPath());
					printError("Found alias in narrow eras.");
				}
				else	
				{
					addEra(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
				}
			}
		}
	}
	
	private void addEra(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.ERA + addXType(bund.getKey());
		xfile.add(curXPath, bund.getString());
	}
	
	private void addDateFormats(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String resourceName = "DateTimePatterns";
		String fullType, longType, mediumType, shortType;
	
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.DATE_FORMATS, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				curXPath += SEP + LDMLConstants.DATE_FORMATS;
				bund = (ICUResourceBundle)bund.get(resourceName);
				
				fullType = bund.getString(4);
				longType = bund.getString(5);
				mediumType = bund.getString(6);
				shortType = bund.getString(7);
				
				String fullPath = curXPath + SEP + LDMLConstants.DFL + addXType("full") + SEP + LDMLConstants.DATE_FORMAT + SEP + LDMLConstants.PATTERN;
				String longPath = curXPath + SEP + LDMLConstants.DFL + addXType("long") + SEP + LDMLConstants.DATE_FORMAT + SEP + LDMLConstants.PATTERN;
				String mediumPath = curXPath + SEP + LDMLConstants.DFL + addXType("medium") + SEP + LDMLConstants.DATE_FORMAT + SEP + LDMLConstants.PATTERN;
				String shortPath = curXPath + SEP + LDMLConstants.DFL + addXType("short") + SEP + LDMLConstants.DATE_FORMAT + SEP + LDMLConstants.PATTERN;
				
				xfile.add(fullPath, fullType);
				xfile.add(longPath, longType);
				xfile.add(mediumPath, mediumType);
				xfile.add(shortPath, shortType);
				//TODO Cannot find the 'default' resource in the ICUResourceBundle...doesn't exist?
				//TODO There are no alias's in Date Formats, the data is duplicated into the string array when building ICU data
			}
		}
		catch(MissingResourceException e){}
	}
	
	private void addTimeFormats(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String resourceName = "DateTimePatterns";
		String fullType, longType, mediumType, shortType;
		try
		{
			bund = (ICUResourceBundle)bund.get(resourceName);
			
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.TIME_FORMATS, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				curXPath += SEP + LDMLConstants.TIME_FORMATS;
				fullType = bund.getString(0);
				longType = bund.getString(1);
				mediumType = bund.getString(2);
				shortType = bund.getString(3);
				
				String fullPath = curXPath + SEP + LDMLConstants.TFL + addXType("full") + SEP + LDMLConstants.TIME_FORMAT + SEP + LDMLConstants.PATTERN;
				String longPath = curXPath + SEP + LDMLConstants.TFL + addXType("long") + SEP + LDMLConstants.TIME_FORMAT + SEP + LDMLConstants.PATTERN;
				String mediumPath = curXPath + SEP + LDMLConstants.TFL + addXType("medium") + SEP + LDMLConstants.TIME_FORMAT + SEP + LDMLConstants.PATTERN;
				String shortPath = curXPath + SEP + LDMLConstants.TFL + addXType("short") + SEP + LDMLConstants.TIME_FORMAT + SEP + LDMLConstants.PATTERN;
				
				xfile.add(fullPath, fullType);
				xfile.add(longPath, longType);
				xfile.add(mediumPath, mediumType);
				xfile.add(shortPath, shortType);
				//TODO Cannot find the 'default' resource in the ICUResourceBundle...doesn't exist?
				//TODO There are no alias's in Time Formats, the data is duplicated into the string array when building ICU data
			}
		}
		catch(MissingResourceException e){}
	}
	
	private void addDateTimeFormats(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		String resourceName = "DateTimePatterns";
		curXPath += SEP + LDMLConstants.DATE_TIME_FORMATS;
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle bund1 = (ICUResourceBundle)bund.get(resourceName);
				String pattern = bund1.getString(8);
				String fullPath = curXPath + SEP + LDMLConstants.DTFL + SEP + LDMLConstants.DATE_TIME_FORMAT + SEP + LDMLConstants.PATTERN;
				xfile.add(fullPath, pattern);
				//TODO Cannot find the 'default' resource in the ICUResourceBundle...doesn't exist?
				//TODO There are no alias's in Date Time Formats, the data is duplicated into the string array when building ICU data
			}
		}
		catch(MissingResourceException e){}
		
		//deal with Available formats
		try
		{
			resourceName = LDMLConstants.AVAIL_FMTS;
		
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.AVAIL_FMTS, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle bund1 = (ICUResourceBundle)bund.get(resourceName);
				String myXPath = curXPath + SEP + LDMLConstants.AVAIL_FMTS;
				Enumeration keys = bund1.getKeysSafe();
				while(keys.hasMoreElements())
				{
					String curKey = (String)keys.nextElement();
					if(bund1.isAlias(curKey))
					{
						addAlias(xfile, curXPath + SEP + LDMLConstants.DATE_FMT_ITEM + addXID(curKey), bund1.getAliasPath(curKey), bund.getResPath());
					}
					else
					{
						addDateFormatItem(xfile, myXPath, (ICUResourceBundle)bund1.get(curKey));
					}
				}
			}
		}
		catch(MissingResourceException e){}
		
		//deal with intervalFormats
		try
		{
			resourceName = LDMLConstants.INTVL_FMTS;
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.INTVL_FMTS, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle bund1 = (ICUResourceBundle)bund.get(resourceName);
				String myXPath = curXPath + SEP + LDMLConstants.INTVL_FMTS;
				Enumeration keys = bund1.getKeysSafe();
				while(keys.hasMoreElements())
				{
					String curKey = (String)keys.nextElement();
					if(bund1.isAlias(curKey))
					{
						addAlias(xfile, curXPath + SEP + LDMLConstants.INTVL_FMT_ITEM + addXID(curKey), bund1.getAliasPath(curKey), bund1.getResPath());
					}
					else
					{
						addIntervalFormatItem(xfile, myXPath, (ICUResourceBundle)bund1.get(curKey));
					}
				}
			}
		}
		catch(MissingResourceException e){}
		
		//deal with appendItems
		try
		{
			resourceName = LDMLConstants.APPEND_ITEMS;
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.APPEND_ITEMS, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle bund1 = (ICUResourceBundle)bund.get(resourceName);
				String myXPath = curXPath + SEP + LDMLConstants.APPEND_ITEMS;
				Enumeration keys = bund1.getKeysSafe();
				while(keys.hasMoreElements())
				{
					String curKey = (String)keys.nextElement();
					if(bund1.isAlias(curKey))
					{
						addAlias(xfile, curXPath + SEP + LDMLConstants.APPEND_ITEM, bund1.getAliasPath(curKey), bund1.getResPath());
					}
					else
					{
						String myXPath1 = myXPath + SEP + LDMLConstants.APPEND_ITEM + addXRequest(curKey);
						xfile.add(myXPath1, bund1.getString(curKey));
					}
				}
			}
		}
		catch(MissingResourceException e){}
	}		
	
	
	private void addDateFormatItem(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.DATE_FMT_ITEM + addXID(bund.getKey());
		xfile.add(curXPath, bund.getString());
	}
	
	private void addIntervalFormatItem(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		String key = bund.getKey();
		if(key.equals(LDMLConstants.FALLBACK))
		{
			curXPath += SEP + LDMLConstants.INTVL_FMT_FALL;  
			xfile.add(curXPath, bund.getString(key));
		}
		else
		{
			curXPath += SEP + LDMLConstants.INTVL_FMT_ITEM + addXID(key);
			Enumeration keys = bund.getKeysSafe();
			while(keys.hasMoreElements())
			{
				String curKey = (String)keys.nextElement();
				if(bund.isAlias(curKey))
				{
					addAlias(xfile, curXPath + SEP + LDMLConstants.GREATEST_DIFF + addXID(curKey), bund.getAliasPath(curKey), bund.getResPath());
				}
				else
				{
					addGreatestDiff(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
				}
			}
		}
	}
	
	private void addGreatestDiff(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.GREATEST_DIFF + addXID(bund.getKey());
		xfile.add(curXPath, bund.getString());
	}
	
	private void addFields(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		//<!ELEMENT fields ( alias | (field*, special*)) >
		//<!ELEMENT field ( alias | (displayName?, relative*, special*)) >
		String resourceName = LDMLConstants.FIELDS;
		curXPath += SEP + LDMLConstants.FIELDS;
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(resourceName);

				String curKey;
				Enumeration keys = bund.getKeysSafe();
				while(keys.hasMoreElements())
				{
					curKey = (String)keys.nextElement();
					if(bund.isAlias(curKey))
					{
						addAlias(xfile, curXPath + SEP + LDMLConstants.FIELD + addXType(curKey), bund.getAliasPath(curKey), bund.getResPath());
					}
					else
					{
						addField(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
					}
				}
			}
		}
		catch(MissingResourceException e){}
		
	}
	
	private void addField(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String displayNameResourceName = "dn";
		final String relativeResourceName = LDMLConstants.RELATIVE;
		
		try
		{
			if(bund.isAlias(displayNameResourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.FIELD + addXType(bund.getKey()), bund.getAliasPath(displayNameResourceName), bund.getResPath());
			}
			else
			{
				curXPath += SEP + LDMLConstants.FIELD + addXType(bund.getKey());
				addDisplayName(xfile, curXPath, (ICUResourceBundle)bund.get(displayNameResourceName));
			}
		}
		catch(MissingResourceException e){}
		
		try
		{
			if(bund.isAlias(relativeResourceName))
			{
				addAlias(xfile, curXPath + SEP + relativeResourceName, bund.getAliasPath(relativeResourceName), bund.getResPath());
			}
			else
			{
				addRelatives(xfile, curXPath, (ICUResourceBundle)bund.get(relativeResourceName));
			}
		}
		catch(MissingResourceException e){}
	}
	
	private void addDisplayName(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.DISPLAY_NAME;
		xfile.add(curXPath, bund.getString()); 
	}
	
	private void addRelatives(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		String curKey;
		Enumeration keys = bund.getKeysSafe();
		while(keys.hasMoreElements())
		{
			curKey = (String)keys.nextElement();
			if(bund.isAlias(curKey))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.RELATIVE + addXType(curKey), bund.getAliasPath(curKey), bund.getResPath());
			}
			else
			{
				addRelative(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
			}
		}
	}
	
	private void addRelative(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.RELATIVE + addXType(bund.getKey());
		xfile.add(curXPath, bund.getString());
	}
	
	private void addSpecial(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		//TODO Special - This is part of the LDML spec, but does not seem to be relevant for any ICU data
	}
		
	private void addTimeZones(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String timeZoneResourceName = "zoneStrings";
		try
		{
			if(bund.isAlias(timeZoneResourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.TZN, bund.getAliasPath(timeZoneResourceName), bund.getResPath());
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(timeZoneResourceName);
				curXPath += SEP + LDMLConstants.TZN;
				//get all keys (each one is the name of a time zone or one of a few special cases
				Enumeration keys = bund.getKeysSafe();
				while(keys.hasMoreElements())
				{
					String curKey = (String)keys.nextElement();
					
					if(bund.isAlias(curKey))
					{
						//TODO this will not have the proper tag around it
						//addAlias(xfile, curXPath + SEP + curKey, bund.getAliasPath(curKey), bund.getResPath());
						printError("Found a Time Zone Name alias.");
					}
					else if(isMeta(curKey))
					{
						addZone(xfile, curXPath, (ICUResourceBundle)bund.get(curKey), META_ID);
					}
					else if(isZoneSpecial(curKey))
					{
						addZoneSpecial(xfile, curXPath, (ICUResourceBundle)bund.get(curKey));
					}
					else
					{
						//it's just a regular time zone
						addZone(xfile, curXPath, (ICUResourceBundle)bund.get(curKey), ZONE_ID);
					}
				}
			}
		}
		catch(MissingResourceException e)
		{
			printInfo("Did not find " + timeZoneResourceName + " in the ICU bundle.");
		}
	}
	
	private static final int ZONE_ID = 0;
	private static final int META_ID = 1;
	
	private void addZone(CLDRFile xfile, String curXPath, ICUResourceBundle bund, int id)
	{
		String exemplarCityResourceName = "ec";
		
		String longGenericResourceName = "lg";
		String longDaylightResourceName = "ld";		
		String longStandardResourceName = "ls";
		
		String shortDaylightResourceName = "sd";
		String shortGenericResourceName = "sg";
		String shortStandardResourceName = "ss";
		
		String commonlyUsedResourceName = "cu";
		
		switch(id)
		{
			case ZONE_ID:
				curXPath += SEP + LDMLConstants.ZONE + addXType(bund.getKey().replace(':', '/'));
				break;
			case META_ID:
				curXPath += SEP + LDMLConstants.METAZONE + addXType(bund.getKey().substring(5).replace(':', '/'));
				break;
			default:
				printError("Invalid ID: " + id);
				break;
		}		
		Enumeration keys = bund.getKeysSafe();
		
		while(keys.hasMoreElements())
		{
			String curKey = (String)keys.nextElement();
			
			if(bund.isAlias(curKey))
			{
				//addAlias(xfile, curXPath + SEP + curKey, bund.getAliasPath(curKey), bund.getResPath());
				//TODO will not produce proper outter tags
				printError("Found alias in Time Zone.");
			}			
			else if(curKey.equals(exemplarCityResourceName))
			{
				String val = bund.getString(curKey);
				String myXPath = curXPath + SEP + LDMLConstants.EXEMPLAR_CITY;
				xfile.add(myXPath, val);
			}
			else if(curKey.equals(longGenericResourceName))
			{
				String myXPath = curXPath + SEP + LDMLConstants.LONG + SEP + LDMLConstants.GENERIC;
				xfile.add(myXPath, bund.getString(curKey));
			}
			else if(curKey.equals(longStandardResourceName))
			{
				String myXPath = curXPath + SEP + LDMLConstants.LONG + SEP + LDMLConstants.STANDARD;
				xfile.add(myXPath, bund.getString(curKey));
			}
			else if(curKey.equals(longDaylightResourceName))
			{
				String myXPath = curXPath + SEP + LDMLConstants.LONG + SEP + LDMLConstants.DAYLIGHT;
				xfile.add(myXPath, bund.getString(curKey));
			}
			else if(curKey.equals(shortGenericResourceName))
			{
				String myXPath = curXPath + SEP + LDMLConstants.SHORT + SEP + LDMLConstants.GENERIC;
				xfile.add(myXPath, bund.getString(curKey));
			}
			else if(curKey.equals(shortStandardResourceName))
			{
				String myXPath = curXPath + SEP + LDMLConstants.SHORT + SEP + LDMLConstants.STANDARD;
				xfile.add(myXPath, bund.getString(curKey));
			}
			else if(curKey.equals(shortDaylightResourceName))
			{
				String myXPath = curXPath + SEP + LDMLConstants.SHORT + SEP + LDMLConstants.DAYLIGHT;
				xfile.add(myXPath, bund.getString(curKey));
			}
			else if(curKey.equals(commonlyUsedResourceName))
			{
				String val = (bund.get(curKey).getInt() == 1)? "true" : "false";
				String myXPath = curXPath + SEP + LDMLConstants.COMMONLY_USED;
				xfile.add(myXPath, val);
			}
			else
			{
				printError("Unrecognized element in time zone: " + curKey);
			}
		}
	}
	
	private void addZoneSpecial(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String hourFormatResourceName = LDMLConstants.HOUR_FORMAT;
		final String hoursFormatResourceName = LDMLConstants.HOURS_FORMAT;
		final String gmtFormatResourceName = LDMLConstants.GMT_FORMAT;
		final String regionFormatResourceName = LDMLConstants.REGION_FORMAT;
		final String fallbackFormatResourceName = LDMLConstants.FALLBACK_FORMAT;
		
		String key = bund.getKey();
			
		if(key.equals(LDMLConstants.PREFERENCE_ORDERING))
		{
			/*
			preferenceOrdering{
	            "",
	        }
	        <preferenceOrdering choice=""/>
	        *
	        */
			String[] val = bund.getStringArray();
			String list = "";
			for(int x = 0; x < val.length; x++)
			{
				list += val[x] + " ";
			}
			list = list.substring(0, list.length()-1);
			curXPath += SEP + LDMLConstants.PREFERENCE_ORDERING + addXChoice(list);
			xfile.add(curXPath, "");
		}
		else if(key.equals(LDMLConstants.SINGLE_COUNTRIES))
		{
			/*
			<singleCountries list="Europe/Kiev Pacific/Majuro Africa/Bamako America/Godthab America/Santiago America/Guayaquil Asia/Shanghai Asia/Tashkent Asia/Kuala_Lumpur Europe/Madrid Europe/Lisbon Europe/London Pacific/Auckland Pacific/Tahiti"/>
			singleCountries{
            "Europe/Kiev",
            "Pacific/Majuro",
            "Africa/Bamako",
            "America/Godthab",
            "America/Santiago",
            "America/Guayaquil",
            "Asia/Shanghai",
            "Asia/Tashkent",
            "Asia/Kuala_Lumpur",
            "Europe/Madrid",
            "Europe/Lisbon",
            "Europe/London",
            "Pacific/Auckland",
            "Pacific/Tahiti",
        }
			*/
			String[] val = bund.getStringArray();
			String list = "";
			for(int x = 0; x < val.length; x++)
			{
				list += val[x] + " ";
			}
			list = list.substring(0, list.length()-1);
			curXPath += SEP + LDMLConstants.SINGLE_COUNTRIES + addXList(list);
			xfile.add(curXPath, "");
		}
		else if(key.equals(hourFormatResourceName))
		{
			String val = bund.getString(key);
			curXPath += SEP + LDMLConstants.HOUR_FORMAT;
			xfile.add(curXPath, val);
		}
		else if(key.equals(hoursFormatResourceName))
		{
			String val = bund.getString(key);
			curXPath += SEP + LDMLConstants.HOURS_FORMAT;
			xfile.add(curXPath, val);
		}
		else if(key.equals(gmtFormatResourceName))
		{
			String val = bund.getString(key);
			curXPath += SEP + LDMLConstants.GMT_FORMAT;
			xfile.add(curXPath, val);
		}
		else if(key.equals(regionFormatResourceName))
		{
			String val = bund.getString(key);
			curXPath += SEP + LDMLConstants.REGION_FORMAT;
			xfile.add(curXPath, val);
		}
		else if(key.equals(fallbackFormatResourceName))
		{
			String val = bund.getString(key);
			curXPath += SEP + LDMLConstants.FALLBACK_FORMAT;
			xfile.add(curXPath, val);
		}
		else
		{
			printError("Did not recognize Time Zone special tag: " + key);
		}
	}
	
	private void addNumbers(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.NUMBERS;
		addSymbols(xfile, curXPath, bund);
		addNumberFormats(xfile, curXPath, bund);
		addCurrencies(xfile, curXPath, bund);
	}
	
	private void addSymbols(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String resourceName = "NumberElements";
			
		final int decimalIndex = 0;
		final int groupIndex = 1;
		final int listIndex = 2;
		final int percentSignIndex = 3;
		final int nativeZeroDigitIndex = 4;
		final int patternDigitIndex = 5;
		final int minusSignIndex = 6;
		final int exponentialIndex = 7;
		final int perMileIndex = 8;
		final int infinityIndex = 9;
		final int nanIndex = 10;
		final int plusSignIndex = 11;
		final int lengthIndex = 12;
		
		
		String[] vals;
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.SYMBOLS, bund.getAliasPath(resourceName), bund.getResPath());
			}			
			else
			{
				bund = (ICUResourceBundle)bund.get(resourceName);
				curXPath += SEP + LDMLConstants.SYMBOLS; 
				vals = bund.getStringArray();
				if(vals.length != lengthIndex)
				{
					printError("Length of Symbols array was not correct. Length was: " + vals.length + ", should have been: " + lengthIndex);
				}
				
				xfile.add(curXPath + SEP + LDMLConstants.DECIMAL, vals[decimalIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.GROUP, vals[groupIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.LIST, vals[listIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.PERCENT_SIGN, vals[percentSignIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.NATIVE_ZERO_SIGN, vals[nativeZeroDigitIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.PATTERN_DIGIT, vals[patternDigitIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.MINUS_SIGN, vals[minusSignIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.EXPONENTIAL, vals[exponentialIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.PER_MILLE, vals[perMileIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.INFINITY, vals[infinityIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.NAN, vals[nanIndex]);
				xfile.add(curXPath + SEP + LDMLConstants.PLUS_SIGN, vals[plusSignIndex]);
			}
		}
		catch(MissingResourceException e){}
	}
	
	private void addNumberFormats(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String patternResourceName = "NumberPatterns";
		final String currencyUnitPatternResourceName = "CurrencyUnitPatterns";
		
		final int decimalIndex = 0;
		final int currencyIndex = 1;
		final int percentIndex = 2;
		final int scientificIndex = 3;
		final int lengthIndex = 4;
		
		try
		{
			if(bund.isAlias(patternResourceName))
			{
				addAlias(xfile, curXPath + SEP + patternResourceName, bund.getAliasPath(patternResourceName), bund.getResPath());
			}			
			else
			{
				ICUResourceBundle patternRes = (ICUResourceBundle)bund.get(patternResourceName);
				ICUResourceBundle curUnitPatternRes = null;
				try
				{
					if(bund.isAlias(currencyUnitPatternResourceName))
					{
						printWarning(currencyUnitPatternResourceName + " was an Alias, unsure how to handle.");
					}
					else
					{
						curUnitPatternRes = (ICUResourceBundle)bund.get(currencyUnitPatternResourceName);
					}
				}
				catch(MissingResourceException e)
				{
					printInfo("Did not find resource " + currencyUnitPatternResourceName + " in the ICU Bundle.");
				}
				String[] patterns = patternRes.getStringArray();
				
				if(patterns.length != lengthIndex)
				{
					printError(patternResourceName + " did not contain enough patterns. Expected: " + lengthIndex + ". Got: " + patterns.length);
				}
				else
				{
					addDecimalFormats(xfile, curXPath, patterns[decimalIndex]);
					addScientificFormats(xfile, curXPath, patterns[scientificIndex]);
					addPercentFormats(xfile, curXPath, patterns[percentIndex]);
					addCurrencyFormats(xfile, curXPath, patterns[currencyIndex], curUnitPatternRes);	
				}
			}
		}
		catch(Exception e){}
	}
	
	private void addDecimalFormats(CLDRFile xfile, String curXPath, String val)
	{	
		curXPath += SEP + LDMLConstants.DECIMAL_FORMATS;
		curXPath += SEP + LDMLConstants.DECFL;
		curXPath += SEP + LDMLConstants.DECIMAL_FORMAT;
		curXPath += SEP + LDMLConstants.PATTERN;
		xfile.add(curXPath, val);
	}
	
	private void addScientificFormats(CLDRFile xfile, String curXPath, String val)
	{		
		curXPath += SEP + LDMLConstants.SCIENTIFIC_FORMATS;
		curXPath += SEP + LDMLConstants.SCIFL;
		curXPath += SEP + LDMLConstants.SCIENTIFIC_FORMAT;
		curXPath += SEP + LDMLConstants.PATTERN;
		xfile.add(curXPath, val);
	}
	
	private void addPercentFormats(CLDRFile xfile, String curXPath, String val)
	{
		curXPath += SEP + LDMLConstants.PERCENT_FORMATS;
		curXPath += SEP + LDMLConstants.PERFL;
		curXPath += SEP + LDMLConstants.PERCENT_FORMAT;
		curXPath += SEP + LDMLConstants.PATTERN;
		xfile.add(curXPath, val);
	}
	
	private void addCurrencyFormats(CLDRFile xfile, String curXPath, String val, ICUResourceBundle bund)
	{		
		Enumeration keys;
		
		curXPath += SEP + LDMLConstants.CURRENCY_FORMATS;
		
		String myXPath = curXPath + SEP + LDMLConstants.CURFL;
		myXPath += SEP + LDMLConstants.CURRENCY_FORMAT;
		myXPath += SEP + LDMLConstants.PATTERN;
		xfile.add(myXPath, val);
		
		if(bund != null)
		{
			keys = bund.getKeysSafe();
			while(keys.hasMoreElements())
			{
				String curKey = (String)keys.nextElement();
				if(bund.isAlias(curKey))
				{
					addAlias(xfile, curXPath + SEP + LDMLConstants.UNIT_PATTERN + addXCount(curKey), bund.getAliasPath(curKey), bund.getResPath());
				}
				else
				{
					String curVal = (String)bund.getString(curKey);
					myXPath = curXPath + SEP + LDMLConstants.UNIT_PATTERN + addXCount(curKey);
					xfile.add(myXPath, curVal);
				}
			}
		}
	}
	
	private void addCurrencies(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String currenciesResourceName = "Currencies";
		final String currenciesPluralResourceName = "CurrencyPlurals";
				
		curXPath += SEP + LDMLConstants.CURRENCIES;
		
		try
		{
			ICUResourceBundle pluralBund = null;
			try
			{
				if(bund.isAlias(currenciesPluralResourceName))
				{
					//addAlias(xfile, curXPath + SEP + currenciesPluralResourceName, bund.getAliasPath(currenciesPluralResourceName), bund.getResPath());
					//TODO ??? do nothing? ICU seperates our plurals and singles, LDML does not
				}
				else
				{
					pluralBund = (ICUResourceBundle)bund.get(currenciesPluralResourceName);
				}
			}
			catch(MissingResourceException e)
			{
				printInfo("No plural currency resource found.");
			}
			if(bund.isAlias(currenciesResourceName))
			{
				addAlias(xfile, curXPath, bund.getAliasPath(currenciesResourceName), bund.getResPath());
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(currenciesResourceName);
				
			
				Enumeration keys = bund.getKeysSafe();
							
				while(keys.hasMoreElements())
				{
					String curKey = (String)keys.nextElement();
					if(bund.isAlias(curKey))
					{
						addAlias(xfile, curXPath + SEP + curKey, bund.getAliasPath(curKey), bund.getResPath());
					}
					else
					{
						ICUResourceBundle curSingle = (ICUResourceBundle)bund.get(curKey);
						ICUResourceBundle curPlural = null;
						if(pluralBund != null)
						{
							try
							{
								curPlural = (ICUResourceBundle)pluralBund.get(curKey);
							}
							catch(Exception e){}
						}
						addCurrency(xfile, curXPath, curKey, curSingle, curPlural);	
					}
				}
			}
		}
		catch(MissingResourceException e){}
	}
	
	private void addCurrency(CLDRFile xfile, String curXPath, String key, ICUResourceBundle symbBund, ICUResourceBundle pluralBund)
	{
		String[] symbArray = null;
		
		try
		{
			symbArray = symbBund.getStringArray();	
		}
		catch(UResourceTypeMismatchException e)
		{
			ArrayList strings = new ArrayList();
			Enumeration keys = symbBund.getKeysSafe();
			while(keys.hasMoreElements())
			{
				String curKey = (String)keys.nextElement();
				try
				{
					String val = symbBund.getString(curKey);
					strings.add(val);
				}
				catch(Exception z){}
			}
			symbArray = new String[strings.size()];
			for(int x = 0; x < strings.size(); x++)
			{
				symbArray[x] = (String)strings.get(x);
			}
		}
		
		if(symbArray.length != 2)
		{
			printError("Currency array for " + key + " is of the wrong length: " + symbArray.length);
		}
		
		String[] keys = null;
		String[] values = null;
		
		try
		{
			if(pluralBund != null)
			{
				Enumeration ekeys = pluralBund.getKeysSafe();
				ArrayList keysArray = new ArrayList();
				ArrayList valuesArray = new ArrayList();
								
				while(ekeys.hasMoreElements())
				{
					String curKey = (String)ekeys.nextElement();
					if(pluralBund.isAlias(curKey))
					{
						addAlias(xfile, curXPath, pluralBund.getAliasPath(curKey), pluralBund.getResPath());
					}
					else
					{
						String curVal = pluralBund.getString(curKey);
						keysArray.add(curKey);
						valuesArray.add(curVal);
					}
				}
				Object[] temp = keysArray.toArray();
				keys = new String[temp.length];
				for(int x = 0; x < temp.length; x++)
				{
					keys[x] = (String)temp[x];
				}
				
				temp = valuesArray.toArray();
				values = new String[temp.length];
				for(int x = 0; x < temp.length; x++)
				{
					values[x] = (String)temp[x];
				}
			}
		}
		catch(Exception e){}
		
		String myXPath = curXPath + SEP + LDMLConstants.CURRENCY + addXType(key);
		String dnXPath = myXPath + SEP + LDMLConstants.DISPLAY_NAME;
		String symbXPath = myXPath + SEP + LDMLConstants.SYMBOL;

		xfile.add(dnXPath, symbArray[1]);
				
		if(keys != null)
		{
			for(int x = 0; x < keys.length; x++)
			{
				xfile.add(dnXPath + addXCount(keys[x]), values[x]);
			}
		}
		
		if(!symbArray[0].equals(key))
		{
			xfile.add(symbXPath, symbArray[0]);
		}
	}
	
	private void addUnits(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		final String unitResourceName = LDMLConstants.UNITS;
		
		curXPath += SEP + LDMLConstants.UNITS;
		
		try
		{
			if(bund.isAlias(unitResourceName))
			{
				addAlias(xfile, curXPath, bund.getAliasPath(unitResourceName), bund.getResPath());
			}
			else
			{
				bund = (ICUResourceBundle)bund.get(unitResourceName);
				Enumeration keys = bund.getKeysSafe();				
				while(keys.hasMoreElements())
				{
					String curKey = (String)keys.nextElement();
					
					if(bund.isAlias(curKey))
					{
						addAlias(xfile, curXPath + SEP + LDMLConstants.UNIT + addXType(curKey), bund.getAliasPath(curKey), bund.getResPath());
					}
					else
					{
						ICUResourceBundle t = (ICUResourceBundle)bund.get(curKey);
						addUnit(xfile, curXPath, t);	
					}
				}
			}
		}
		catch(Exception e){}
	}
	
	private void addUnit(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.UNIT + addXType(bund.getKey());
		
		Enumeration keys = bund.getKeysSafe();
		while(keys.hasMoreElements())
		{
			String curKey = (String)keys.nextElement();
						
			if(bund.isAlias(curKey))
			{
				addAlias(xfile, curXPath + SEP + LDMLConstants.UNIT_PATTERN + addXCount(curKey), bund.getAliasPath(curKey), bund.getResPath());
			}
			else
			{
				String curVal = bund.getString(curKey);
				String myXPath = curXPath + SEP + LDMLConstants.UNIT_PATTERN + addXCount(curKey);
				xfile.add(myXPath, curVal);	
			}
		}
	}	
	
	private void addLayout(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		//TODO cannot find data in resource bundle...
	}
	
	private void addDefault(CLDRFile xfile, String curXPath, ICUResourceBundle bund)
	{
		curXPath += SEP + LDMLConstants.DEFAULT + addXChoice(bund.getString());
		xfile.add(curXPath, "");
	}

	
	private void addAlias(CLDRFile xfile, String curXPath, String path, String curPath)
	{		
		//<alias source="locale" path="../../calendar[@type='islamic']/eras"/>
		//eras:alias{"/LOCALE/calendar/islamic/eras"}

		int start = path.indexOf(SEP) +1;
		if(start > 0)
		{
			int end = path.indexOf(SEP, start);
			
			String source = path.substring(start, end).toLowerCase();
			path = path.substring(end+1);
			
			char[] cArray = new char[1];
			cArray[0] = SEP;
			String pathSep = new String(cArray);
			
			StringTokenizer stk = new StringTokenizer(curPath, pathSep);
			String relativePath = "";
			
			while(stk.hasMoreTokens())
			{
				stk.nextToken();
				relativePath += ".." + SEP;
			}
			
			boolean isType = false;
			stk = new StringTokenizer(path, pathSep);
			
			while(stk.hasMoreTokens())
			{
				String temp = stk.nextToken();
				
				if(isType)
				{
					relativePath += addXType(translateICUtoLDMLName(temp)) + SEP;
					isType = false;
				}
				else if(usesType(temp))
				{
					relativePath += translateICUtoLDMLName(temp);
					isType = true;
				}
				else
				{
						relativePath += translateICUtoLDMLName(temp) + SEP;
				}
			}
			
			relativePath = cleanRelativePath(relativePath);
			
			 
			if(relativePath.charAt(relativePath.length()-1) == SEP)
			{
				relativePath = relativePath.substring(0,relativePath.length()-1);
			}
			relativePath = reducePath(relativePath, curXPath);
			relativePath = relativePath.replace('"','\'');
			
			curXPath += SEP + LDMLConstants.ALIAS + addXSource(source) + addXPath(relativePath);
		}
		else
		{
			curXPath += SEP + LDMLConstants.ALIAS + addXSource(path);
		}
		
		xfile.add(curXPath, "");
		
	}
	
	
	
	private String reducePath(String relative, String cur)
	{
		String temp = "";
		String[] r = relative.split("" + SEP);
		String[] c = cur.split("" + SEP);
		int dotCnt = 0;
		
		while(r[0].equals(".."))
		{
			//remove the first element
			String[] t = new String[r.length - 1];
			for(int x = 0; x < t.length; x++)
			{
				t[x] = r[x+1];
			}
			r = t;
			//count the dots
			dotCnt++;
		}
		
		while(arrayContains(c, r[0]))
		{
			//remove the first element
			String[] t = new String[r.length - 1];
			for(int x = 0; x < t.length; x++)
			{
				t[x] = r[x+1];
			}
			r = t;
			
			//remove a dot
			dotCnt--;
		}
		for(int x = 0; x < dotCnt; x++)
		{
			temp += ".." + SEP;
		}
		for(int x = 0; x < r.length; x++)
		{
			temp += r[x] + SEP;
		}
		temp = temp.substring(0,temp.length()-1);
		return temp;
	}
	
	private boolean arrayContains(String[] a, String s)
	{
		for(int x = 0; x < a.length; x++)
		{
			if(a[x].equals(s))
			{
				return true;
			}
		}
		return false;
	}
	//*********************** Generic tag writer ***************************
	
	/*
	 * This method is a generic way of looking up a resource and printing it.
	 * This method can only be used if the resourceName given corresponds to a resource Table,
	 * and that table only contains string elements.
	 */
	private void addGenericTagSet(CLDRFile xfile, String curXPath, ICUResourceBundle bund, String resourceName, String outerTagName, String innerTagName)
	{
		try
		{
			if(bund.isAlias(resourceName))
			{
				addAlias(xfile, curXPath + SEP + outerTagName, bund.getAliasPath(resourceName), bund.getResPath());
			}
			else
			{
				ICUResourceBundle table = (ICUResourceBundle)bund.get(resourceName);
				Enumeration keys = table.getKeysSafe();
				Object temp;
				String curKey;
				String curValue = "";
	
				curXPath += SEP + outerTagName + SEP + innerTagName;
				
				while(keys.hasMoreElements())
				{
					temp = keys.nextElement();
					
					if(temp instanceof String)
					{
						curKey = (String) temp;
						
						if(table.isAlias(curKey))
						{
							addAlias(xfile, curXPath, table.getAliasPath(curKey), table.getResPath());
						}
						else
						{
							curValue = table.getString(curKey);
							String myXPath = curXPath + addXType(curKey);
							xfile.add(myXPath, curValue);
						}
					}
				}
			}
		}
		catch(MissingResourceException e)
		{
			printInfo("Did not find " + resourceName + " in the ICU bundle.");
		}
	}
	
	
	//***************************** Random helper methods **********************

	private String getDayOfWeek(String num)
	{
		switch((new Integer(num)))
		{
			case 0:
				return "sun";
			case 1:
				return "mon";
			case 2:
				return "tue";
			case 3:
				return "wed";
			case 4:
				return "thu";
			case 5:
				return "fri";
			case 6:
				return "sat";
			default:
				printError("Day resource not properly formatted.");
				System.exit(-1);
		}
		return "";
	}
	
	private String plusOne(String num)
	{
		return new Integer((new Integer(num) + 1)).toString();
	}
	
	private String addXKey(String key)
	{
		return "[@" + LDMLConstants.KEY + "=\"" + key + "\"]";
	}
	
	private String addXType(String type)
	{
		return "[@" + LDMLConstants.TYPE + "=\"" + type + "\"]";
	}
	
	private String addXID(String id)
	{
		return "[@" + LDMLConstants.ID + "=\"" + id + "\"]";
	}	
	
	private String addXCount(String cnt)
	{
		return "[@" + LDMLConstants.COUNT + "=\"" + cnt + "\"]";
	}
	
	private String addXSource(String src)
	{
		return "[@" + LDMLConstants.SOURCE + "=\"" + src + "\"]";
	}
	
	private String addXPath(String path)
	{
		return "[@" + LDMLConstants.PATH + "=\"" + path + "\"]";
	}
	
	private String addXChoice(String c)
	{
		return "[@" + LDMLConstants.CHOICE + "=\"" + c + "\"]";
	}
	
	private String addXRequest(String req)
	{
		return "[@" + LDMLConstants.REQUEST + "=\"" + req + "\"]";
	}
	
	private String addXList(String list)
	{
		return "[@" + LDMLConstants.LIST + "=\"" + list + "\"]";
	}
	
	private String firstToUpper(String str)
	{
		return str.substring(0,1).toUpperCase() + str.substring(1, str.length()).toLowerCase();
	}

	private boolean isMeta(String key)
	{
		try
		{
			String meta = key.substring(0, 5);
			if(meta.equals("meta:"))
			{
				return true;
			}
			return false;
		}
		catch(IndexOutOfBoundsException e)
		{
			return false;
		}
	}
	
	private boolean isZoneSpecial(String key)
	{
		if(key.equals(LDMLConstants.FALLBACK_FORMAT)
				|| key.equals(LDMLConstants.GMT_FORMAT)
				|| key.equals(LDMLConstants.HOUR_FORMAT)
				|| key.equals(LDMLConstants.REGION_FORMAT)
				|| key.equals(LDMLConstants.HOURS_FORMAT)
				|| key.equals(LDMLConstants.PREFERENCE_ORDERING)
				|| key.equals(LDMLConstants.SINGLE_COUNTRIES))
		{
			return true;
		}
		return false;
	}
	
	/**
	 * This method will take in the ICU resource name and if there is an equivalent LDML tag name for it,
	 * that name is returned.
	 * @param icuResourceName
	 * @return
	 */
	private String translateICUtoLDMLName(String icuResourceName)
	{
		if(theHash == null)
		{
			populateTranslationHash();
		}
		
		Object temp = theHash.get(icuResourceName);
		if(temp == null)
		{
			return icuResourceName;
		}
		if(temp instanceof String)
		{
			return (String)temp;
		}
		return null;
	}
	
	private void populateTranslationHash()
	{
		theHash = new Hashtable();
			
		theHash.put("dayNames", LDMLConstants.DAYS);
		theHash.put("monthNames", LDMLConstants.MONTHS);
		theHash.put("Countries", LDMLConstants.TERRITORIES);
		theHash.put("Languages", LDMLConstants.LANGUAGES);
		theHash.put("Currencies", LDMLConstants.CURRENCIES);
		theHash.put("Variants", LDMLConstants.VARIANTS);
		theHash.put("Scripts", LDMLConstants.SCRIPTS);
		theHash.put("Keys", LDMLConstants.KEYS);
		theHash.put("Types", LDMLConstants.TYPES);
		theHash.put("Version", LDMLConstants.VERSION); 
		theHash.put("ExemplarCharacters", LDMLConstants.EXEMPLAR_CHARACTERS);
		theHash.put("zoneStrings", LDMLConstants.TZN);
		theHash.put("localPatternChars", LDMLConstants.LPC);
		theHash.put("PaperSize", LDMLConstants.PAPER_SIZE);
		theHash.put("dn", LDMLConstants.DISPLAY_NAME);
		theHash.put("fallback", LDMLConstants.INTVL_FMT_FALL);
		theHash.put("ec", LDMLConstants.EXEMPLAR_CITY);
		theHash.put("cu", LDMLConstants.COMMONLY_USED);
		theHash.put("unitPattern", LDMLConstants.UNIT);
		theHash.put("eras/abbreviated", LDMLConstants.ERAS + SEP + LDMLConstants.ERAABBR);
		theHash.put("eras/wide", LDMLConstants.ERAS + SEP + LDMLConstants.ERANAMES);
		theHash.put("eras/narrow", LDMLConstants.ERAS + SEP + LDMLConstants.ERANARROW);
		
		
		//***************MONTHS***************
		//months/format => months/monthContext[@type="format"]
		theHash.put(LDMLConstants.MONTHS + SEP + LDMLConstants.FORMAT, LDMLConstants.MONTHS + SEP + LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.FORMAT));
		
		//months/stand-alone => months/monthContext[@type="stand-alone"]
		theHash.put(LDMLConstants.MONTHS + SEP + LDMLConstants.STAND_ALONE, LDMLConstants.MONTHS + SEP + LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.STAND_ALONE));
		
		//monthContext[@type="format"]/wide => monthContext[@type="format"]/monthWidth[@type="wide"]  
		theHash.put(LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.WIDE,
					LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.MONTH_WIDTH + addXType(LDMLConstants.WIDE));
		
		//monthContext[@type="format"]/narrow => monthContext[@type="format"]/monthWidth[@type="narrow"]  
		theHash.put(LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.NARROW,
					LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.MONTH_WIDTH + addXType(LDMLConstants.NARROW));
		
		//monthContext[@type="format"]/abbreviated => monthContext[@type="format"]/monthWidth[@type="abbreviated"]  
		theHash.put(LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.ABBREVIATED,
					LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.MONTH_WIDTH + addXType(LDMLConstants.ABBREVIATED));
		
		//monthContext[@type="stand-alone"]/wide => monthContext[@type="stand-alone"]/monthWidth[@type="wide"]  
		theHash.put(LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.WIDE,
					LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.MONTH_WIDTH + addXType(LDMLConstants.WIDE));
		
		//monthContext[@type="stand-alone"]/narrow => monthContext[@type="stand-alone"]/monthWidth[@type="narrow"]  
		theHash.put(LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.NARROW,
					LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.MONTH_WIDTH + addXType(LDMLConstants.NARROW));
		
		//monthContext[@type="stand-alone"]/abbreviated => monthContext[@type="stand-alone"]/monthWidth[@type="abbreviated"]  
		theHash.put(LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.ABBREVIATED,
					LDMLConstants.MONTH_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.MONTH_WIDTH + addXType(LDMLConstants.ABBREVIATED));
		
		//***************DAYS*************
		
		//days/format => days/dayContext[@type="format"]
		theHash.put(LDMLConstants.DAYS + SEP + LDMLConstants.FORMAT, LDMLConstants.DAYS + SEP + LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.FORMAT));
		
		//days/stand-alone => days/dayContext[@type="stand-alone"]
		theHash.put(LDMLConstants.DAYS + SEP + LDMLConstants.STAND_ALONE, LDMLConstants.DAYS + SEP + LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.STAND_ALONE));
		
		//dayContext[@type="format"]/wide => dayContext[@type="format"]/dayWidth[@type="wide"]  
		theHash.put(LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.WIDE,
					LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.DAY_WIDTH + addXType(LDMLConstants.WIDE));
		
		//dayContext[@type="format"]/narrow => dayContext[@type="format"]/dayWidth[@type="narrow"]  
		theHash.put(LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.NARROW,
					LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.DAY_WIDTH + addXType(LDMLConstants.NARROW));
		
		//dayContext[@type="format"]/abbreviated => dayContext[@type="format"]/dayWidth[@type="abbreviated"]  
		theHash.put(LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.ABBREVIATED,
					LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.DAY_WIDTH + addXType(LDMLConstants.ABBREVIATED));
		
		//dayContext[@type="stand-alone"]/wide => dayContext[@type="stand-alone"]/dayWidth[@type="wide"]  
		theHash.put(LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.WIDE,
					LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.DAY_WIDTH + addXType(LDMLConstants.WIDE));
		
		//dayContext[@type="stand-alone"]/narrow => dayContext[@type="stand-alone"]/dayWidth[@type="narrow"]  
		theHash.put(LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.NARROW,
					LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.DAY_WIDTH + addXType(LDMLConstants.NARROW));
		
		//dayContext[@type="stand-alone"]/abbreviated => dayContext[@type="stand-alone"]/dayWidth[@type="abbreviated"]  
		theHash.put(LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.ABBREVIATED,
					LDMLConstants.DAY_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.DAY_WIDTH + addXType(LDMLConstants.ABBREVIATED));
		
		//***************QUARTERS*************
		//quarters/format => quarters/quarterContext[@type="format"]
		theHash.put(LDMLConstants.QUARTERS + SEP + LDMLConstants.FORMAT, LDMLConstants.QUARTERS + SEP + LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.FORMAT));
		
		//quarters/stand-alone => quarters/quarterContext[@type="stand-alone"]
		theHash.put(LDMLConstants.QUARTERS + SEP + LDMLConstants.STAND_ALONE, LDMLConstants.QUARTERS + SEP + LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.STAND_ALONE));
		
		//quarterContext[@type="format"]/wide => quarterContext[@type="format"]/quarterWidth[@type="wide"]  
		theHash.put(LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.WIDE,
					LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.QUARTER_WIDTH + addXType(LDMLConstants.WIDE));
		
		//quarterContext[@type="format"]/narrow => quarterContext[@type="format"]/quarterWidth[@type="narrow"]  
		theHash.put(LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.NARROW,
					LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.QUARTER_WIDTH + addXType(LDMLConstants.NARROW));
		
		//quarterContext[@type="format"]/abbreviated => quarterContext[@type="format"]/quarterWidth[@type="abbreviated"]  
		theHash.put(LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.ABBREVIATED,
					LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.FORMAT) + SEP + LDMLConstants.QUARTER_WIDTH + addXType(LDMLConstants.ABBREVIATED));
		
		//quarterContext[@type="stand-alone"]/wide => quarterContext[@type="stand-alone"]/quarterWidth[@type="wide"]  
		theHash.put(LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.WIDE,
					LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.QUARTER_WIDTH + addXType(LDMLConstants.WIDE));
		
		//quarterContext[@type="stand-alone"]/narrow => quarterContext[@type="stand-alone"]/quarterWidth[@type="narrow"]  
		theHash.put(LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.NARROW,
					LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.QUARTER_WIDTH + addXType(LDMLConstants.NARROW));
		
		//quarterContext[@type="stand-alone"]/abbreviated => quarterContext[@type="stand-alone"]/quarterWidth[@type="abbreviated"]  
		theHash.put(LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.ABBREVIATED,
					LDMLConstants.QUARTER_CONTEXT + addXType(LDMLConstants.STAND_ALONE) + SEP + LDMLConstants.QUARTER_WIDTH + addXType(LDMLConstants.ABBREVIATED));
		
	}
	
	private boolean usesType(String tag)
	{
		return (tag.equals(LDMLConstants.CALENDAR)
				|| tag.equals(LDMLConstants.MONTH_CONTEXT)
				|| tag.equals(LDMLConstants.MONTH_WIDTH)
				|| tag.equals(LDMLConstants.CALENDAR)
				|| tag.equals(LDMLConstants.CALENDAR)
				|| tag.equals(LDMLConstants.CALENDAR)
				|| tag.equals(LDMLConstants.CALENDAR));
	}
	
	private String cleanRelativePath(String p)
	{
		char[] cArray = new char[1];
		cArray[0] = SEP;
		String pathSep = new String(cArray);
		
		StringTokenizer tok = new StringTokenizer(p, pathSep);
		String returnString = p;
		if(tok.countTokens() > 1)
		{
			ArrayList l = new ArrayList();
			
			while(tok.hasMoreTokens())
			{
				l.add(tok.nextToken());
			}
			
			int x = 0;
			int z = 1;
			while(z < l.size())
			{
				StringTokenizer t = new StringTokenizer(translateICUtoLDMLName((String)l.get(x) + SEP + (String)l.get(z)), pathSep);
				l.set(x, t.nextToken());
				l.set(z, t.nextToken());
				z++;
				x++;
			}
			Object[] o = l.toArray();
			returnString = (String)o[0]; 
			for(x = 1; x < o.length; x++)
			{
				returnString += SEP + (String)o[x]; 
			}	  
		}
		
		return returnString;
	}
	
	
	//******************** Methods for File path constructions **************/
	
	private String getMainPath(ULocale locale)
	{
		return createFullPath(MAIN_FOLDER, locale.getName() + LDML_FILE_EXTENSION);
	}
	
	private String getCollationPath(ULocale locale)
	{
		return createFullPath(COLLATION_FOLDER, locale.getName() + LDML_FILE_EXTENSION);
	}
	
	private String getTransformsPath(ULocale locale)
	{
		return createFullPath(TRANSFORMS_FOLDER, locale.getName() + LDML_FILE_EXTENSION);
	}
	
	private String createFullPath(String folderName, String fileName)
	{
		String fullName = outDir;
		
		//if the last character is not a slash in the output directory
		if(!fullName.substring(fullName.length() - 1).equals(FILE_SEPERATOR)) 
		{
			fullName += "/";
		}
		fullName += folderName;
		
		File f = new File(fullName);
		if(!f.exists())
		{
			f.mkdir();
		}
		
		if(!fullName.substring(fullName.length() - 1).equals(FILE_SEPERATOR)) 
		{
			fullName += "/";
		}
		fullName += fileName;
		
		return fullName;
	}
	
	private void usage() 
	{
		System.out.println("\nUsage: ICU2LDMLWriter [OPTIONS] -d OUTPUTFOLDER [FILES]\n" +
		"This program generates LDML documents which represent the data currently inside of your ICU installation\n"+
		"If no files are given, a file for each supported locale will be produced.\n" +
		"If no destination folder is given, the file structure will be created in the current working directory.\n" + 
		"Options:\n" + 
		"-m or --main			Generate the main locale files.\n" +
		"-t or --trans			Generate the transliteration locale files.\n" + 
		"-c or --coll			Generate the collation files.\n" +
		"If none of the above options are given, all three types of files will be generated.\n");
		System.exit(-1);
	}
	
	private PrintWriter createPrinter(String fullPath) throws Exception
	{
		FileOutputStream fos = new FileOutputStream(fullPath);
		BufferedOutputStream bow = new BufferedOutputStream(fos);
		OutputStreamWriter osw = new OutputStreamWriter(bow, "UTF-8");
		PrintWriter pw = new PrintWriter(osw, true);
		return pw;
	}
	
	//**********************Printing Methods *********************************

	private void printInfo(String message)
	{
	    if(isVerbose())
	    {
	        System.out.println("INFO : " + currentLocaleName + ": " + message);
	    }
	}
	
	private void printWarning(String message)
	{
	    System.err.println("WARNING : " + currentLocaleName + ": " + message );
	}
	
	private void printError(String message)
	{
	    System.err.println("ERROR : " + currentLocaleName + ": " + message);
	}
	
	private boolean isVerbose()
	{
		return verbose;
	}
}
