var redis = require('redis');
var Stratum = require('stratum-pool');



/*
This module deals with handling shares when in internal payment processing mode. It connects to a redis
database and inserts shares with the database structure of:

key: coin_name + ':' + block_height
value: a hash with..
        key:

 */



module.exports = function(logger, poolConfig){

    var redisConfig = poolConfig.redis;
    var coin = poolConfig.coin.name;


    var forkId = process.env.forkId;
    var logSystem = 'Pool';
    var logComponent = coin;
    var logSubCat = 'Thread ' + (parseInt(forkId) + 1);

    var connection = redis.createClient(redisConfig.port, redisConfig.host);

    connection.on('ready', function(){
        logger.debug(logSystem, logComponent, logSubCat, 'Share processing setup with redis (' + redisConfig.host +
            ':' + redisConfig.port  + ')');
    });
    connection.on('error', function(err){
        logger.error(logSystem, logComponent, logSubCat, 'Redis client had an error: ' + JSON.stringify(err))
    });
    connection.on('end', function(){
        logger.error(logSystem, logComponent, logSubCat, 'Connection to redis database has been ended');
    });

    connection.info(function(error, response){
        if (error){
            logger.error(logSystem, logComponent, logSubCat, 'Redis version check failed');
            return;
        }
        var parts = response.split('\r\n');
        var version;
        var versionString;
        for (var i = 0; i < parts.length; i++){
            if (parts[i].indexOf(':') !== -1){
                var valParts = parts[i].split(':');
                if (valParts[0] === 'redis_version'){
                    versionString = valParts[1];
                    version = parseFloat(versionString);
                    break;
                }
            }
        }
        if (!version){
            logger.error(logSystem, logComponent, logSubCat, 'Could not detect redis version - but be super old or broken');
        }
        else if (version < 2.6){
            logger.error(logSystem, logComponent, logSubCat, "You're using redis version " + versionString + " the minimum required version is 2.6. Follow the damn usage instructions...");
        }
    });
    
    var _lastShareTimes = {};

    this.handleShare = function(isValidShare, isValidBlock, shareData) {

        var redisCommands = [];

        if (isValidShare) {
            redisCommands.push(['hincrbyfloat', coin + ':shares:roundCurrent', shareData.worker, shareData.difficulty]);
            redisCommands.push(['hincrby', coin + ':stats', 'validShares', 1]);
        }
        else{
            redisCommands.push(['hincrby', coin + ':stats', 'invalidShares', 1]);
        }
        
        // pplnt time share tracking of workers
        if (isValidShare || isValidBlock) {
            var now = Date.now();
            var lastShareTime = now;
            if (_lastShareTimes[shareData.worker] != null && _lastShareTimes[shareData.worker] > 0)
                lastShareTime = _lastShareTimes[shareData.worker];
            
            var timeChangeSec = Math.round(Math.max(now - lastShareTime, 0) / 1000);
            // if its been less than 10 minutes since last share was submitted
            if (timeChangeSec < 600) {
                redisCommands.push(['hincrbyfloat', coin + ':shares:timesCurrent', shareData.worker, timeChangeSec]);
            }
            
            // track last time share
            _lastShareTimes[shareData.worker] = now;
        }
        
        /* Stores share diff, worker, and unique value with a score that is the timestamp. Unique value ensures it
           doesn't overwrite an existing entry, and timestamp as score lets us query shares from last X minutes to
           generate hashrate for each worker and pool. */
        var dateNow = Date.now();
        var hashrateData = [ isValidShare ? shareData.difficulty : -shareData.difficulty, shareData.worker, dateNow];
        redisCommands.push(['zadd', coin + ':hashrate', dateNow / 1000 | 0, hashrateData.join(':')]);

        if (isValidBlock){
            redisCommands.push(['rename', coin + ':shares:roundCurrent', coin + ':shares:round' + shareData.height]);
            redisCommands.push(['rename', coin + ':shares:timesCurrent', coin + ':shares:times' + shareData.height]);
            redisCommands.push(['sadd', coin + ':blocksPending', [shareData.blockHash, shareData.txHash, shareData.height, shareData.worker, dateNow].join(':')]);
            redisCommands.push(['hincrby', coin + ':stats', 'validBlocks', 1]);            
            // reset pplnt share times
            _lastShareTimes = {};
        }
        else if (shareData.blockHash){
            redisCommands.push(['hincrby', coin + ':stats', 'invalidBlocks', 1]);
        }

        connection.multi(redisCommands).exec(function(err, replies){
            if (err)
                logger.error(logSystem, logComponent, logSubCat, 'Error with share processor multi ' + JSON.stringify(err));
        });


    };

};

@@ -585,24 +585,337 @@
 kId) + 1);%0A%0A
+    function roundTo(n, digits) %7B%0A        if (digits === undefined) %7B%0A            digits = 0;%0A        %7D%0A        var multiplicator = Math.pow(10, digits);%0A        n = parseFloat((n * multiplicator).toFixed(11));%0A        var test =(Math.round(n) / multiplicator);%0A        return +(test.toFixed(digits));%0A    %7D%0A    %0A
     var conn
@@ -3425,26 +3425,23 @@
 geSec = 
-Math.
 round
+To
 (Math.ma
@@ -3472,16 +3472,19 @@
 ) / 1000
+, 3
 );%0A     

Update shareProcessor.js