/* JFox, the OpenSource J2EE Application Server
 *
 * Distributable under GNU LGPL license by gun.org
 * more details please visit http://www.huihoo.org/jfox
 */
package org.jfox.framework.deploy;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import org.jfox.framework.loader.ClassLoaderRepository;
import org.jfox.framework.loader.LocalClassLoader;
import org.jfox.framework.logger.Logger;
import org.jfox.framework.util.FileFilters;
import org.jfox.framework.util.Files;
import org.jfox.framework.util.XmlUtils;

/**
 * a module directory
 *
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class Module implements Deployable, Comparable {
    private File moduleDir;
    private LocalClassLoader moduleClassLoader;
    private ClassLoaderRepository loaderRepo;
    private ModuleDescriptor moduleDescriptor;

    private Logger logger;

    public Module(File moduleDir, ClassLoaderRepository loaderRespo) throws ComponentDescriptionException {
        this.moduleDir = moduleDir;
        this.loaderRepo = loaderRespo;
        logger = Logger.getLogger(this.getClass().getName() + "[" + moduleDir.getName() + "]");
        init();
    }

    public File getModuleFile() {
        return moduleDir;
    }

    public void deploy(Deployer deployer) throws DeployException {
        deployer.deploy(this);
    }

    public File getTempDeployDirectory() {
        return moduleDir;
    }

    public void init() throws ComponentDescriptionException {
        try {
            moduleDescriptor = new ModuleDescriptor(XmlUtils.getDocument(getDescriptorURL()));
        }
        catch(Exception e) {
            throw new ComponentDescriptionException("build module descriptor failed.", e);
        }

        // add component jars to Common loader
        File[] componentJars = getComponentJars();
        List urls = new ArrayList(componentJars.length + 1);
        try {
            // add the classes dir to pub class path
            File classesDir = new File(moduleDir, "classes");
            if(classesDir.exists() && classesDir.isDirectory()) {
                urls.add(classesDir.toURL());
                logger.debug("add component classes directory to module's public ClassLoader " + classesDir.toString());
            }
            for(int i = 0; i < componentJars.length; i++) {
                urls.add(componentJars[i].toURL());
                logger.debug("add component jar to module's public ClassLoader " + componentJars[i].toString());
            }
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        // constructor's urls is the module's pub jars
        moduleClassLoader = new LocalClassLoader((URL[]) urls.toArray(new URL[urls.size()]), loaderRepo);

        // add component lib jars to module private loader
        File[] libJars = getComponentLibJars();
        try {
            for(int i = 0; i < libJars.length; i++) {
                moduleClassLoader.addURL(libJars[i].toURL());
                logger.debug("add component lib to module's private ClassLoader " + libJars[i].toString());
            }
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    public URL getDescriptorURL() {
        try {
            return new File(moduleDir, "META-INF/module.xml").toURL();
        }
        catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public URLClassLoader getClassLoader() {
        return moduleClassLoader;
    }

    public ModuleDescriptor getModuleDescriptor() {
        return moduleDescriptor;
    }

    public File[] getComponentJars() {
        return moduleDir.listFiles(FileFilters.suffixFileFilter(new String[]{"jar", "zip"}));
    }

    private File[] getComponentLibJars() {
        File lib = new File(moduleDir, "lib");
        if(!lib.exists()) return new File[0];
        List files = Files.listFiles(lib, FileFilters.suffixFileFilter(new String[]{"jar", "zip"}));
        return (File[]) files.toArray(new File[files.size()]);
    }

    public int compareTo(Object o) {
        Module _module = (Module) o;
        return new Integer(moduleDescriptor.getPriority()).compareTo(new Integer(_module.getModuleDescriptor().getPriority()));
    }

    public boolean equals(Object obj) {
        return moduleDir.getName().equals(((Module) obj).moduleDir.getName());
    }

    public int hashCode() {
        return moduleDir.getName().toString().hashCode();
    }

    public String toString() {
        return "Module{" +
                "moduleDir=" + moduleDir +
                ", description=" + moduleDescriptor.getDescription() +
                "}";
    }

    public static void main(String[] args) {

    }
}

