var fs = require('fs');

exports = module.exports = function accesslog(option) {
    var getStream = null;
    var accesslogCurr = null;
    var accesslogStream = null;
    if (option.kafka) {
        var kafka = require('./kafka');
        kafka.init(option.kafka);
    }

    if (option.filePeriod) {
        var accesslogPeriod = period(option.filePeriod);
        getStream = function(date) {
            var ts = date.getTime();
            var acc = ts - ts % accesslogPeriod;
            if (acc == accesslogCurr) {
                return accesslogStream;
            }
            accesslogCurr = acc;
            var dd = new Date(acc);
            var fileName = 'access' + (process.env.port||'') + '-' + dd.getFullYear() + addDigit(dd.getMonth()+1) +
                addDigit(dd.getDate()) + 
                (accesslogPeriod < 24 * 3600 * 1000 ? addDigit(dd.getHours()) : '') + 
                '.log';
            var old = accesslogStream;
            accesslogStream = fs.createWriteStream('logs/' + fileName, {flags: 'a+'});
            if (old) {
                process.nextTick(function() {
                    old.end();
                });
            }
            return accesslogStream;
        };
    }

    return function accessLogger(req, res, next) {
        var sock = req.socket;
        req._startTime = new Date();
        req._remoteAddress = sock.socket ? sock.socket.remoteAddress : sock.remoteAddress;

        var end = res.end;
        res.end = function(chunk, encoding) {
            res.end = end;
            res.end(chunk, encoding);
            log();
        };

        var log = function() {
            var cl = res.getHeader('content-length') || 0;
            var reqTime = new Date().getTime() - req._startTime.getTime();
            var line = req._remoteAddress + ' ' +
                (req.headers['x-real-ip'] || '-') + ' ' +
                (req.headers.common_session_id || '-') + ' ' +
                logDate(req._startTime) + 
                ' "' + req.method + ' ' +
                (req.orginalUrl || req.url) + ' ' +
                req.httpVersion + '" ' + 
                res.statusCode + ' ' +
                cl + ' ' +
                (reqTime * 1000) + ' ' +
                (req.headers.referer ? '"' + req.headers.referer + '"' : '"-"') + ' ' +
                (req.headers['x-forwarded-for'] ? '"' + req.headers['x-forwarded-for'] +  '"' : '"-"') ;
            var line1 = line + ' ' + (req.headers['user-agent'] ? '"' + req.headers['user-agent']  + '"' : '"-"') + '\n'
            if (getStream) {
                var stream = getStream(req._startTime);
                if (stream) stream.write(line1 );
            }
            if (option.stdout) process.stdout.write(line1);

            if(req.orginalUrl && kafka){
                if (res.statusCode >= 400) {
                    kafka.send(line + '\n', kafka.config().accessTopic);
                }
                if (kafka.config().slowAceessTime
                    && reqTime > kafka.config().slowAceessTime * 1000) {
                    kafka.send(line + '\n', kafka.config().accessTopic);
                }
            }
        };

        next();
    };
};


var months = [
        'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
        'Jul',  'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
    ];
    

var addDigit = function(n) {
        if (n < 10) {
            return '0' + n;
        }
        return n;
    };

var logDate = function(date) {
    return '[' + 
        addDigit(date.getDate()) + '/' + 
        months[date.getMonth()] + '/' + 
        date.getFullYear() + ':' + 
        addDigit(date.getHours()) + ':' + 
        addDigit(date.getMinutes()) + ':' + 
        addDigit(date.getSeconds()) + ' +0800]';
};

var period = function(i) {
    try {
        var s = i.trim();
        var u = s.charAt(s.length - 1);
        var n = Number.parseInt(s);
        if (n > 0) {
            if (u === 'd' || u === 'D') {
                return n * 24 * 3600 * 1000;
            } else if (u === 'h' || u === 'H') {
                return n * 3600 * 1000;
            }
        }
    } catch (e) {
        // do nothing
    }
    return 24 * 3600 * 1000;
};

