package org.metaborg.spoofax.eclipse.processing;

import java.util.Set;

import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.PlatformUI;
import org.metaborg.spoofax.core.language.ILanguageCache;
import org.metaborg.spoofax.core.language.ILanguageDiscoveryService;
import org.metaborg.spoofax.core.language.ILanguageIdentifierService;
import org.metaborg.spoofax.core.language.ILanguageService;
import org.metaborg.spoofax.core.language.LanguageChange;
import org.metaborg.spoofax.eclipse.editor.ISpoofaxEditorListener;
import org.metaborg.spoofax.eclipse.job.GlobalSchedulingRules;
import org.metaborg.spoofax.eclipse.language.LanguageAddedJob;
import org.metaborg.spoofax.eclipse.language.LanguageInvalidatedJob;
import org.metaborg.spoofax.eclipse.language.LanguageReloadedActiveJob;
import org.metaborg.spoofax.eclipse.language.LanguageRemovedJob;
import org.metaborg.spoofax.eclipse.resource.IEclipseResourceService;

import rx.functions.Action1;

import com.google.inject.Inject;

public class Processor {
    // private static final Logger logger = LoggerFactory.getLogger(Processor.class);

    private final IEclipseResourceService resourceService;
    private final ILanguageService languageService;
    private final ILanguageIdentifierService languageIdentifierService;
    private final ILanguageDiscoveryService languageDiscoveryService;
    private final Set<ILanguageCache> languageCaches;

    private final ISpoofaxEditorListener spoofaxEditorListener;
    private final GlobalSchedulingRules globalRules;

    private final IWorkspace workspace;
    private final IEditorRegistry editorRegistry;


    @Inject public Processor(IEclipseResourceService resourceService, ILanguageService languageService,
        ILanguageIdentifierService languageIdentifierService, ILanguageDiscoveryService languageDiscoveryService,
        Set<ILanguageCache> languageCaches, ISpoofaxEditorListener spoofaxEditorListener,
        GlobalSchedulingRules globalRules) {
        this.resourceService = resourceService;
        this.languageService = languageService;
        this.languageIdentifierService = languageIdentifierService;
        this.languageDiscoveryService = languageDiscoveryService;
        this.languageCaches = languageCaches;

        this.spoofaxEditorListener = spoofaxEditorListener;
        this.globalRules = globalRules;

        this.workspace = ResourcesPlugin.getWorkspace();
        this.editorRegistry = PlatformUI.getWorkbench().getEditorRegistry();

        this.languageService.changes().subscribe(new Action1<LanguageChange>() {
            @Override public void call(LanguageChange change) {
                languageChange(change);
            }
        });
    }

    public void startup() {
        final Job job = new StartupJob(resourceService, languageDiscoveryService);
        job.setRule(new MultiRule(new ISchedulingRule[] { globalRules.startupWriteLock(),
            globalRules.languageServiceLock() }));
        job.schedule();
    }

    // public void projectOpen(IProject project) {
    // // TODO: Check if there is a language inside this project, if so, load it.
    // }
    //
    // public void projectClose(IProject project) {
    // // TODO: Check if there is a loaded language inside this project, if so, unload it.
    // // TODO: Cancel all build jobs in this project.
    // // TODO: Cancel all update jobs in this project, this may happen automatically because all
    // // editors inside this project will be closed when the project is closed.
    // }


    private void languageChange(LanguageChange change) {
        final Job changeJob;
        switch(change.kind) {
            case ADD_FIRST:
                changeJob = new LanguageAddedJob(spoofaxEditorListener, editorRegistry, change.newLanguage);
                break;
            case REPLACE_ACTIVE:
            case RELOAD_ACTIVE:
                changeJob =
                    new LanguageReloadedActiveJob(languageCaches, spoofaxEditorListener, editorRegistry,
                        change.oldLanguage, change.newLanguage);
                break;
            case RELOAD:
            case REMOVE:
                changeJob = new LanguageInvalidatedJob(languageCaches, change.oldLanguage);
                break;
            case REMOVE_LAST:
                changeJob =
                    new LanguageRemovedJob(resourceService, languageIdentifierService, spoofaxEditorListener,
                        editorRegistry, workspace, change.oldLanguage);
                break;
            default:
                changeJob = null;
                break;
        }

        if(changeJob == null) {
            return;
        }

        changeJob.setRule(workspace.getRoot());
        changeJob.schedule();
    }
}

@@ -1511,31 +1511,24 @@
 geIdentifier
-Service
 ;%0A    privat
@@ -1679,32 +1679,25 @@
 torListener 
-spoofaxE
+e
 ditorListene
@@ -2325,23 +2325,16 @@
 entifier
-Service
  = langu
@@ -2481,24 +2481,17 @@
    this.
-spoofaxE
+e
 ditorLis
@@ -3083,16 +3083,37 @@
 Rule%5B%5D %7B
+ workspace.getRoot(),
  globalR
@@ -3223,544 +3223,8 @@
  %7D%0A%0A
-    // public void projectOpen(IProject project) %7B%0A    // // TODO: Check if there is a language inside this project, if so, load it.%0A    // %7D%0A    //%0A    // public void projectClose(IProject project) %7B%0A    // // TODO: Check if there is a loaded language inside this project, if so, unload it.%0A    // // TODO: Cancel all build jobs in this project.%0A    // // TODO: Cancel all update jobs in this project, this may happen automatically because all%0A    // // editors inside this project will be closed when the project is closed.%0A    // %7D%0A%0A
 %0A   
@@ -3295,23 +3295,17 @@
 nal Job 
-changeJ
+j
 ob;%0A    
@@ -3366,39 +3366,33 @@
                 
-changeJ
+j
 ob = new Languag
@@ -3401,24 +3401,17 @@
 ddedJob(
-spoofaxE
+e
 ditorLis
@@ -3550,39 +3550,33 @@
                 
-changeJ
+j
 ob =%0A           
@@ -3630,24 +3630,17 @@
 Caches, 
-spoofaxE
+e
 ditorLis
@@ -3661,16 +3661,36 @@
 egistry,
+ change.oldLanguage,
 %0A       
@@ -3705,36 +3705,16 @@
         
- change.oldLanguage,
  change.
@@ -3812,31 +3812,25 @@
             
-changeJ
+j
 ob = new Lan
@@ -3951,31 +3951,25 @@
             
-changeJ
+j
 ob =%0A       
@@ -4043,38 +4043,40 @@
 fier
-Service, spoofaxEditorListener
+, editorListener, editorRegistry
 ,%0A  
@@ -4096,32 +4096,16 @@
         
- 
-editorRegistry,
  workspa
@@ -4189,23 +4189,17 @@
         
-changeJ
+j
 ob = nul
@@ -4246,23 +4246,17 @@
      if(
-changeJ
+j
 ob == nu
@@ -4296,31 +4296,25 @@
  %7D%0A%0A        
-changeJ
+j
 ob.setRule(w
@@ -4316,45 +4316,158 @@
 ule(
-workspace.getRoot());%0A        changeJ
+new MultiRule(new ISchedulingRule%5B%5D %7B workspace.getRoot(), globalRules.startupReadLock(),%0A            globalRules.languageServiceLock() %7D));%0A        j
 ob.s

Make sure that project builds don't run concurrently with the startup job. Cleanup.