import Promise from 'promise';
import Bootstrapper from './bootstrapper';
import Task from './task';
import concatFlattened from '../utils/array-concat-flattened';

export default class Runner {
    constructor (proxy, browserConnectionGateway) {
        this.proxy        = proxy;
        this.bootstrapper = new Bootstrapper(browserConnectionGateway);

        this.opts = {
            screenshotPath:        null,
            takeScreenshotOnFails: false,
            failOnJsErrors:        true,
            quarantineMode:        false
        };
    }

    static _watchBrowserConnectionError (browserConnections, task) {
        var onError = msg => {
            task.terminate();
            task.removeAllListeners();
            Bootstrapper.freeBrowserConnections(browserConnections, onError);
            throw new Error(msg);
        };

        browserConnections.forEach(bc => bc.once('error', onError));

        return onError;
    }

    _runTask (reporter, browserConnections, tests) {
        var task           = new Task(tests, browserConnections, this.proxy, this.opts);
        var passed         = true;
        var bcErrorHandler = Runner._watchBrowserConnectionError(browserConnections, task);

        task.once('start', () => reporter.onTaskStart(task));

        task.on('test-run-done', testRun => {
            passed &= !testRun.errs.length;
            reporter.onTestRunDone(testRun);
        });

        return new Promise((resolve) => {
            task.once('done', () => {
                reporter.onTaskDone(task);
                Bootstrapper.freeBrowserConnections(browserConnections, bcErrorHandler);
                resolve(passed);
            });
        });
    }


    // API
    src (...src) {
        this.bootstrapper.src = concatFlattened(this.bootstrapper.src, src);

        return this;
    }

    browsers (...browsers) {
        this.bootstrapper.browsers = concatFlattened(this.bootstrapper.browsers, browsers);

        return this;
    }

    reporter (reporter, outStream = null) {
        this.bootstrapper.reporter        = reporter;
        this.bootstrapper.reportOutStream = outStream;

        return this;
    }

    filter (filter) {
        this.bootstrapper.filter = filter;

        return this;
    }

    screenshots (path, takeOnFails = false) {
        this.opts.takeScreenshotOnFails  = takeOnFails;
        this.bootstrapper.screenshotPath = path;

        return this;
    }

    async run ({ failOnJsErrors = true, quarantineMode = false }) {
        this.opts.failOnJsErrors = failOnJsErrors;
        this.opts.quarantineMode = quarantineMode;

        var { reporter, browserConnections, tests } = await this.bootstrapper.createRunnableConfiguration();

        return await this._runTask(reporter, browserConnections, tests);
    }
}

@@ -565,21 +565,20 @@
 static _
-watch
+free
 BrowserC
@@ -586,21 +586,17 @@
 nnection
-Error
+s
  (browse
@@ -613,76 +613,66 @@
 ns, 
-task) %7B%0A        var onError = msg =%3E %7B%0A            task.terminate();
+errorHandler) %7B%0A        browserConnections.forEach(bc =%3E %7B
 %0A   
@@ -684,30 +684,25 @@
     
-task
+bc
 .remove
-All
 Listener
 s();
@@ -701,13 +701,34 @@
 ener
-s
 (
+'error', errorHandler
 );%0A
+%0A
     
@@ -739,198 +739,194 @@
     
-Bootstrapper.freeBrowserConnections(browserConnections, onError);%0A            throw new Error(msg);%0A        %7D;%0A%0A        browserConnections.forEach(bc =%3E bc.once('error', onError)
+// NOTE: we should close local connections and %0A            // related browsers once we've done%0A            if (bc instanceof LocalBrowserConnection)%0A                bc.close(
 );%0A
-%0A
         
 retu
@@ -925,22 +925,10 @@
     
-return onError
+%7D)
 ;%0A  
@@ -981,24 +981,78 @@
 s, tests) %7B%0A
+        return new Promise((resolve, reject) =%3E %7B%0A    
         var 
@@ -1132,24 +1132,28 @@
 s);%0A        
+ 
+   
 var passed  
@@ -1171,24 +1171,28 @@
 ue;%0A        
+    
 var bcErrorH
@@ -1204,72 +1204,736 @@
 r = 
-Runner._watchBrowserConnectionError(browserConnections, task);%0A%0A
+msg =%3E %7B%0A                task.terminate();%0A                task.removeAllListeners();%0A                freeBrowserConnections();%0A                reject(new Error(msg));%0A            %7D;%0A            var freeBrowserConnections = () =%3E %7B%0A                browserConnections.forEach(bc =%3E %7B%0A                    bc.removeListener('error', bcErrorHandler);%0A                    %0A                    // NOTE: we should close local connections and %0A                    // related browsers once we've done%0A                    if (bc instanceof LocalBrowserConnection)%0A                        bc.close();%0A                %7D);%0A            %7D;%0A            %0A            browserConnections.forEach(bc =%3E bc.once('error', onError));%0A            %0A    
     
@@ -1995,24 +1995,28 @@
 );%0A%0A        
+   
+ 
 task.on('tes
@@ -2053,16 +2053,20 @@
         
+    
 passed &
@@ -2089,16 +2089,20 @@
 length;%0A
+    
         
@@ -2150,54 +2150,16 @@
     
+    
 %7D);%0A
-%0A        return new Promise((resolve) =%3E %7B
 %0A   
@@ -2256,21 +2256,8 @@
     
-Bootstrapper.
 free
@@ -2279,42 +2279,8 @@
 ons(
-browserConnections, bcErrorHandler
 );%0A 

Update index.js