Package xplanetconfigurator.util

Source Code of xplanetconfigurator.util.XPlanetRessourceFinder

/*
* Published under GPLv3
*/
package xplanetconfigurator.util;

import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import xplanetconfigurator.gui.MainFrame;

/**
* This class helps to find the ressources directories of XPlanet using the
* same search behaviour as XPlanet.
*
* @author Tom Wiedenhoeft
*/
public class XPlanetRessourceFinder {

    private static String KEY_XPLANET_CONFIGDIR_PREFIX = "xplanet.dir.";
    private static String KEY_XPLANET_DIR_TESTED = "xplanet.dir.tested";
    private static String KEY_XPLANET_SEARCHDIR = "xplanet.searchdir";
    private static String KEY_XPLANET_DIR_USED = "xplanet.dir.used";
    private Logger logger;

    /**
     * <p>Should be the same behaviour as in XPlanet. If xPlanet needs a
     * file (example map of the earth)it a searches through the file system.
     * See below for the exact search behaviour of xPlanet. It takes the
     * first directory it can find (for example the 'images' directory)</p>
     * <p>If this function finds a a directory ('images'), it
     * checks wether the files in this directory can be written. Why?
     * The Downloader tries to copy files into the file system. It double
     * checks: a) can overwrite an existing file in the directory,
     * b) can write a new file into the found directory. If both is
     * possible take this directory. If not keep searching according to xPlanets search
     * behaviour. If existing files can not be overwritten but new files
     * can be created do not take the directory.</p>
     * <p>If this function found a directory ('images') it sets
     * a system property in the manner of 'xplanet.dir.images'. Later
     * another part of the program is using these properties for reading
     * and writing files (as maps, markers,...) to it.</p>
     * <p>If no directory was found the program creates one and sets
     * the System Property to it.<br>
     * Assume no images directory 'images' was found th program would
     * create:</p>
     * <ul>
     * <li>Windows: ${HOME}/.xplanet/images</li>
     * <li>X11: ${HOME}/.xplanet/images</li>
     * <li>Mac OS: ${HOME}/Library/Xplanet</li>
     * </ul>
     * Here the help text of XPlanet<br>
     * -searchdir directory<br>
     * Any files used by xplanet should be placed in one of the following
     * directories depending on its type: "arcs", "config", "ephemeris",
     * "fonts", "images", "markers", "origin", "satellites", or "stars".  By
     * default, xplanet will look for a file in the following order:<ul>
     * <li>The current directory</li>
     * <li>searchdir</li>
     * <li>subdirectories of searchdir</li>
     * <li>subdirectories of xplanet (if it exists in the current directory)</li>
     * <li>subdirectories of ${HOME}/.xplanet on X11</li>
     * <li>subdirectories of ${HOME}/Library/Xplanet on Mac OS X</li>
     * <li>subdirectories of DATADIR/xplanet</li>
     * <li>DATADIR is set at compile time and defaults to /usr/local/share.</li></ul>
     * <p>Call checkUserPreferences() explicitely if  the class should use them.</p>
     */
    public XPlanetRessourceFinder() {
        this.logger = Logger.getLogger(this.getClass().getName());
    }

    public XPlanetRessourceFinder(boolean readUserPreferences) {
        this();
        if (readUserPreferences) {
            this.checkUserPreferences();
        }
    }

    public void setXPlanetSearchDir(String searchdir) {
        // Reset the used dir if the search dir has changed
        String existingSearchDir = System.getProperty(KEY_XPLANET_SEARCHDIR, "");
        if (searchdir == null) {
            searchdir = "";
        }
        if (!existingSearchDir.equals(searchdir)) {
            this.resetXPlanetDirs();
        }
        if (!searchdir.equals("")) {
            this.logger.finer("Set system property '" + KEY_XPLANET_SEARCHDIR + "' to '" + searchdir + "'.");
            searchdir = searchdir.replaceAll("\\\\", "/");
            System.setProperty(KEY_XPLANET_SEARCHDIR, searchdir);
            this.saveUserPrefs();
        } else {
            this.logger.finer("Reset system property '" + KEY_XPLANET_SEARCHDIR + "'.");
            System.setProperty(KEY_XPLANET_SEARCHDIR, "");
            this.saveUserPrefs();
        }
    }

    public String getXPlanetSearchDir() {
        String searchDir = System.getProperty(KEY_XPLANET_SEARCHDIR, "");
        searchDir = searchDir.replaceAll("\\\\", "/");
        return searchDir;
    }

    /**
     * replace a parameter of a control in the long parameter string and send it back.
     */
    public String replaceSearchDir(String parameters) {
        String regExpr = "(?i)(-searchdir\\b)(\\s*)([^-]*)";
        String searchdir = this.getXPlanetSearchDir();
        if (!"".equals(searchdir)) {
            searchdir = "-searchdir " + searchdir + " ";
        }
        this.logger.finer("Befor replacement by " + regExpr + ": Parameters: " + parameters);
        Pattern p = Pattern.compile(regExpr);
        Matcher matcher = p.matcher(parameters);
        if (matcher.find()) {
            String found = matcher.group();
            this.logger.finer("Found: " + found + ". Replacing parameters: ownParam: " + searchdir + "...");
            parameters = parameters.replaceAll(regExpr, searchdir);
        } else {
            this.logger.finer("Appending parameters: ownParam: " + searchdir + "...");
            parameters = parameters.trim() + " " + searchdir;
        }
        this.logger.finer("After replacement by " + regExpr + ": Parameters: " + parameters);
        return parameters;
    }

    /**
     * Read all values from the user preferences if not found in the
     * system properties: searchdir, used dir, tested dir.
     */
    private void checkUserPreferences() {
        logger.finer("Loading user preferences...");
        String searchDir = System.getProperty(KEY_XPLANET_SEARCHDIR);
        if (searchDir != null && !"".equals(searchDir)) {
            this.logger.finer("Do not load '" + KEY_XPLANET_SEARCHDIR + "' from user preferences because found System Property '" + KEY_XPLANET_SEARCHDIR + "' = '" + searchDir + "' as user preference.");
        } else {
            OwnPreferences prefs = OwnPreferences.userNodeForPackage(this.getClass());
            searchDir = prefs.get(KEY_XPLANET_SEARCHDIR, "");
            if ("".equals(searchDir)) {
                this.logger.finer("Found '" + KEY_XPLANET_SEARCHDIR + "' neither in System Properties nor in User Preferences.");
            } else {
                this.logger.finer("Found '" + KEY_XPLANET_SEARCHDIR + "' not in System Properties but in the User Preferences with value = '" + searchDir + "'. Set as System Property.");
                System.setProperty(KEY_XPLANET_SEARCHDIR, searchDir);
            }
        }
        String dir = System.getProperty(KEY_XPLANET_DIR_TESTED, "");
        if (dir != null && !"".equals(dir)) {
            this.logger.finer("Found value for key '" + KEY_XPLANET_DIR_TESTED + "' in the system properties.");
        } else {
            this.logger.finer("No value for key '" + KEY_XPLANET_DIR_TESTED + "' was found in the system properties. Looking into the user preferences.");
            OwnPreferences prefs = OwnPreferences.userNodeForPackage(this.getClass());
            dir = prefs.get(KEY_XPLANET_DIR_TESTED, "");
            if (dir.equals("")) {
                this.logger.finer("No value for key '" + KEY_XPLANET_DIR_TESTED + "' was found in the user preferences.");
            } else {
                System.setProperty(KEY_XPLANET_DIR_TESTED, dir);
            }
        }
        dir = System.getProperty(KEY_XPLANET_DIR_USED, "");
        if (dir != null && !"".equals(dir)) {
            this.logger.finer("Found value for key '" + KEY_XPLANET_DIR_USED + "' in the system properties.");
        } else {
            this.logger.finer("No value for key '" + KEY_XPLANET_DIR_USED + "' was found in the system properties. Looking into the user preferences.");
            OwnPreferences prefs = OwnPreferences.userNodeForPackage(this.getClass());
            dir = prefs.get(KEY_XPLANET_DIR_USED, "");
            if (dir.equals("")) {
                this.logger.finer("No value for key '" + KEY_XPLANET_DIR_USED + "' was found in the user preferences.");
            } else {
                System.setProperty(KEY_XPLANET_DIR_USED, dir);
            }
        }
    }

    private void saveUserPrefs() {
        logger.finer("Saving user preferences...");
        OwnPreferences prefs = OwnPreferences.userNodeForPackage(this.getClass());
        String searchDir = System.getProperty(KEY_XPLANET_SEARCHDIR);
        prefs.put(KEY_XPLANET_SEARCHDIR, searchDir);
        this.logger.finer("Store '" + KEY_XPLANET_SEARCHDIR + "' = '" + searchDir + "' as user preference.");
    }

    /**
     * Find a config directory and set the system property in the
     * manner of 'xplanet.dir.images'. The same search behaviour
     * of XPlanet is used.<br> By
     * default, xplanet will look for a file in the following order:<ul>
     * <li>The current directory</li>
     * <li>searchdir</li>
     * <li>subdirectories of searchdir</li>
     * <li>subdirectories of xplanet (if it exists in the current directory)</li>
     * <li>subdirectories of ${HOME}/.xplanet on X11</li>
     * <li>subdirectories of ${HOME}/Library/Xplanet on Mac OS X</li>
     * <li>subdirectories of DATADIR/xplanet</li>
     * <li>DATADIR is set at compile time and defaults to /usr/local/share.</li></ul>
     * <p>The guessing of the directory will fail if
     * <ul>
     * <li>Files lay directly in the current directory, or</li>
     * <li>Files lay directly in -searchdir and not one of its subdirectories</li>
     * </ul>
     * Why? This class/function will allways look for directories (and check
     * wether it can write a file to it) but not for files. If there is no
     * subdirectory it will preceed to the next place. Therefor its a good
     * idea to have no file directly in the current directory or the
     * -searchdir.</p>
     *
     * @param ressourceDirName for exampel: 'images', 'markers',...
     * @return the found config directory. Search for it if
     * it was not yet found in the System Properties.
     * the system properties. Returns null if nothing was found.
     */
    public String getRessourceDirectory(String ressourceDirName) {
        this.logger.finer("Try to get a directory for ressource/directory " + ressourceDirName + "...");
        //----------------------------------------------------------------------
        //--- Stored value as System Property ----------------------------------
        //----------------------------------------------------------------------
        String key = KEY_XPLANET_CONFIGDIR_PREFIX + ressourceDirName;
        this.logger.finer("Looking for key '" + key + "'...");
        String subdir = System.getProperty(key);
        this.logger.finer("Found System Property '" + subdir + "' (directory) for key '" + key + "'.");
        if (subdir != null && !"".equals(subdir)) {
            this.logger.finer("Value '" + subdir + "' is not set for key '" + key + "'.");
            // Check wether the KEY_XPLANET_DIR_TESTED is still the same.
            String xplanetDir = System.getProperty(KEY_XPLANET_DIR_USED);
            this.logger.finer("Found System Property '" + xplanetDir + "' for key '" + KEY_XPLANET_DIR_USED + "'.");
            if (xplanetDir != null) {
                if (subdir.startsWith(xplanetDir)) {
                    this.logger.finer("'" + key + "' = '" + subdir + "' is a subdirectory of '" + KEY_XPLANET_DIR_USED + "' = '" + xplanetDir + "'.");
                    return subdir;
                }
            }
        }

        //----------------------------------------------------------------------
        //--- subdirectories of searchdir --------------------------------------
        //----------------------------------------------------------------------
        // Search the search directory (-searchdir) and its subdirectories
        this.logger.finer("Looking for key '" + KEY_XPLANET_SEARCHDIR + "'...");
        String searchdir = System.getProperty(KEY_XPLANET_SEARCHDIR);
        this.logger.finer("Found System Property '" + searchdir + "' (directory) for key '" + KEY_XPLANET_SEARCHDIR + "'.");
        if (searchdir != null && !"".equals(searchdir)) {
            subdir = this.searchDirectories(ressourceDirName, searchdir, true);
            if (subdir != null) {
                return subdir;
            }
        }
        //----------------------------------------------------------------------
        //--- Tested directories analysed from xplanet call --------------------
        //----------------------------------------------------------------------
        this.logger.finer("Start seaching file system for the ressource directory '" + ressourceDirName + "'...");
        String xplanetDir = System.getProperty(KEY_XPLANET_DIR_TESTED);
        if (xplanetDir != null) {
            subdir = this.searchDirectories(ressourceDirName, xplanetDir, true);
            if (subdir != null) {
                return subdir;
            } else {
                // This will set the System Property as well
                subdir = this.makeRessourceDir(xplanetDir, ressourceDirName);
                if (subdir != null) {
                    return subdir;
                }
            }
        }

        this.logger.warning("No System Property found for key='" + KEY_XPLANET_DIR_TESTED + ". This should usually not happen. Does XPlanet use the realy the same config and ressources as the Configurator does? Start seaching file system...");

        //----------------------------------------------------------------------
        //--- The current directory -- (without subdirectories) ----------------
        //----------------------------------------------------------------------
        String userDir = System.getProperty("user.dir");
        this.logger.finer("Found the user.dir '" + userDir + "'. Start searching this directory...");
        subdir = this.searchDirectories(ressourceDirName, userDir, false);
        if (subdir != null) {
            return subdir;
        }

        //----------------------------------------------------------------------
        //--- subdirectories of xplanet (if it exists in the current directory)-
        //----------------------------------------------------------------------
        // We do not know where the executable xplanet is installed.
        // On Windows the user is asked to copie the xplanet.jar to the same
        // directory than the xplanet.exe. If xplanet.jar is started it is the
        // user.dir.
        // On Mac and Linux it is likely to be the same if the user
        // compiles the sources. In this case the path will probably to xplanet
        // will not be set and the user should have xplanet.jar and the xplanet
        // executable in the same directory as well.
        // If xplanet is in the path and is not in the same directory as
        // the xplanet.jar and we hope it is likely that no config files will
        // be in the subdirectories of xplanet. This could cause problems. But
        // with the parameter -searchdir it should be no problem. If the user
        // takes example configuration he could start xplanet.jar with the
        // proper System Properties for example 'xplanet.dir.images'.
        // This class will use it and won't search for directories.

        //----------------------------------------------------------------------
        //--- subdirectories of ${HOME}/.xplanet on X11 ------------------------
        String userHome = System.getProperty("user.home");
        this.logger.finer("Found the user.home '" + userHome + "'.");
        String userHomeX11 = userHome + File.separator + ".xplanet";
        this.logger.finer("Start searching directory '" + userHomeX11 + "' for X11...");
        subdir = this.searchDirectories(ressourceDirName, userHomeX11, true);
        if (subdir != null) {
            return subdir;
        }

        //----------------------------------------------------------------------
        //--- subdirectories of ${HOME}/Library/Xplanet on Mac OS X-------------
        String userHomeMacOS = userHome + File.separator + "Library" + File.separator + "Xplanet";
        this.logger.finer("Start searching directory '" + userHomeMacOS + "' for Mac OS...");
        subdir = this.searchDirectories(ressourceDirName, userHomeMacOS, true);
        if (subdir != null) {
            return subdir;
        }

        //----------------------------------------------------------------------
        //--- subdirectories of DATADIR/xplanet
        //--- DATADIR is set at compile time and defaults to /usr/local/share.--
        String dataDir = "/usr/local/share/xplanet";
        this.logger.finer("Start searching directory '" + dataDir + "' for DATADIR/xplanet, default is /usr/local/share/xplanet...");
        subdir = this.searchDirectories(ressourceDirName, dataDir, true);
        if (subdir != null) {
            return subdir;
        }

        this.logger.finer("Found no suitable directory for '" + ressourceDirName + "'. Try to recover by making directory...");
        subdir = this.makeConfigDir(ressourceDirName);
        if (subdir != null) {
            return subdir;
        }

        return null;
    }

    private boolean isWindows() {
        String osName = System.getProperty("os.name");
        this.logger.finer("System property os.name is '" + osName + "'.");
        if (osName.matches("(?i).*windows.+")) {
            this.logger.finer("... is Windows");
            return true;
        } else {
            this.logger.finer("... is not Windows");
        }
        return false;
    }

    private boolean isLinux() {
        String osName = System.getProperty("os.name");
        this.logger.finer("System property os.name is '" + osName + "'.");
        if (osName.matches("(?i).*linux.*")) {
            this.logger.finer("... is Linux");
            return true;
        } else {
            this.logger.finer("... is not Linux");
        }
        return false;
    }

    private boolean isMac() {
        String osName = System.getProperty("os.name");
        this.logger.finer("System property os.name is '" + osName + "'.");
        if (osName.matches("(?i).*Mac.*")) {
            this.logger.finer("... is Mac");
            return true;
        } else {
            this.logger.finer("... is not Mac");
        }
        return false;
    }

    /**
     *
     * <p>This functios is called as fallback if no directory was found
     * for, lets say 'images'. The program creates a directory and sets
     * the System Property to it.<br>
     * Assume no images directory 'images' was found th program would
     * create:</p>
     * <ul>
     * <li>Windows: System Property xplanet.dir.images = ${HOME}/.xplanet/images</li>
     * <li>X11: System Property xplanet.dir.images = ${HOME}/.xplanet/images</li>
     * <li>Mac OS: System Property xplanet.dir.images = ${HOME}/Library/Xplanet</li>
     * </ul>
     * @param ressourceDirName like 'images', 'markers',...
     * @return the directory created.
     */
    private String makeConfigDir(String configDirName) {
        this.logger.finer("Trying to make directory for '" + configDirName + "'...");
        String dir = null;
        String osName = System.getProperty("os.name");
        if (osName != null) {
            String userDir = System.getProperty("user.dir");
            if (!this.canWriteToDir(userDir)) {
                userDir = null;
            }

            //------------------------------------------------------------------
            //-- Oop, tell Hari Nairi why he implemented this behaviour.
            //-- XPlanet under windows will first search for:
            //-- 1. user.dir/xplanet/...
            //-- 2. C:/WINDOWS/DESKTOP/xplanet-1.2.0/xplanet/... (Ask Hari why hi did this.)
            //-- 3. Stop the search
            //-- Ask him to change it to the search behaviour as described in the docu for -searchdir
            String windowsSecondDir = "C:/WINDOWS/DESKTOP/xplanet-1.2.0/xplanet/";
            //------------------------------------------------------------------
            String userHome = System.getProperty("user.home");
            // Guess for Windows
            if (osName.matches("(?i).*windows.+")) {
                if (userDir != null) {
                    dir = userDir + File.separator + "xplanet" + File.separator + configDirName;
                } else {
                    // this should never been used because xplanet under windows will not search the config here by default.
                    this.logger.warning("There is probably something wrong with place where the configuration is stored. The Configurtor is using the home directory but XPlanet will not use it under Windows. The changes you are making in the GUI will have most probably no effect the output of XPlanet.");
                    dir = userHome + File.separator + ".xplanet" + File.separator + configDirName;
                }
            } else if (osName.matches("(?i).*linux.*")) {
                if (userDir != null) {
                    dir = userDir + File.separator + configDirName;
                } else {
                    dir = userHome + File.separator + ".xplanet" + File.separator + configDirName;
                }
            } else if (osName.matches("(?i).*mac.+")) {
                if (userDir != null) {
                    dir = userDir + File.separator + configDirName;
                } else {
                    dir = userHome + File.separator + "Library" + File.separator + "Xplanet" + File.separator + configDirName;
                }
            } else {
                this.logger.warning("No operating System found. Please check ths source code (this program).");
            }
        } else {
            this.logger.warning("No System Property 'os.name' found. This should never happen.");
        }
        if (dir != null) {
            File d = new File(dir);
            try {
                if (!d.exists()) {
                    boolean success = d.mkdirs();
                    if (!success) {
                        this.logger.finer("Failed to make directory for '" + dir + "' without an exception.");
                        return null;
                    }
                }
                String key = KEY_XPLANET_CONFIGDIR_PREFIX + configDirName;
                System.setProperty(key, dir);
                this.logger.fine("Set Property key='" + key + "', value='" + dir + "'");
            } catch (Exception e) {
                this.logger.warning(e.getMessage() + " - Failed to make directory for '" + dir + "'.");
            }
        }
        return dir;
    }

    /**
     * Create a subdirectory. Check wether a file can be written into it.
     * It sets the System.Property automatically for this ressource dir.
     * @param baseDir
     * @param ressourceSubdir
     * @return true the absolut path to the directory
     */
    private String makeRessourceDir(String baseDir, String ressourceSubdir) {
        String dir = baseDir + File.separator + ressourceSubdir;
        if (dir != null) {
            File d = new File(dir);
            try {
                if (!d.exists()) {
                    boolean success = d.mkdirs();
                    if (!success) {
                        this.logger.finer("Failed to make directory for '" + dir + "' without an exception.");
                        return null;
                    }
                }
                String key = KEY_XPLANET_CONFIGDIR_PREFIX + ressourceSubdir;
                System.setProperty(key, dir);
                this.logger.fine("Set Property key='" + key + "', value='" + dir + "'");
                return dir;
            } catch (Exception e) {
                this.logger.warning(e.getMessage() + " - Failed to make directory for '" + dir + "'.");
            }
        }
        return null;
    }

    private boolean canWriteToDir(String dir) {
        if (dir != null && !"".equals(dir)) {
            this.logger.finer("Check wether application can write files into directory '" + dir + "'...");
            File d = new File(dir);
            File tempFile = new File(dir + File.separator + "xplanet.tmp");
            // Just in case it is there.
            tempFile.delete();
            boolean canCreate = false;
            try {
                canCreate = tempFile.createNewFile();
            } catch (IOException ex) {
                this.logger.warning(ex.getMessage() + " - Could write xplanet.tmp to dir '" + dir + "'.");
                return false;
            }
            if (canCreate) {
                this.logger.finer("Could write xplanet.tmp to dir '" + dir + "'. Deleting it again...");
                if (tempFile.delete()) {
                    this.logger.finer("Deleted xplanet.tmp to dir '" + dir + "'");
                } else {
                    this.logger.warning("Failed to deleted xplanet.tmp to dir '" + dir + "'");
                }
                return true;
            }
        }
        return false;
    }

    /**
     * Search the directory and its subdirectories.
     * Set a System Property in the manner of 'xplanet.dir.images'
     * if a directory is found and existing files in it can be
     * overwrittten AND new files in this directory can be created.
     * @param ressourceDirName like 'images', 'markers',...
     * @param dir absolute path
     * @param recursive include subdirectories
     * @return the found config directory
     */
    private String searchDirectories(String configDirName, String dir, boolean recursive) {
        if (configDirName == null) {
            this.logger.warning("No config dir name given as parameter ('images', 'markers',..)");
            return null;
        }
        if (configDirName.equals("")) {
            this.logger.warning("Empty String for config dir name given as parameter ('images', 'markers',..)");
            return null;
        }
        this.logger.fine("Start to search diectory '" + dir + "' for the config dir name '" + configDirName + "'...");
        File d = new File(dir);
        if (!d.exists()) {
            this.logger.finer("The directory'" + dir + "' does not exist. Returning...");
            return null;
        }
        if (!d.isDirectory()) {
            this.logger.finer("The directory'" + dir + "' is not a directory. Returning...");
            return null;
        }
        // Look for the config directory as subdirectory
        File[] subdirs = d.listFiles();
        int length = subdirs.length;
        for (int i = 0; i < length; i++) {
            File subdir = subdirs[i];
            if (subdir.isDirectory()) {
                this.logger.fine("Seaching subirectory'" + subdir.getAbsolutePath() + "'.");
                String dirName = subdir.getName();
                if (configDirName.equalsIgnoreCase(dirName)) {
                    this.logger.finer("Name of subdirectory '" + dirName + "' matches.");
                    // Check wether files in this directory can be overwritten.
                    File[] files = subdir.listFiles();
                    int l = files.length;
                    if (l > 0) {
                        for (int j = 0; j < l; j++) {
                            File file = files[j];
                            if (file.isFile()) {
                                this.logger.finer("Found a file '" + file + "' in the directory" + subdir.getAbsolutePath() + "'.");
                                if (file.canWrite()) {
                                    this.logger.finer("Found a file'" + file + "' in the directory" + subdir.getAbsolutePath() + "' that can be overwritten.");
                                    String foundDir = testAndSetConfigDir(configDirName, subdir);
                                    if (foundDir != null) {
                                        this.logger.finer("Found a suituable subdirectory in '" + subdir.getAbsolutePath() + "'. Leaving directory...");
                                        return foundDir;
                                    }
                                }
                            } else {
                                this.logger.finer("Leaving subdirectorys because found a file'" + file + "' in the directory" + subdir.getAbsolutePath() + "' that can not be overwritten. Do not test any other file in this directory. This would be useless for the Downloader because it is likely that it will try to copy file into this directory, like clouds or markers.");
                                break;
                            }
                        }
                    } else {
                        this.logger.finer("Test to write a file into the empty directory '" + subdir.getAbsolutePath() + "'");
                        String foundDir = testAndSetConfigDir(configDirName, subdir);
                        if (foundDir != null) {
                            this.logger.finer("Found a suituable subdirectory in '" + subdir.getAbsolutePath() + "'. Leaving directory...");
                            return foundDir;
                        }
                    }

                } else {
                    this.logger.finer("Search the subdirectories of '" + subdir + "'. Name of subdirectory '" + dirName + "' does not match.");
                    // Go deeper into the subdirectories
                    if (recursive) {
                        String foundDir = this.searchDirectories(configDirName, subdir.getAbsolutePath(), recursive);
                        if (foundDir != null) {
                            this.logger.finer("Found a suituable subdirectory in '" + subdir.getAbsolutePath() + "'. Leaving directory...");
                            return foundDir;
                        }
                    } else {
                        this.logger.finer("Do not search the subdirectories of '" + subdir.getAbsolutePath() + "'.");
                    }
                }
            } else {
                this.logger.finer("Found a file not a subdirectory'" + subdir.getAbsolutePath() + "'.");
            }
        }
        return null;
    }

    /**
     * Try to write a test file into the directory. If successfull than
     * set the System property and return the found directory.
     * @param ressourceDirName like 'images', 'markers',...
     * @param subdir
     * @return the found direcrtory (same as parameter) or null if the
     * creation of a new file in the directory failed.
     */
    private String testAndSetConfigDir(String configDirName, File subdir) {
        boolean created = false;
        // Test if a new file can be written to this directory
        File testFile = new File(subdir.getAbsolutePath() + File.separator + "xplanettestfile");
        try {
            created = testFile.createNewFile();
        } catch (IOException ex) {
            this.logger.fine(ex.toString() + " - Can not create files in this directory '" + subdir + "'. Leaving this subdirectory...");
            return null;
        }
        if (!created) {
            this.logger.finer("Can not create files in this directory '" + subdir + "'. Leaving this subdirectory...");
        } else {
            this.logger.finer("Can create files in this directory '" + subdir + "'. Leaving this subdirectory...");
            String key = KEY_XPLANET_CONFIGDIR_PREFIX + configDirName;
            System.setProperty(key, subdir.getAbsolutePath());
            this.logger.fine("Set Property key='" + key + "', value='" + subdir.getAbsolutePath() + "'");
            this.logger.finer("Deleting test file '" + testFile + "'...");
            boolean deleted = testFile.delete();
            if (!deleted) {
                this.logger.warning("Could create a test file '" + testFile + "' but could not deleted it. Please check and delete if still there.");
            }
            // Set the used directory
            String parent = subdir.getParent();
            System.setProperty(KEY_XPLANET_DIR_USED, parent);
            return subdir.getAbsolutePath();
        }
        return null;
    }

    public String getRootDirectoryForDownloads() {
        String confDir = this.getRessourceDirectory("config");
        File f = new File(confDir);
        File parent = f.getParentFile();
        String dir = parent.getAbsolutePath();
        this.logger.finer("Returning '" + dir + "' as root directory for local Downloads.");
        return dir;
    }

    /**
     * Take the command line parameters of XPlanet and read value of -searchdir
     * from it.
     * @param parameters the command line parameters of XPlanet
     */
    public void readSearchDir(String parameters) {
        String regExpr = "(?i)(-searchdir\\b)(\\s*)([^-]*)";
        Pattern p = Pattern.compile(regExpr);
        if (parameters == null) {
            parameters = "";
        }
        Matcher matcher = p.matcher(parameters);
        while (matcher.find()) {
            String found = matcher.group();
            this.logger.finer("Found : '" + found + "' for (?i)(-searchdir\\b)(\\s*)([^-]*)");
            String foundValue = matcher.group(3);
            if (foundValue != null) {
                foundValue = foundValue.trim();
                // do not allow blanks
                if (!foundValue.equals("")) {
                    this.logger.finer("Found '" + foundValue + "' for -searchdir.");
                    System.setProperty(KEY_XPLANET_SEARCHDIR, foundValue);
                }
            }
        }
    }

    /**
     * Look first into to the system properties. If not found there than look
     * into the user preferences and set as system property
     * if a directory is stored.
     * @return absolute path to the directory (test result)
     */
    public String getXPlanetDirUsed() {
        String dir = System.getProperty(KEY_XPLANET_DIR_USED, "");
        if (dir != null && !"".equals(dir)) {
            this.logger.finer("Found value for key '" + KEY_XPLANET_DIR_USED + "' in the system properties.");
        } else {
            this.logger.finer("No value for key '" + KEY_XPLANET_DIR_USED + "' was found in the system properties. Looking into the user preferences.");
        }
        return dir;
    }

    /**
     * Revmove it from the System Properties as well as from the
     * User Preferences.
     */
    public void resetXPlanetDirs() {
        this.logger.finer("Setting back all the System Properties starting with '" + KEY_XPLANET_CONFIGDIR_PREFIX + "'...");
        PropertiesReader pr = new PropertiesReader();
        pr.removeSystemPropertyStartingWith(KEY_XPLANET_CONFIGDIR_PREFIX);
        OwnPreferences prefs = OwnPreferences.userNodeForPackage(this.getClass());
        prefs.put(KEY_XPLANET_DIR_TESTED, "");
        prefs.put(KEY_XPLANET_DIR_USED, "");
    }

    /**
     * <p>Analyse the system.out and sytem.err to find the 'config' directory where
     * XPlanet tries to find a config file ressources</p>
     * Sample output for linux
     * <pre>2009-11-07 04:28:41.282 - std.out - Looking for shouldNotExist ... not found
     * 2009-11-07 04:28:41.387 - std.out - Looking for xplanet/shouldNotExist ... not found
     * 2009-11-07 04:28:41.397 - std.out - Looking for xplanet/config/shouldNotExist ... not found
     * 2009-11-07 04:28:41.466 - std.out - Looking for /home/tom/.xplanet/shouldNotExist ... not found
     * 2009-11-07 04:28:41.474 - std.out - Looking for /home/tom/.xplanet/config/shouldNotExist ... not found
     * 2009-11-07 04:28:41.480 - std.out - Looking for /usr/share/xplanet/shouldNotExist ... not found
     * 2009-11-07 04:28:41.486 - std.out - Looking for /usr/share/xplanet/config/shouldNotExist ... not found
     * 2009-11-07 04:28:41.502 - std.err - Warning: Can't find shouldNotExist in
     * 2009-11-07 04:28:41.509 - std.err - xplanet/config
     * 2009-11-07 04:28:41.516 - std.err - /home/tom/.xplanet/config
     * 2009-11-07 04:28:41.523 - std.err - /usr/share/xplanet/config
     * 2009-11-07 04:28:41.531 - std.err - In findFile.cpp at line 107
     * 2009-11-07 04:28:41.538 - std.err -
     * 2009-11-07 04:28:41.546 - std.err - Error: Can't load configuration file shouldNotExist
     * 2009-11-07 04:28:41.561 - std.err - Exiting from readConfig.cpp at line 519
     * </pre>
     * Sample output for Windows
     * <pre>
     * 2009-11-08 17:08:50.919 - std.out - Looking for shouldNotExist ... not found
     * 2009-11-08 17:08:50.935 - std.out - Looking for xplanet\\shouldNotExist ... not found
     * 2009-11-08 17:08:50.940 - std.out - Looking for xplanet\\config\\shouldNotExist ... not found
     * 2009-11-08 17:08:50.946 - std.out - Looking for C:\WINDOWS\DESKTOP\xplanet-1.2.0\\xplanet\\shouldNotExist ... not found
     * 2009-11-08 17:08:50.957 - std.out - Looking for C:\WINDOWS\DESKTOP\xplanet-1.2.0\\xplanet\\config\\shouldNotExist ... not found
     * 2009-11-08 17:08:50.963 - std.err - Warning: Can't find shouldNotExist in
     * 2009-11-08 17:08:50.970 - std.err - xplanet\\config
     * 2009-11-08 17:08:50.976 - std.err - C:\WINDOWS\DESKTOP\xplanet-1.2.0\\xplanet\\config
     * 2009-11-08 17:08:50.984 - std.err - In findFile.cpp at line 107
     * 2009-11-08 17:08:50.990 - std.err -
     * 2009-11-08 17:08:50.996 - std.err - Error: Can't load configuration file shouldNotExist
     * 2009-11-08 17:08:51.004 - std.err - Exiting from readConfig.cpp at line 519
     * </pre>
     * <p>The search will prepend the user.dir (working directory) to
     * relativ paths</p>
     * @param xPlanetMessages
     * @return the parent directory of the found 'config'.
     */
    public String getXPlanetDirTested(String xPlanetMessages) {
        this.logger.finer("Analysing directory from system.out and system.err of XPlanet. Output is: " + xPlanetMessages);
        String dir = null;
        Pattern p = Pattern.compile("(?i)(Looking for)(.+\\bconfig\\b)(.+\\.\\.\\.)");
        Matcher m = p.matcher(xPlanetMessages);
        while (m.find()) {
            String line = m.group();
            String found = m.group(2);
            if (found != null) {
                dir = found.trim();
                this.logger.finer("Found a line '" + line + "' in the test output of xplanet that seems to contain the config directory: '" + dir + "'.");
                File d = new File(dir);
                if (!d.isAbsolute()) {
                    if (this.isWindows()) {
                        // Prepend user.dir
                        this.logger.finer("The directory '" + dir + "' is relativ.");
                        String userDir = System.getProperty("user.dir");
                        dir = userDir + File.separator + dir;
                        this.logger.finer("Prepended the user.dir to make it an absolute path '" + dir + "'.");
                    } else {
                        this.logger.finer("Is not Windows. Do not prepend the user.dir to directory '" + dir + "'. Under Linux the user.dir is the directory where xplanet is installed.");
                        String pathXPlanet = MainFrame.getXPLANET_EXECUTABLE();
                        if (pathXPlanet != null && !"".equals(pathXPlanet)) {
                            File fileXPlanet = new File(pathXPlanet);
                            File dirXPlanet = fileXPlanet.getParentFile();
                            if (dirXPlanet == null) {
                                this.logger.finer("Parent of '" + pathXPlanet + "' is null. Can not prepend an absolute path to the directory '" + dir + "'.");
                                dir = null;
                                continue;
                            }
                            if (dirXPlanet.exists()) {
                                String dirXPlanetPath = dirXPlanet.getAbsolutePath();
                                dir = dirXPlanetPath + File.separator + dir;
                                this.logger.finer("Prepended directory of xplanet executable. Directory is now '" + dir + "'.");
                            }
                        } else {
                            this.logger.finer("Path to xplanet executable is not set in the GUI. Can not prepend an absolute path to the directory '" + dir + "'.");
                            dir = null;
                            continue;
                        }
                    }
                }
                d = new File(dir);
                File parentDir = d.getParentFile();
                if (p == null) {
                    dir = null;
                    this.logger.finer("'" + dir + "' is has not parent dirctory. Continue to next search result if any...");
                    continue;
                }
                boolean mustMakeDirectory = false;
                if (!parentDir.exists()) {
                    mustMakeDirectory = true;
                } else {
                    if (!parentDir.isDirectory()) {
                        mustMakeDirectory = true;
                    }
                }
                if (mustMakeDirectory) {
                    // Try to make the directory because the user wants to
                    // write the config files and ressources to it.
                    boolean success = parentDir.mkdirs();
                    if (!success) {
                        this.logger.finer("Failed to make directory '" + parentDir.getAbsolutePath() + "'. Check the name of the directory. Migth be 'xplanet'.");
                        String dirName = parentDir.getName();
                        if(dirName.equalsIgnoreCase("xplanet")) {
                            this.logger.finer("Yes, the directory name was 'xplanet'. Try to find and/or make subdirectory 'config'. Probably Linux? There is some work to to for the programmer.");
//                            String subdir = dirName + File.separator + "config";
//                            File fSubdir = new File(subdir);
//                            if(fSubdir.exists() && fSubdir.isDirectory()) {
//                                this.logger.finer("Yes, found subdir '" + subdir + "'.");
//                            }
                        }
                        this.logger.finer("Failed to make directory '" + parentDir.getAbsolutePath() + "'. Continue to next search result if any...");
                        dir = null;
                        continue;
                    }
                    this.logger.info("Made directory '" + parentDir.getAbsolutePath() + "'.");
                }
                dir = parentDir.getAbsolutePath();
                // Can the user write to the directory?
                if (this.canWriteToDir(dir)) {
                    this.logger.fine("Found a directory XPlanet uses for ressources and the configurator can write to.");
                    break;
                } else {
                    dir = null;
                    this.logger.fine("Found a directory of an XPlanet test output but can not write a file to it. Continue....");

                }
            } else {
                this.logger.finer("Found no directory (as 2nd group) in " + m.group());
            }
        }
        if (dir == null) {
            this.logger.finer("No directory that was tested for XPlanet was found from the output of XPlanet.");
            this.setXPlanetDirTested("");
            this.setXPlanetDirUsed("");
        } else {
            this.setXPlanetDirTested(dir);
            this.setXPlanetDirUsed(dir);
            this.logger.fine("Found and set the tested xplanet directoy to '" + dir + "'.");
        }
        return dir;
    }

    /**
     * This directory will be used first to seach for the ressources
     * @param dir
     */
    public void setXPlanetDirTested(String dir) {
        OwnPreferences prefs = OwnPreferences.userNodeForPackage(this.getClass());
        if (dir != null) {
            prefs.put(KEY_XPLANET_DIR_TESTED, dir);
            System.setProperty(KEY_XPLANET_DIR_TESTED, dir);
            this.logger.finer("Set the tested xplanet directoy to '" + dir + "'.");
        } else {
            prefs.put(KEY_XPLANET_DIR_TESTED, "");
            PropertiesReader pr = new PropertiesReader();
            pr.removeSystemPropertyStartingWith(KEY_XPLANET_DIR_TESTED);
            this.logger.finer("Reset/Remove the key '" + KEY_XPLANET_DIR_TESTED + "' in system properties and user preferences.");
        }
    }

    /**
     * This directory will be used first to seach for the ressources
     * @param dir null will reset/remove the key in system properties and user preferences.
     */
    public void setXPlanetDirUsed(String dir) {
        OwnPreferences prefs = OwnPreferences.userNodeForPackage(this.getClass());
        if (dir != null) {
            prefs.put(KEY_XPLANET_DIR_USED, dir);
            System.setProperty(KEY_XPLANET_DIR_USED, dir);
            this.logger.finer("Set the used xplanet directoy to '" + dir + "' in system properties and user preferences.");
        } else {
            prefs.put(KEY_XPLANET_DIR_USED, "");
            PropertiesReader pr = new PropertiesReader();
            pr.removeSystemPropertyStartingWith(KEY_XPLANET_DIR_USED);
            this.logger.finer("Reset/Remove the key '" + KEY_XPLANET_DIR_USED + "' in system properties and user preferences.");
        }
    }

    /**
     * Set the absolute path to the executable of xplanet.
     * @param absolutePath to the xplanet executable
     */
    public void setPathToXPlanetExecutable(String absolutePath) {
        // Check null
        if (absolutePath != null && !"".equals(absolutePath)) {
        } else {
            this.logger.finer("Absolute path '" + absolutePath + "' to the executable was empty. Returning...");
            return;
        }
        // Check wether the user can execute the file
        File f = new File(absolutePath);
        if (!f.canExecute()) {
            this.logger.finer("The user can not execute the xplanet executable '" + absolutePath + "'. Returning...");
            return;
        }
        MainFrame.setXPLANET_EXECUTABLE(absolutePath);
    }

    /**
     * Get the preview image.
     *
     * @return the absolute path of the image used for the preview. It is
     * {root-directory-for-downloads}/preview/preview.jpg
     */
    public String getPreviewImage() {
        String previewDir = this.getRessourceDirectory("preview");
        String imagePath = previewDir + File.separator + "preview.jpg";
        return imagePath;
    }
}
TOP

Related Classes of xplanetconfigurator.util.XPlanetRessourceFinder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.