package com.redhat.ceylon.compiler.java.runtime.model;

import java.util.Collections;
import java.util.List;

import com.redhat.ceylon.cmr.api.ArtifactResult;
import com.redhat.ceylon.compiler.loader.AbstractModelLoader;
import com.redhat.ceylon.compiler.loader.impl.reflect.model.ReflectionModule;
import com.redhat.ceylon.compiler.loader.impl.reflect.model.ReflectionModuleManager;
import com.redhat.ceylon.compiler.loader.model.LazyModule;
import com.redhat.ceylon.compiler.loader.model.LazyPackage;
import com.redhat.ceylon.compiler.typechecker.analyzer.ModuleManager;
import com.redhat.ceylon.compiler.typechecker.context.Context;
import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.model.ModuleImport;
import com.redhat.ceylon.compiler.typechecker.model.Modules;
import com.redhat.ceylon.compiler.typechecker.model.Package;
import com.redhat.ceylon.compiler.typechecker.model.Unit;

public class RuntimeModuleManager extends ReflectionModuleManager {

    public RuntimeModuleManager(Context context) {
        super(context);
    }

    @Override
    protected boolean isModuleLoadedFromSource(String moduleName) {
        return false;
    }
    
    @Override
    protected AbstractModelLoader createModelLoader(Modules modules) {
        return new RuntimeModelLoader(this, modules);
    }

    @Override
    protected Package createPackage(String pkgName, Module module) {
        final Package pkg = new LazyPackage(getModelLoader());
        List<String> name = pkgName.isEmpty() ? Collections.<String>emptyList() : splitModuleName(pkgName); 
        pkg.setName(name);
        if (module != null) {
            module.getPackages().add(pkg);
            pkg.setModule(module);
        }
        return pkg;
    }

    @Override
    protected Module createModule(List<String> moduleName, String version) {
        Module module;
        module = new ReflectionModule(this);
        module.setName(moduleName);
        module.setVersion(version);
        if(module instanceof ReflectionModule)
            setupIfJDKModule((LazyModule) module);
        return module;
    }

    public void loadModule(String name, String version, ArtifactResult artifact, ClassLoader classLoader) {
        Module module = getOrCreateModule(splitModuleName(name), version);
        RuntimeModelLoader modelLoader = getModelLoader();
        modelLoader.addModuleToClassPath(module, artifact);
        modelLoader.addModuleClassLoader(module, classLoader);
        module.setAvailable(true);
        Unit u = new Unit();
        u.setFilename(artifact.name());
        if(artifact.artifact() != null)
            u.setFullPath(artifact.artifact().getAbsolutePath());
        module.setUnit(u);
        
        if(!module.isDefault()){
            // FIXME: dependencies of Ceylon modules?
            if(!modelLoader.loadCompiledModule(module)){
                // we didn't find module.class so it must be a java module if it's not the default module
                ((LazyModule)module).setJava(true);

                // Java modules must have their dependencies set by the artifact result, as there is no module info in the jar
                for (ArtifactResult dep : artifact.dependencies()) {
                    Module dependency = getOrCreateModule(ModuleManager.splitModuleName(dep.name()), dep.version());

                    ModuleImport depImport = findImport(module, dependency);
                    if (depImport == null) {
                        ModuleImport moduleImport = new ModuleImport(dependency, false, false);
                        module.addImport(moduleImport);
                    }
                }
            }
        }
    }
    
    @Override
    public RuntimeModelLoader getModelLoader() {
        return (RuntimeModelLoader) super.getModelLoader();
    }
    
    public Module findModuleForClass(java.lang.Class<?> klass){
        return getModelLoader().findModuleForClass(klass);
    }
}

@@ -2242,32 +2242,140 @@
 ader) %7B%0A        
+RuntimeModelLoader modelLoader = getModelLoader();%0A        synchronized(modelLoader.getLock())%7B%0A            
 Module module = 
@@ -2433,63 +2433,8 @@
     
-    RuntimeModelLoader modelLoader = getModelLoader();%0A
     
@@ -2489,32 +2489,36 @@
 ifact);%0A        
+    
 modelLoader.addM
@@ -2556,16 +2556,20 @@
 oader);%0A
+    
         
@@ -2603,16 +2603,20 @@
         
+    
 Unit u =
@@ -2624,24 +2624,28 @@
 new Unit();%0A
+    
         u.se
@@ -2680,16 +2680,20 @@
         
+    
 if(artif
@@ -2716,16 +2716,20 @@
 = null)%0A
+    
         
@@ -2786,32 +2786,36 @@
 ath());%0A        
+    
 module.setUnit(u
@@ -2821,17 +2821,13 @@
 u);%0A
-    
+%0A
     
-%0A
     
@@ -2851,24 +2851,28 @@
 Default())%7B%0A
+    
             
@@ -2921,24 +2921,28 @@
             
+  
+  
 if(!modelLoa
@@ -2970,24 +2970,28 @@
 e(module))%7B%0A
+    
             
@@ -3100,16 +3100,20 @@
         
+  
+  
 ((LazyMo
@@ -3137,24 +3137,28 @@
 ava(true);%0A%0A
+    
             
@@ -3288,16 +3288,20 @@
         
+  
+  
 for (Art
@@ -3341,24 +3341,28 @@
 encies()) %7B%0A
+    
             
@@ -3479,32 +3479,36 @@
                 
+  
+  
 ModuleImport dep
@@ -3564,24 +3564,28 @@
             
+    
 if (depImpor
@@ -3613,32 +3613,36 @@
                 
+  
+  
 ModuleImport mod
@@ -3717,24 +3717,28 @@
             
+    
 module.addIm
@@ -3753,24 +3753,50 @@
 uleImport);%0A
+                        %7D%0A
             

synchronise #347