"use strict";

var WebdriverIO = require('webdriverio/lib/webdriverio');
var MultiDevice = require('./multidevice');
var Flow = require('./flow'),
    Step = require('./step');
var path = require('path'),
    fs = require('fs');

var step = 0;

var flow = new Flow();

var remote = module.exports.remote = function remote(options, modifier, multiDevice) {

    options = options || {};

    let screenshotBlackList = {
        protocolQueries: ['element', 'elementActive', 'elementIdDisplayed', 'elementIdElement', 'elementIdElements', 'elementIdEnabled', 'elementIdLocation', 'elementIdLocationInView', 'elementIdName', 'elementIdSelected', 'elementIdSize', 'elementIdText', 'elements', 'windowHandle', 'windowHandles', 'title'],
        stateQueries: ['isEnabled', 'isExisting', 'isSelected', 'isVisible', 'isVisibleWithinViewport'],
        cookieCommands: ['deleteCookie', 'getCookie', 'setCookie', 'cookie'],
        elementPropertyQueries: ['getAttribute', 'getCssProperty', 'getElementSize', 'getHTML', 'getLocation', 'getLocationInView', 'getSource', 'getTagName', 'getText', 'getTitle', 'getUrl', 'getValue'],
        interferingCommands: ['init', 'end', 'endAll', 'session', 'sessions', 'saveScreenshot', 'screenshot'],
        otherCommandsWithoutSideEffects: ['timeouts', 'timeoutsAsyncScript', 'timeoutsImplicitWait', 'windowHandlePosition', 'getCommandHistory', 'getTabIds', 'getViewportSize']
    };
    // Merge all blacklists into one list
    screenshotBlackList = Object.keys(screenshotBlackList).map(key => screenshotBlackList[key]).reduce((previous, current) => previous.concat(current), []);


    /**
     * Initialise monad
     */
    var unit = WebdriverIO(options, modifier);
    /**
     * Add the webdriverIO commands
     * Build prototype: commands
     */
    ['protocol', 'commands'].forEach(function(commandType) {
        var dir = path.join(__dirname, '../node_modules/webdriverio', 'lib', commandType),
            files = fs.readdirSync(dir);

        files.forEach(function(filename) {
            let commandName = filename.slice(0, -3);
            let commandFunc = require(path.join(dir, filename));

            /**
             * Command proxy: Take a screenshot between commands
             * @returns {WebdriverIO.Client}
             */
            let proxyCommandFunc = function () {
                let globalStep = step;
                let deviceId = this.options.id;
                step += 1;

                //console.log(globalStep, deviceId, commandName);

                // Take a screenshot before each command
                // This does not override the original commands return value
                // TODO ensure last command is finished, use waitUntil?
                // TODO think about taking screenshots on all devices to capture side effects
                let intermediate = this.saveScreenshot(
                    function(err, screenshot, response) {
                        if (err) {
                            console.log(err);
                            throw new err;
                        }
                        var step = new Step(deviceId, globalStep, commandName, screenshot, this.options);

                        // TODO serialize and store the screenshots less often. This is probably a performance killer
                        flow.addStep(step)
                            //.store()
                        ;
                    }
                );

                // Execute function after the screenshot
                return commandFunc.apply(intermediate, arguments);
            };

            unit.lift(commandName,
                screenshotBlackList.indexOf(commandName) !== -1 ? commandFunc : proxyCommandFunc
            );
        });
    });

    /**
     * Add xdTesting commands
     */
    ['commands'].forEach(function (commandType) {
        var dir = path.join(__dirname, commandType),
            files = fs.readdirSync(dir);

        files.forEach(function (filename) {
            var commandName = filename.slice(0, -3); // remove .js suffix
            unit.lift(commandName, require(path.join(dir, filename))(multiDevice));
        });
    });

    var prototype = unit();
    prototype.defer.resolve();
    return prototype;
};

/**
 * @todo Lookup WebdriverIO jsdoc
 */
module.exports.multiremote = function multiremote(options) {
    // Add id key to options
    Object.keys(options).forEach(function (id) {
        options[id]['id'] = id;
    });

    var multiDevice = new MultiDevice(options);

    Object.keys(options).forEach(function(browserName) {
        multiDevice.addInstance(
            browserName,
            remote(options[browserName], multiDevice.getInstanceModifier(), multiDevice)
        );
    });

    var multiModifier = multiDevice.getModifier();
    return remote(options, multiModifier, multiDevice);
};

@@ -1692,24 +1692,25 @@
  modifier);%0A
+%0A
     /**%0A    
@@ -2349,106 +2349,496 @@
     
-let globalStep = step;%0A                let deviceId = this.options.id;%0A                step += 1;%0A
+// Default: no additional behaviour%0A                let intermediate = this;%0A%0A                if (commandName === 'end' %7C%7C commandName == 'endAll') %7B%0A                    // Serialize and store the steps and screenshots only at the end.%0A                    // Storing flows with large screenshots can take a while.%0A                    // TODO only rewrite file of cache is dirty%0A                    flow.store()%0A                %7D else if (screenshotBlackList.indexOf(commandName) === -1) %7B
 %0A   
@@ -2850,18 +2850,20 @@
         
-//
+    
 console.
@@ -2899,24 +2899,155 @@
 mandName);%0A%0A
+                    let globalStep = step;%0A                    let deviceId = this.options.id;%0A                    step += 1;%0A%0A    
             
@@ -3103,24 +3103,28 @@
             
+   
+ 
 // This does
@@ -3180,32 +3180,36 @@
                 
+    
 // TODO ensure l
@@ -3256,32 +3256,36 @@
                 
+  
+  
 // TODO think ab
@@ -3354,35 +3354,35 @@
                 
-let
+   
  intermediate = 
@@ -3405,37 +3405,16 @@
 hot(
-%0A                    
 function
 (err
@@ -3409,16 +3409,17 @@
 function
+ 
 (err, sc
@@ -3725,250 +3725,68 @@
     
-// TODO serialize and store the screenshots less often. This is probably a performance killer%0A                        flow.addStep(step)%0A                            //.store()%0A                        ;%0A                    %7D%0A                );
+flow.addStep(step)%0A                    %7D);%0A                %7D
 %0A%0A  
@@ -3829,26 +3829,28 @@
 ter the 
-screenshot
+intermediate
 %0A       
@@ -3922,17 +3922,16 @@
        %7D
-;
 %0A%0A      
@@ -3962,88 +3962,8 @@
 ame,
-%0A                screenshotBlackList.indexOf(commandName) !== -1 ? commandFunc :
  pro
@@ -3975,29 +3975,16 @@
 mandFunc
-%0A            
 );%0A     

Store flow when session ends