// Map configuration storage

var step       = require('step');
var RedisPool  = require('redis-mpool');
var _          = require('underscore');
var MapConfig  = require('../models/mapconfig');
var assert = require('assert');

/**
 * @constructor
 * @type {MapStore}
 */
function MapStore(opts) {
  opts = opts || {};
  this._config = _.defaults(opts, {
    redis_host: "127.0.0.1",
    redis_port: 6379,
    redis_db: 0,
    redis_key_mapcfg_prefix: "map_cfg|",
    expire_time: 300, // in seconds (7200 is 5 hours; 300 is 5 minutes)
    pool_max: 50,
    pool_idleTimeout: 10000, // in milliseconds
    pool_reapInterval: 1000, // in milliseconds
    pool_log: false
  });
  this.redis_pool = this._get("pool");
  if ( ! this.redis_pool ) {
    var redis_opts = {
      host: this._get("redis_host"),
      port: this._get("redis_port"),
      max: this._get("pool_max"),
      idleTimeoutMillis: this._get("pool_idleTimeout"),
      reapIntervalMillis: this._get("pool_reapInterval"),
      log: this._get("pool_log")
    };
    this.redis_pool = new RedisPool(redis_opts);
  }
}

var o = MapStore.prototype;

/// Internal method: get configuration item
o._get = function(key) {
  return this._config[key];
};

/// Internal method: get redis pool
o._redisPool = function() {
  return this.redis_pool;
};

/// Internal method: run redis command
//
/// @param func - the redis function to execute (uppercase required!)
/// @param args - the arguments for the redis function in an array
///               NOTE: the array will be modified
/// @param callback - function(err,val) function to pass results too.
///
o._redisCmd = function(func, args, callback) {
  var client;
  var pool = this._redisPool();
  var db = this._get("redis_db");

  step(
        function getRedisClient() {
            pool.acquire(db, this);
        },
        function executeQuery(err, data) {
            assert.ifError(err);

            client = data;
            args.push(this);
            client[func].apply(client, args);
        },
        function releaseRedisClient(err, data) {
            if ( ! _.isUndefined(client) ) {
                pool.release(db, client);
            }
            if ( callback ) {
                callback(err, data);
            }
        }
    );

};

/// API: Load a saved MapStore object, renewing expiration time
//
/// Static method
///
/// @param id the MapStore identifier
/// @param callback function(err, mapConfig) callback function
///
o.load = function(id, callback) {
  var that = this;
  var key = this._get("redis_key_mapcfg_prefix") + id;
  var exp = this._get("expire_time");
  step(
    function getRecord() {
      that._redisCmd('GET', [key], this);
    },
    function parseRecord(err, json) {
      assert.ifError(err);

      if ( ! json ) {
        throw new Error("Invalid or nonexistent map configuration token '" + id + "'");
      }
      return JSON.parse(json);
    },
    function instantiateConfig(err, serializedMapConfig) {
      assert.ifError(err);

      var obj = MapConfig.create(serializedMapConfig);
      return obj;
    },
    function finish(err, obj) {
      if ( ! err ) {
        // Postpone expiration for the key
        that._redisCmd('EXPIRE', [key, exp]); // not waiting for response
      }
      callback(err, obj);
    }
  );
};

/// API: store map to redis
//
/// @param map MapConfig to store
/// @param callback function(err, id, known) called when save is completed
///
o.save = function(map, callback) {
  var that = this;
  var id = map.id();
  var key = this._get("redis_key_mapcfg_prefix") + id;
  var exp = this._get("expire_time");
  step(
    function writeRecord() {
      that._redisCmd('SETNX', [key, map.serialize()], this);
    },
    function finish(err, wasNew) {
      if ( ! err ) {
        that._redisCmd('EXPIRE', [key, exp]); // not waiting for response
      }
      callback(err, id, !wasNew);
    }
  );
};

/// API: delete map from store
//
/// @param map MapConfig to delete from store
/// @param callback function(err, id, known) called when save is completed
///
o.del = function(id, callback) {
  var that = this;
  var key = this._get("redis_key_mapcfg_prefix") + id;
  step(
    function writeRecord() {
      that._redisCmd('DEL', [key], this);
    },
    function finish(err) {
      callback(err);
    }
  );
};


module.exports = MapStore;

@@ -1656,22 +1656,8 @@
 ) %7B%0A
-  var client;%0A
   va
@@ -1725,144 +1725,54 @@
 %0A%0A  
-step(%0A        function getRedisClient() %7B%0A            pool.acquire(db, this);%0A        %7D,%0A        function executeQuery(err, data
+pool.acquire(db, function (err, client
 ) %7B%0A    
     
@@ -1771,186 +1771,77 @@
     
-        assert.ifError(err);%0A%0A            client = data;%0A            args.push(this);%0A            client%5Bfunc%5D.apply(client, args);%0A   
+if (err) %7B%0A      return callback(err);%0A
     
- %7D,
+%7D%0A
 %0A    
-    function releaseRedisClient
+args.push(function 
 (err
@@ -1860,55 +1860,22 @@
     
-      
 if (
- ! _.isUndefined(
 client)
- )
  %7B%0A
-        
     
@@ -1914,28 +1914,48 @@
     
+%7D%0A%0A
       
-%7D%0A    
+if (err && callback) %7B%0A
         
 if (
@@ -1950,20 +1950,22 @@
         
-if (
+return
  callbac
@@ -1965,29 +1965,54 @@
 callback
- ) %7B%0A        
+(err);%0A      %7D%0A%0A      if (callback) %7B%0A
         
@@ -2042,34 +2042,63 @@
     
-  
+%7D%0A
     %7D
+);%0A
 %0A    
-    %7D%0A    
+client%5Bfunc%5D.apply(client, args);%0A  %7D
 );%0A
-%0A
 %7D;%0A%0A

remove step 1