package org.jcon.io;

import org.jcon.util.GenLib;
import java.io.File;
import java.io.FileReader;
import java.util.StringTokenizer;

/**
 * Class resource related static library methods.
 *
 * @author Jack Harich
 */
public class ResourceLib {

//---------- Initialization ------------------------------
public static void main(String args[]) { // Testing
    String path = getClassPath(new ResourceLib());
    print("You're a lucky winner, the path is: " + path);
    try {
        String filePath = getResourcePath(new ResourceLib());
        String fileName = filePath + "FileLib.java";
        print("fileName = " + fileName);

        // The test
        new FileReader(fileName);
        print("Successfully opened fileName" + fileName);

    } catch(Exception ex) {
        print("Exception " + ex);
    }
    print(".separator = " + File.separator);
}
//---------- Public Methods ------------------------------
/**
 * Returns the directory path containing the instance,
 * with a handy File.separator at the end. Appending a file
 * name to this gives the full fileName needed to open it.
 *
 * Useful for building a file name from its resource class.
 * Example "COM.test.Hello" returns "C:\JP\COM\test\" on Windows.
 * Note this only works locally on single files.
 */
public static String getResourcePath(Object instance) {
    return getResourcePath(instance.getClass().getName());
}
public static String getResourcePath(String className) {
    String classPath = getClassPath(className); 
    String fileName = classPath + File.separator + className;

    // Remove fileName at end
    fileName = getPackageName(fileName);
    fileName = fileName.replace('.', File.separatorChar);
    return fileName + File.separator;    
}    
/**
 * Returns the exact class path for the the instance.
 * When prepended to the class name with a "/" between,
 * this is the full file named needed to open files for
 * read and write. (Is there a better way?)
 */
public static String getClassPath(Object instance) {
    return getClassPath(instance.getClass().getName());
}
public static String getClassPath(String className) {
    String classPaths = System.getProperty("java.class.path");
    StringTokenizer tokens = new StringTokenizer(
        classPaths, File.pathSeparator); // *** Was ";" on Windows
    while (tokens.hasMoreElements()) {
        String path = (String)tokens.nextElement();
        try {
            String fileName = path + File.separator +
                className;
            fileName = fileName.replace('.', File.separatorChar);
            fileName += ".class";
            // Exception if incorrect
            new FileReader(fileName);
            return path;
        } catch(Exception ex) {
            // Do nothing, we'll try the next one
        }
    }
    GenLib.error("ResourceLib.getClassPath()",
        "Cannot get classPath for " + className);
    return null;    
}    
/**
 * Returns the first Class found by walking forwards using
 * the directory and fileName. (better way???)
 * If none are found then null is returned. The class MUST
 * have a no arg constructor.
 *
 * The fileName must be of the format "ClassName.class".
 * If the directory is null then the fileName must be
 * the fully qualified class name.
 */
public static Class getFileClass(String directory,
        String fileName) {

    // Remove ".class" from end of file if there
    int dotPosition = fileName.lastIndexOf(".");
    if (dotPosition != -1) fileName = fileName.substring(0, dotPosition);

    // Prepare to walk complete fileName
    String name = fileName;
    if (directory != null) {
        name = directory + fileName;
        // *** name = name.replace('\\', '.');
        name = name.replace(File.separatorChar, '.');
        
        // Remove drive
        name = removeFirstDirectory(name);
    }
    // Walk
    while (name != null) {
        try {
            return Class.forName(name);
        } catch(ClassNotFoundException ex) {
            name = removeFirstDirectory(name);
        }
    }
    return null;
}
/**
 * Returns the package name from the full className,
 * for example "COM.hjac.beans.TestBean" returns
 * "COM.hjac.beans".
 * Returns null if no package name is apparent.
 */
public static String getPackageName(String className) {
    int index = className.lastIndexOf(".");
    if (index == -1) {
        return null; // No period in className
    } else {
        return className.substring(0, index);
    }
}
//---------- Private Methods -----------------------------
// Returns null if no more periods
private static String removeFirstDirectory(String name) {
    int dotPosition = name.indexOf(".");
    if (dotPosition == -1) {
        return null;
    } else {
        return name.substring(dotPosition + 1);
    }
}
//--- Std
private static void print(String text) {
    System.out.println("ResourceLib" + text);
}

} // End class
