/*
* MegaMek - Copyright (C) 2004 Ben Mazur (bmazur@sev.org)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package megamek.common.util;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;
/**
* This class represents a collection of files present within a directory
* hierarchy, categorized according to their directories. This collection will
* include all files inside of JAR and ZIP files that are located in the
* directory hierarchy. Created on January 17, 2004
*
* @author James Damour
* @version 1
*/
public class DirectoryItems implements Categorized {
/**
* The root category name.
*/
private String rootName;
/**
* A map of the category names to the sub-categories. Please note that this
* map includes the root category, if the root category contains any items.
*/
private TreeMap<String, Categorized> categories = new TreeMap<String, Categorized>(
StringUtil.stringComparator());
/**
* A map of item names to the <code>ItemFile</code>s in the root
* category.
*/
private TreeMap<String, ItemFile> items = new TreeMap<String, ItemFile>(
StringUtil.stringComparator());
/**
* The factory that will create <code>ItemFile</code>s for the contents
* of the directory hierarchy.
*/
private ItemFileFactory factory = null;
/**
* Helper function to file away new categories. It adds one entry in the map
* for each sub-category in the passed category.
*
* @param category - the <code>Categorized</code> files.
*/
private void addCategory(Categorized category) {
Iterator<String> names = category.getCategoryNames();
while (names.hasNext()) {
categories.put(names.next(), category);
}
}
/**
* Create a categorized collection of all files beneth the given directory.
* Please note, the name of any sub-directories will be added to the root
* category name to create the name of the sub-directories' category name.
*
* @param rootDir - the <code>File</code> object for the root directory of
* the image files. All files in this root, or in any sub-
* directory of this root will be included in this collection.
* This value must not be <code>null</code> and it must be a
* directory.
* @param categoryName - the <code>String</code> root category name for
* this collection. All sub-categories will include this name.
* This value may be <code>null</code> (it will be replaced).
* @param itemFactory - the <code>ItemFileFactory</code> that will create
* <code>ItemFile</code>s for the contents of the directory.
* This value must not be <code>null</code>.
* @throws <code>IllegalArgumentException</code> if <code>rootDir</code>
* is null or if it is not a directory, or if a
* <code>null</code> is passed for <code>itemFactory</code>.
*/
public DirectoryItems(File rootDir, String categoryName,
ItemFileFactory itemFactory) throws IllegalArgumentException {
// Validate input.
if (null == rootDir) {
throw new IllegalArgumentException(
"A null root directory was passed."); //$NON-NLS-1$
} else if (!rootDir.isDirectory()) {
throw new IllegalArgumentException(
"The passed file is not a directory."); //$NON-NLS-1$
}
if (null == itemFactory) {
throw new IllegalArgumentException(
"A null item factory was passed."); //$NON-NLS-1$
}
// Save the root category name and the item factory.
rootName = categoryName;
factory = itemFactory;
// Replace a null name with an empty name.
if (null == rootName) {
rootName = ""; //$NON-NLS-1$
}
/***********************************************************************
* DEBUG : uncomment this section to debug System.out.print( "Loading
* items from "); System.out.println( rootDir.getPath() ); /* DEBUG :
* uncomment this section to debug
*/
// Walk through the contents of the root directory.
String[] contents = rootDir.list();
for (int entry = 0; entry < contents.length; entry++) {
// Get the entry's file.
File file = new File(rootDir, contents[entry]);
// Is this entry a sub-directory?
if (file.isDirectory()) {
// Construct the category name for this sub-directory.
StringBuffer name = new StringBuffer();
name.append(rootName).append(contents[entry]).append("/"); //$NON-NLS-1$
// Parse the sub-directory, and add it to the map.
this.addCategory(new DirectoryItems(file, name.toString(),
factory));
}
// Is this entry a ZIP or JAR file?
else if (ZippedItems.isZipName(contents[entry])) {
// Construct the category name for this ZIP file.
StringBuffer name = new StringBuffer();
name.append(rootName).append(contents[entry]);
// Try to parse the ZIP file, and add it to the map.
try {
this.addCategory(new ZippedItems(file, name.toString(),
factory));
} catch (Exception err) {
// Print diagnostics and keep going.
System.err.print("Could not parse "); //$NON-NLS-1$
System.err.println(contents[entry]);
err.printStackTrace();
}
}
// Does the factory accept this entry?
else if (factory.accept(rootDir, contents[entry])) {
// Save the ItemFile for this entry.
items.put(contents[entry], factory.getItemFile(file));
}
/*******************************************************************
* DEBUG : uncomment this section to debug else { System.out.print(
* "... ignoring " ); System.out.println( contents[entry] ); } /*
* DEBUG : uncomment this section to debug
*/
} // Get the next entry in the root directory.
// If the root directory has any item files, add it to the map.
if (!items.isEmpty()) {
categories.put(rootName, this);
}
}
/**
* Get the names of all the categories.
*
* @return an <code>Enumeration</code> of <code>String</code> names.
* This value will not be <code>null</code>, but it may be empty.
*/
public Iterator<String> getCategoryNames() {
return categories.keySet().iterator();
}
/**
* Get the names of all the items in one of the categories.
*
* @param categoryName - the <code>String</code> name of the category
* whose item names are required.
* @return an <code>Enumeration</code> of <code>String</code> names.
* This value will not be <code>null</code>, but it may be empty.
*/
public Iterator<String> getItemNames(String categoryName) {
// Get the category with the given name.
Categorized category = categories.get(categoryName);
// Return an empty Enumeration if we couldn't find the category.
if (null == category) {
return new ArrayList<String>().iterator();
}
// Is this a subcategory?
if (this != category) {
// Yup. Pass the request on.
return category.getItemNames(categoryName);
}
// Return the names of this directory's items.
return items.keySet().iterator();
}
/**
* Get the indicated item from the correct catagory.
*
* @param categoryName - the <code>String</code> name of the category
* whose item names are required. This value may be
* <code>null</code>.
* @param itemName - the <code>String</code> name of the indicated item.
* @return the <code>Object<code> in the given category with the given
* name. This value may be <code>null</code>.
* @throws <code>Exception</code> if there's any error getting the item.
*/
public Object getItem(String categoryName, String itemName)
throws Exception {
// Validate input.
if (null == categoryName) {
throw new IllegalArgumentException(
"A null category name was passed."); //$NON-NLS-1$
}
if (null == itemName) {
throw new IllegalArgumentException("A null item name was passed."); //$NON-NLS-1$
}
// Make sure we have this category?
if (!categories.containsKey(categoryName)) {
return null;
}
// Get the category with the given name.
Categorized category = categories.get(categoryName);
// Is this a subcategory?
if (this != category) {
// Yup. Pass the request on.
return category.getItem(categoryName, itemName);
}
// Make sure we have an item by that name.
if (!items.containsKey(itemName)) {
return null;
}
// Find the named entry.
ItemFile entry = items.get(itemName);
// Return the item.
return entry.getItem();
}
}
|