package org.CG.infrastructure;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.net.www.protocol.file.FileURLConnection;

/**
 *
 * @author ldavid
 */
public class DrawingsLoader {

    static final String drawingPackages = "org.CG.drawings";

    /**
     * Private helper method
     *
     * @param directory The directory to start with
     * @param pckgname The package name to search for. Will be needed for
     * getting the Class object.
     * @param classes if a file isn't loaded but still is in the directory
     * @throws ClassNotFoundException
     */
    private static void checkDirectory(File directory, String pckgname,
        List<Class<?>> classes) throws ClassNotFoundException {
        File tmpDirectory;

        if (directory.exists() && directory.isDirectory()) {
            final String[] files = directory.list();

            for (final String file : files) {
                if (file.endsWith(".class")) {
                    try {
                        classes.add(Class.forName(pckgname + '.'
                            + file.substring(0, file.length() - 6)));
                    } catch (final NoClassDefFoundError e) {
                        // do nothing. this class hasn't been found by the
                        // loader, and we don't care.
                    }
                } else if ((tmpDirectory = new File(directory, file))
                    .isDirectory()) {
                    checkDirectory(tmpDirectory, pckgname + "." + file, classes);
                }
            }
        }
    }

    /**
     * Private helper method.
     *
     * @param connection the connection to the jar
     * @param pckgname the package name to search for
     * @param classes the current ArrayList of all classes. This method will
     * simply add new classes.
     * @throws ClassNotFoundException if a file isn't loaded but still is in the
     * jar file
     * @throws IOException if it can't correctly read from the jar file.
     */
    private static void checkJarFile(JarURLConnection connection,
        String pckgname, List<Class<?>> classes)
        throws ClassNotFoundException, IOException {
        final JarFile jarFile = connection.getJarFile();
        final Enumeration<JarEntry> entries = jarFile.entries();
        String name;

        for (JarEntry jarEntry = null; entries.hasMoreElements()
            && ((jarEntry = entries.nextElement()) != null);) {
            name = jarEntry.getName();

            if (name.contains(".class")) {
                name = name.substring(0, name.length() - 6).replace('/', '.');

                if (name.contains(pckgname)) {
                    classes.add(Class.forName(name));
                }
            }
        }
    }

    /**
     * Attempts to list all the classes in the specified package as determined
     * by the context class loader
     *
     * @param pckgname the package name to search
     * @return a list of classes that exist within that package
     * @throws ClassNotFoundException if something went wrong
     */
    public static List<Class<?>> getClassesForPackage(String pckgname)
        throws ClassNotFoundException {
        final List<Class<?>> classes = new LinkedList<>();

        try {
            final ClassLoader cld = Thread.currentThread()
                .getContextClassLoader();

            if (cld == null) {
                throw new ClassNotFoundException("Can't get class loader.");
            }

            final Enumeration<URL> resources = cld.getResources(pckgname
                .replace('.', '/'));
            URLConnection connection;

            for (URL url = null; resources.hasMoreElements()
                && ((url = resources.nextElement()) != null);) {
                try {
                    connection = url.openConnection();

                    if (connection instanceof JarURLConnection) {
                        checkJarFile((JarURLConnection) connection, pckgname,
                            classes);
                    } else if (connection instanceof FileURLConnection) {
                        try {
                            checkDirectory(
                                new File(URLDecoder.decode(url.getPath(),
                                        "UTF-8")), pckgname, classes);
                        } catch (final UnsupportedEncodingException ex) {
                            throw new ClassNotFoundException(
                                pckgname
                                + " does not appear to be a valid package (Unsupported encoding)",
                                ex);
                        }
                    } else {
                        throw new ClassNotFoundException(pckgname + " ("
                            + url.getPath()
                            + ") does not appear to be a valid package");
                    }
                } catch (final IOException ioex) {
                    throw new ClassNotFoundException(
                        "IOException was thrown when trying to get all resources for "
                        + pckgname, ioex);
                }
            }
        } catch (final NullPointerException ex) {
            throw new ClassNotFoundException(
                pckgname
                + " does not appear to be a valid package (Null pointer exception)",
                ex);
        } catch (final IOException ioex) {
            throw new ClassNotFoundException(
                "IOException was thrown when trying to get all resources for "
                + pckgname, ioex);
        }

        return classes;
    }

    public static List<Class<? extends Drawing>> getDrawingsClasses() {
        List<Class<? extends Drawing>> drawings = new LinkedList<>();
        
        try {
            getClassesForPackage(drawingPackages).forEach(c -> {
                drawings.add(c.asSubclass(Drawing.class));
            });
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(DrawingsLoader.class.getName()).log(Level.SEVERE, null, ex);
        }

        return drawings;
    }
}

@@ -938,37 +938,39 @@
 n%0A     */%0A    pr
-ivate
+otected
  static void che
@@ -2368,21 +2368,23 @@
 /%0A    pr
-ivate
+otected
  static 
@@ -3432,29 +3432,32 @@
     */%0A    p
-ublic
+rotected
  static List

Fix DrawingsLoader methods visibility