package com.redhat.ceylon.compiler.typechecker.model;

import static com.redhat.ceylon.compiler.typechecker.model.Util.isNameMatching;
import static com.redhat.ceylon.compiler.typechecker.model.Util.isResolvable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class Module {

    public static final String DEFAULT_MODULE_NAME = "default";

    private List<String> name;
    private String version;
    private List<Package> packages = new ArrayList<Package>();
    private List<ModuleImport> imports = new ArrayList<ModuleImport>();
    private Module languageModule;
    private boolean available;
    private String license;
    private String doc;
    private List<String> authors = new ArrayList<String>();
    private boolean isDefault;

    /**
     * Whether or not the module is available in the
     * source path or the repository
     */
    public boolean isAvailable() {
        return available;
    }

    public void setAvailable(boolean available) {
        this.available = available;
    }

    public List<String> getName() {
        return name;
    }

    public void setName(List<String> name) {
        this.name = name;
    }

    public List<Package> getPackages() {
        return packages;
    }

    public List<Package> getSharedPackages() {
        List<Package> list = new ArrayList<Package>();
        for (Package p: packages) {
        	if (p.isShared()) {
        		list.add(p);
        	}
        }
        return list;
    }

    public List<ModuleImport> getImports() {
        return imports;
    }
    
    public Module getLanguageModule() {
        return languageModule;
    }
    
    public void setLanguageModule(Module languageModule) {
        this.languageModule = languageModule;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public List<Package> getAllPackages() {
        List<Package> list = new ArrayList<Package>();
        list.addAll(packages);
        for (ModuleImport mi: imports) {
            list.addAll(mi.getModule().getSharedPackages());
        }
        return list;
    }
    
    public Map<String, DeclarationWithProximity> getAvailableDeclarations(String startingWith, int proximity) {
    	Map<String, DeclarationWithProximity> result = new TreeMap<String, DeclarationWithProximity>();
    	for (Package p: getAllPackages()) {
    		String moduleName = p.getModule().getNameAsString();
			if (!moduleName.startsWith("java") &&
    				!moduleName.startsWith("ceylon.language") &&
    				!p.getNameAsString().isEmpty()) {
    			for (Declaration d: p.getMembers()) {
    				try {
    					if (isResolvable(d) && d.isShared() && isNameMatching(startingWith, d)) {
    						result.put(d.getQualifiedNameString(), 
    								new DeclarationWithProximity(d, proximity, true));
    					}
    				}
    				catch (Exception e) {}
    			}
    		}
        }
        return result;
    }

    List<Package> getAllKnownPackages() {
        List<Package> list = new ArrayList<Package>();
        list.addAll(packages);
        for (ModuleImport mi: imports) {
            list.addAll(mi.getModule().getPackages());
        }
        return list;
    }

    public Package getDirectPackage(String name) {
        for (Package pkg: packages) {
            if ( pkg.getQualifiedNameString().equals(name) ) {
                return pkg;
            }
        }
        return null;
    }
    
    public Package getPackage(String name) {
        Package pkg = getDirectPackage(name);
        if(pkg != null)
            return pkg;
        for (ModuleImport mi: imports) {
            pkg = mi.getModule().getDirectPackage(name);
            if(pkg != null)
                return pkg;
        }
        return null;
    }
    
    public String getNameAsString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < name.size(); i++) {
            sb.append(name.get(i));
            if (i < name.size() - 1) {
                sb.append('.');
            }
        }
        return sb.toString();
    }

    @Override
    public String toString() {
        return "Module[" + getNameAsString() + ", " + getVersion() + "]";
    }
    
    public String getDoc() {
        return doc;
    }
    
    public void setDoc(String doc) {
        this.doc = doc;
    }
    
    public String getLicense() {
        return license;
    }
    
    public void setLicense(String license) {
        this.license = license;
    }
    
    public List<String> getAuthors() {
		return authors;
	}

    /**
     * Is this the default module hosting all units outside of an explicit module
     */
    public boolean isDefault() {
        return isDefault;
    }

    public void setDefault(boolean isDefault) {
        this.isDefault = isDefault;
    }
    
    public boolean isJava() {
        return false;
    }
    
}

@@ -2536,13 +2536,24 @@
 %0A%09%09%09
-if (!
+boolean isJdk = 
 modu
@@ -2577,29 +2577,48 @@
 (%22java%22)
- &&%0A    %09%09%09%09!
+;%0A%09%09%09boolean isLanguageModule = 
 moduleNa
@@ -2620,26 +2620,22 @@
 uleName.
-startsWith
+equals
 (%22ceylon
@@ -2649,53 +2649,280 @@
 ge%22)
- &&%0A    %09%09%09%09!p.getNameAsString().isEmpty()) %7B
+;%0A%09%09%09boolean isDefaultPackage = p.getNameAsString().isEmpty();%0A%09%09%09if ((!isJdk%7C%7CstartingWith.length()%3E1) && !isDefaultPackage) %7B%0A%09%09%09%09int prox;%0A%09%09%09%09if (isJdk) %7B%0A%09%09%09%09%09prox=200;%0A%09%09%09%09%7D%0A%09%09%09%09else if (isLanguageModule) %7B%0A%09%09%09%09%09prox=100; %0A%09%09%09%09%7D%0A%09%09%09%09else %7B%0A%09%09%09%09%09prox=proximity;%0A%09%09%09%09%7D
 %0A   
@@ -3025,16 +3025,28 @@
 ed() && 
+%0A    %09%09%09%09%09%09%09
 isNameMa
@@ -3170,21 +3170,16 @@
 (d, prox
-imity
 , true))

return langauge module and jdk matches