ST.context = {}; // namespace 
 
ST._screenshotCount = 0;
 
(function () {
var logger = ST.logger.forClass('context/Base');
 
ST.context.Base = ST.define({
 
    /**
     * @cfg {Boolean} eventTranslation 
     * `false` to disable event translation.  If `false` events that are not supported by
     * the browser's event APIs will simply be skipped.
     * NOTE: inherited from Player
     */
    eventTranslation: true,
 
    /**
     * @cfg {Boolean} visualFeedback 
     * `false` to disable visual feedback during event playback (mouse cursor, and "gesture"
     * indicator)
     * NOTE: inherited from Player
     */
    visualFeedback: true,
 
    /**
     * @param {Array} playables Either a config for a playable or a Playable
     * @param done
     */
    play: function (playables, done) {
        var me = this,
            player = ST.player(),
            options = ST.options,
            length = playables.length,
            i, p, tail;
        logger.trace('.play', '[' + length + ']', 'done');
 
        if (done) {
            tail = {
                type: 'tail',
                remoteable: false,
                fn: function () {
                    player.un('error', tail);
 
                    if (done) {
                        done();
                    }
                }
            };
            playables.push(tail);
        }
 
        for (= 0; i < length; i++) {
            p = playables[i];
            p.context = me;
            if (typeof p.futureClsName === 'undefined') {
                p.futureClsName = 'ST.future.Element';
            }
            p.args = p.args || {};
        }
 
        me.eventDelay = player.eventDelay = options.eventDelay;
        me.typingDelay = player.typingDelay = options.typingDelay;
        me.visualFeedback = player.visualFeedback = options.visualFeedback;
        me.eventTranslation = player.eventTranslation = options.eventTranslation;
        if (me.injector) {
            me.injector.translate = options.eventTranslation;
        }
 
        player.add(playables);
 
        if (done) {
            playables.pop();
            player.on('error', tail.fn);
        }
 
        player.start();  // does nothing if already started 
        return playables;
    },
    
    screenshot: function (name, tolerance, done) {
        logger.trace('.screenshot');
        var me = this;
        name = name || ST._screenshotCount++;
        tolerance = tolerance || 0;
        
        me._screenshot(name, function (err, comparison) {
            var expectation,
                passed;
            
            if (err) {
                expectation = {
                    passed: false,
                    message: err.stack || err.message || err
                };
            } else if (comparison) {
                passed = comparison.diffCount <= tolerance;
                expectation = {
                    passed: passed,
                    message: 'Expected screenshot ' + name + ' to match baseline.',
                    screenshot: comparison.path,
                    baseline: comparison.baseline,
                    diff: comparison.diff
                };
            } else {
                expectation = {
                    passed: true,
                    message: 'Screenshot comparison unsupported for this session'
                };
            }
            
            ST.status.addResult(expectation);
            done(comparison);
        });
    },
    
    _createInstance: function (className, config) {
        logger.trace('._createInstance', className, '{config}');
        var fn = ST.clsFromString(className);
 
        if (!fn) {
            fn = ST.playable.Playable;
        }
 
        return new fn(config);
    },
 
 
    createPlayable: function (event) {
        var me = this,
            type = event.type,
            playableClsName, playable;
        logger.trace('.createrPlayable <=', type);
 
        playableClsName = event.futureClsName + '.prototype.playables.' + ST.capitalize(type);
        playable = me._createInstance(playableClsName, event);
 
        // allows for custom events such as the expandX methods for tap/type... 
        if (!playable) {
            playable = new ST.playable.Playable(event);
        }
 
        playable.context = playable.context || me;
 
        logger.trace('.createPlayable() =>', playable.type);
        return playable;
    },
 
    checkGlobalLeaks: function (done) {
        logger.trace('._checkGlobalLeaks', 'done()');
 
        this._checkGlobalLeaks(function (result) {
            result = result || {};
 
            var results = result.results,
                addedGlobals = result.addedGlobals;
 
            if (results && results.length) {
                for (var i=0; i<results.length; i++) {
                    ST.status.addResult(results[i]);
                }
            }
 
            if (addedGlobals && addedGlobals.length) {
                ST.addGlobals(addedGlobals);
            }
            done();
        });
    }
});
 
}());