package com.redhat.ceylon.compiler.loader;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.junit.After;
import org.junit.Assert;
import org.junit.Test;

import util.ModelUtils;

import com.redhat.ceylon.cmr.api.RepositoryManager;
import com.redhat.ceylon.cmr.ceylon.CeylonUtils;
import com.redhat.ceylon.cmr.impl.JSUtils;
import com.redhat.ceylon.compiler.Options;
import com.redhat.ceylon.compiler.js.JsCompiler;
import com.redhat.ceylon.compiler.typechecker.TypeChecker;
import com.redhat.ceylon.compiler.typechecker.TypeCheckerBuilder;
import com.redhat.ceylon.compiler.typechecker.model.Method;
import com.redhat.ceylon.compiler.typechecker.model.SiteVariance;

public class TestSiteVariance {

    private Options options(String srcdir) {
        return new Options().outDir("modules").addRepo("vartests").addRepo("build/runtime")
                .optimize(true).generateSourceArchive(false)
                .addSrc(srcdir);
    }

    private TypeChecker typeChecker(Options opts) {
        final RepositoryManager repoman = CeylonUtils.repoManager()
                .userRepos(opts.getRepos())
                .outRepo(opts.getOutDir())
                .buildManager();
        final TypeCheckerBuilder builder = new TypeCheckerBuilder()
            .moduleManagerFactory(new JsModuleManagerFactory("UTF-8"));
        for (String sd : opts.getSrcDirs()) {
            builder.addSrcDirectory(new File(sd));
        }
        builder.setRepositoryManager(repoman);
        final TypeChecker tc = builder.getTypeChecker();
        JsModuleManagerFactory.setVerbose(true);
        tc.process();
        return tc;
    }

    @Test @SuppressWarnings("unchecked")
    public void testSiteVariance() throws IOException {
        //Typecheck
        Options opts = options("src/test/resources/variance/phase1");
        TypeChecker tc = typeChecker(opts);
        //Compile
        JsCompiler jsc = new JsCompiler(tc, opts);
        jsc.generate();
        Map<String, Object> model = JSUtils.readJsonModel(new File("modules/phase1/0.1/phase1-0.1-model.js"));
        Assert.assertNotNull("Model not found", model);
        model = (Map<String,Object>)model.get("phase1");
        Assert.assertNotNull("Default package not found", model);
        model = (Map<String,Object>)model.get("m2");
        Assert.assertNotNull("Method m2 not found", model);
        Map<String,Object> type = (Map<String,Object>)model.get(MetamodelGenerator.KEY_TYPE);
        List<Map<String,Object>> targs = (List<Map<String,Object>>)type.get(MetamodelGenerator.KEY_TYPE_PARAMS);
        type = targs.get(0);
        List<List<Map<String,Object>>> paramLists = (List<List<Map<String,Object>>>)model.get(MetamodelGenerator.KEY_PARAMS);
        Map<String,Object> parm = paramLists.get(0).get(0);
        parm = (Map<String,Object>)parm.get(MetamodelGenerator.KEY_TYPE);
        targs = (List<Map<String,Object>>)parm.get(MetamodelGenerator.KEY_TYPE_PARAMS);
        parm = targs.get(0);
        Assert.assertEquals(SiteVariance.OUT.ordinal(), type.get(MetamodelGenerator.KEY_US_VARIANCE));
        Assert.assertEquals(SiteVariance.IN.ordinal(), parm.get(MetamodelGenerator.KEY_US_VARIANCE));

        //Typecheck phase2
        final File repo2 = new File("vartests/phase1");
        repo2.mkdirs();
        new File("modules/phase1").renameTo(repo2);
        opts = options("src/test/resources/variance/phase2");
        tc = typeChecker(opts);
        Method m2 = (Method)tc.getPhasedUnits().getPhasedUnits().get(0).getPackage().getModule().getPackage("phase1").getDirectMember("m2", null, false);
        Assert.assertNotNull("phase1::m2 missing", m2);
        Assert.assertFalse("Missing variance overrides in return type",
                m2.getType().getVarianceOverrides().isEmpty());
        Assert.assertFalse("Missing variance overrides in parameter",
                m2.getParameterLists().get(0).getParameters().get(0).getType()
                    .getVarianceOverrides().isEmpty());
        jsc = new JsCompiler(tc, opts);
        jsc.generate();
        Assert.assertTrue("Should compile without errors", jsc.getErrors().isEmpty());
    }

    @After
    public void cleanup() {
        ModelUtils.deleteRecursively(new File("vartests"));
        ModelUtils.deleteRecursively(new File("modules"));
    }

}

@@ -856,28 +856,8 @@
 po(%22
-vartests%22).addRepo(%22
 buil
@@ -3234,140 +3234,8 @@
 se2%0A
-        final File repo2 = new File(%22vartests/phase1%22);%0A        repo2.mkdirs();%0A        new File(%22modules/phase1%22).renameTo(repo2);%0A
     
@@ -4076,68 +4076,8 @@
 ) %7B%0A
-        ModelUtils.deleteRecursively(new File(%22vartests%22));%0A
     

don't overcomplicate things