/*
 * grunt-sauce-screenshots
 * https://github.com/cvrebert/grunt-sauce-screenshots
 *
 * Copyright (c) 2014 Chris Rebert
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path');

var colors = require('colors');
var wd = require('wd');

function filenameForBrowser(browserSpec) {
  var cleanVersion = (browserSpec.version === undefined ? '' : browserSpec.version);
  var filename = (browserSpec.browserName + '-' + browserSpec.platform + '-' + cleanVersion).replace(/ /g, '_') + '.png';
  return filename;
}

var DEFAULTS = {
  timeout: 5 * 60 * 1000 // 5 minutes
};

module.exports = function(grunt) {
  grunt.registerMultiTask('sauce_screenshots', 'Takes screenshots of webpages in various browsers using Sauce', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = grunt.util._.extend.apply(null, [{}, DEFAULTS, this.data]);
    // options.browsers
    if (options.browsers === undefined) {
      grunt.fail.warn('Required option "browsers" not specified!');
    }
    else if ((typeof options.browsers) === 'string') {
      options.browsers = grunt.file.readYAML(options.browsers);
      if (!(options.browsers instanceof Array)) {
        grunt.fail.warn('YAML file specified in "browsers" option did not contain an array!');
      }
    }
    else if ((typeof options.browsers) === 'function') {
      options.browsers = options.browsers();
      if (!(options.browsers instanceof Array)) {
        grunt.fail.warn('"browsers" option function did not return an array!');
      }
    }
    else if (!(options.browsers instanceof Array)) {
      grunt.fail.warn('"browsers" option was of invalid type! Must be a string (path to YAML file) or function (returning an array).');
    }
    // options.urls
    if (options.urls === undefined) {
      grunt.fail.warn('Required option "urls" not specified!');
    }
    else if ((typeof options.urls) === 'function') {
      options.urls = options.urls();
      if ((typeof options.urls) !== 'object') {
        grunt.fail.warn('"urls" option function did not return a plain object!');
      }
    }
    else if ((typeof options.urls) !== 'object') {
      grunt.fail.warn('"urls" option was of invalid type! Must be a (function returning a) plain object.');
    }
    // options.timeout
    if ((typeof options.timeout) === 'function') {
      options.timeout = options.timeout({
        urls: options.urls.length,
        browsers: options.browsers.length
      });
      if ((typeof options.timeout) !== 'number') {
        grunt.fail.warn('"timeout" option function did not return a number!');
      }
    }
    else if ((typeof options.timeout) !== 'number') {
      grunt.fail.warn('"timeout" option was of invalid type! Must be a (function returning a) number.');
    }

    if (!process.env.SAUCE_USERNAME) {
      grunt.fail.warn('Required environment variable $SAUCE_USERNAME not set!');
    }
    if (!process.env.SAUCE_ACCESS_KEY) {
      grunt.fail.warn('Required environment variable $SAUCE_ACCESS_KEY not set!');
    }

    var done = this.async();
    grunt.log.writeln('Connecting to Sauce Labs...');
    var browser = wd.promiseChainRemote('ondemand.saucelabs.com', 80, process.env.SAUCE_USERNAME, process.env.SAUCE_ACCESS_KEY);

    var screenshotsPromise = Object.keys(options.urls).reduce(function (urlWisePromise, url) {
      var destDir = options.urls[url];

      return options.browsers.reduce(function (browserWisePromise, browserSpec) {
        var filepath = path.join(destDir, filenameForBrowser(browserSpec));

        return (browserWisePromise
          .init(browserSpec, function (err, sessionInfo) {
            if (err) {
              throw err;
            }
            var sessionId = sessionInfo[0];
            grunt.log.writeln();
            grunt.log.writeln('Initialized session ' + sessionId.yellow + '.');
          })
          .then(function () {
            grunt.log.writeflags(browserSpec, 'Screenshotting ' + url.underline + ' in');
          })
          .get(url, function (err) {
            if (err) {
              throw err;
            }
          })
          .takeScreenshot(function (err, base64png) {
            if (err) {
              throw err;
            }
            var pngBuf = new Buffer(base64png, 'base64');
            grunt.file.write(filepath, pngBuf);
            grunt.log.writeln('Screenshot ' + filepath.bold.cyan + ' snapped.');
          })
          .fin(function() {
            return browser.quit(function (err) {
              throw err;
            });
          })
        );
      }, urlWisePromise);
    }, browser);

    (screenshotsPromise
      .timeout(options.timeout, 'Sauce screenshotting process exceeded ' + options.timeout + 'ms timeout!')
      .fail(function (err) {
        grunt.fail.warn(err);
      })
      .then(function () {
        done(true);
      })
    );
  });
};

@@ -3306,127 +3306,8 @@
 se =
- Object.keys(options.urls).reduce(function (urlWisePromise, url) %7B%0A      var destDir = options.urls%5Burl%5D;%0A%0A      return
  opt
@@ -3382,43 +3382,29 @@
     
-  
 var 
-filepath = path.join(destDir,
+browserFilename =
  fil
@@ -3435,28 +3435,37 @@
 pec)
-);%0A
+;
 %0A      
-  return (
+browserWisePromise = 
 brow
@@ -3478,27 +3478,16 @@
 ePromise
-%0A          
 .init(br
@@ -3527,36 +3527,32 @@
 Info) %7B%0A        
-  
-  
 if (err) %7B%0A     
@@ -3538,36 +3538,32 @@
      if (err) %7B%0A
-    
           throw 
@@ -3571,34 +3571,26 @@
 rr;%0A        
-    %7D%0A    
+%7D%0A
         var 
@@ -3617,36 +3617,32 @@
 nfo%5B0%5D;%0A        
-    
 grunt.log.writel
@@ -3646,20 +3646,16 @@
 teln();%0A
-    
         
@@ -3720,38 +3720,261 @@
 w + '.');%0A      
-    %7D)
+%7D);%0A      browserWisePromise = Object.keys(options.urls).reduce(function (urlWisePromise, url) %7B%0A        var destDir = options.urls%5Burl%5D;%0A        var filepath = path.join(destDir, browserFilename);%0A%0A        return (urlWisePromise
 %0A          .then
@@ -4527,18 +4527,80 @@
         
-  
+);%0A      %7D, browserWisePromise);%0A      return browserWisePromise
 .fin(fun
@@ -4605,28 +4605,24 @@
 unction() %7B%0A
-    
         retu
@@ -4656,36 +4656,32 @@
 rr) %7B%0A          
-    
 throw err;%0A     
@@ -4683,20 +4683,16 @@
         
-  
-  
 %7D);%0A    
@@ -4697,49 +4697,9 @@
     
-    %7D)%0A        );%0A      %7D, urlWisePromise
+%7D
 );%0A 

change loop nesting so single session for each browser shared by all URLs