var async = require('async');

var MAX_PARALLEL_TASKS = 5;

/**
 * Creates a new VNodeStore object, optionally taking in the persistence hooks
 * needed to save and restore the in-memory vnode set from an external data
 * source.
 * @constructor
 * @param {function} loadVNodeKeysFromStorage The function that will return
 *    a set, keyed by VNode name, with a list or set of keys. Usually sourced
 *    by the datastore.
 * @param {function} persistKeyToVNode The function that will take a VNode and
 *    a new key and will save the new key out to the datastore.  
 * @param {function} persistRemoveKeyFromVNode The inverse of
 *    persistKeyToVNode, this will remove a key from a VNode's set in the
 *    store.
 */
function VNodeStore(loadVNodeKeysFromStorage, persistKeyToVNode, persistRemoveKeyFromVNode) {
    this.vnCache = {};
    this.loadVNodeKeysFromStorage = loadVNodeKeysFromStorage;
    this.persistKeyToVNode = persistKeyToVNode;
    this.persistRemoveKeyFromVNode = persistRemoveKeyFromVNode;
}

/**
 * Adds key stewardship to a VNode.  If the cache doesn't currently know
 * about the VNode, it adds it. 
 * @param {string} vnodeName The name of the virtual node to own the key.
 * @param {string} key The key to be watched by the vnode.
 * @param {function} done The method to be called when persistence is complete.
 */
VNodeStore.prototype.addKeyToVNode = function addKeyToVNode(vnodeName, key, done) {
    var self = this;
    var vnCache = self.vnCache;
    if (!self._objectContainsKey(vnCache, vnodeName)) {
        vnCache[vnodeName] = {};
    }
    if (!self._objectContainsKey(vnCache[vnodeName], key) ) {
        self.persistKeyToVNode(vnodeName, key, function(err) {
            if(!err) {
                vnCache[vnodeName][key] = true;
            }
            done(err);
        });
    }
};


/**
 * Removes a key from a VNode's watch, if it exists in the first place.  If
 * a delete operation is actually performed, the persistence callback is
 * triggered.
 * @param {string} vnodeName The name of the vnode to disown the key.
 * @param {string} key The key to be disowned.
 * @param {function} done The callback for once the key was successfully
 *      removed.
 */
VNodeStore.prototype.removeKeyFromVNode = function removeKeyFromVNode(vnodeName, key, done) {
    var self = this;
    if (self._objectContainsKey(self.vnCache, vnodeName) &&
            self._objectContainsKey(self.vnCache[vnodeName], key)) {
        self.persistRemoveKeyFromVNode(vnodeName, key, function(err) {
            delete self.vnCache[vnodeName][key];
            done();
        });
    } else {
        done();
    }
};

/**
 * Uses the parameter vnodeKeyArray if exists to set the vnode cache to a Map where
 * the key is a VNode name and the value is a set of keys. If the parameter is
 * not passed, it checks for the overriden method loadVNodeKeysFromStorage to
 * return the same Map from whatever source the client desires.  If neither can
 * provide such a Map, it defaults to setting the cache to an empty object, if
 * none exist.
 * @param {string} vnodeName The name of the vnode to load all the keys for.
 * @param {function} forEachKey A callback to run on each key loaded. Returns
 *     true if the key should be forgotten after recovery.
 * @param {function} done Callback for when keys have been loaded, optional err
 */
VNodeStore.prototype.loadVNodeKeys = function loadVNodeKeys(vnodeName, forEachKey, done) {
    var self = this;
    var vnodeKeyArray = [];
    vnodeKeyArray = self.loadVNodeKeysFromStorage(vnodeName, function(err, keys) {
		self.onKeysLoaded(err, vnodeName, keys, forEachKey, function(err){
            done(err);
        });
	});
};

/**
 * This is the function called when all keys have been loaded from the datastore.
 * It then uses forEachKey function for the specific business logic that the service
 * wants to call on each key.  If the forEachKey returns false, we will remove the
 * key from bookkeeping.
 * @param {Error} err Error object if any persistence issues when fetching the set.
 * @param {string} vnodeName The name of the vnode who owns the keys.
 * @param {Array} keys The entire array of keys loaded from memory.
 * @param {function} forEachKey The method to be called onthe recovery of each key.
 * @param {function} done The method to call when all keys have been handled.
 */
VNodeStore.prototype.onKeysLoaded = function onKeysLoaded(err, vnodeName, keys, forEachKey, done) {
    var self = this;
    var nodeKeyArray = keys || [];
    var keysToRemove = [];
    if (typeof forEachKey === 'function') {
        async.filter(vnodeKeyArray, forEachKey, function(completedKeys) {
            // Load all keys to the cache
            self.vnCache[vnodeName] = self._arrayToSet(vnodeKeyArray);
            // Remove the handled keys
            async.eachLimit(
                completedKeys,
                MAX_PARALLEL_TASKS,
                function (item, callback) {
                    return self.removeKeyFromVNode(vnodeName, item, callback);
                },
                function onKeysLoadedComplete(err) {
                    //TODO (joseph): when logging exists, log here.
                    done(err);
                }
            );
        });
   } else {
       // nothing to do, return
       done();
    }
};


/**
 * A helper method to check if the object/map has the key requested, without
 * getting an accidental hit on an Object base property or method.  If it ends
 * up being used elsewhere in the code, should probably move to a helper file,
 * but currently it's assigned to this class to avoid the function being
 * garbage collected.
 * @param {object} object Any object, to be checked for the peresence of key.
 * @param {string} key Any string, checks to see if the object contains that
 *    that property.
 */
VNodeStore.prototype._objectContainsKey = function _objectContainsKey(obj, key) {
    return Object.prototype.hasOwnProperty.call(obj, key);
};

/**
 * A helper method to turn an array, which will often be returned from the
 * datastore callbacks, to a set, which is more optimal for searching.
 * @param {object} array A list of items to be added to the set as keys.
 */
VNodeStore.prototype._arrayToSet = function _arrayToSet(array) {
    var set = {};
    for (var i=0; i < array.length; i++) {
        set[array[i]] = true;
    }
    return set;
};

module.exports = VNodeStore;

@@ -2509,32 +2509,60 @@
 function(err) %7B%0A
+            if (!err) %7B%0A    
             dele
@@ -2594,16 +2594,30 @@
 %5D%5Bkey%5D;%0A
+            %7D%0A
         
@@ -2621,24 +2621,27 @@
        done(
+err
 );%0A        %7D

fix for error case