/**
 * Copyright 2016 the WHATAP project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */
var WHATAP_CONF  = 'reqlog';

var conf     = require('./conf/configure'),
    DateUtil = require('./util/dateutil'),
    IPUtil   = require('./util/iputil'),
    path     = require('path'),
    fs       = require('fs'),
    LOGGER = require('./logger');

var PID=process.pid;

var initializer = {
    last : DateUtil.currentTime(),
    lastDateUnit : DateUtil.getDateUnit(),
    lastFileRotation : true,
    reset : function () {
        if(RequestLog.printWriter) RequestLog.printWriter.close();
        RequestLog.logfile = null;
        RequestLog.openFile();
    },
    process : function () {
        conf  = require('./conf/configure');
        var now = DateUtil.currentTime();
        if(now > this.last + DateUtil.MILLIS_PER_HOUR) {
            this.last = now;
            RequestLog.clearOldLog();
        }
        if(this.lastFileRotation !== conf.reqlog_rotation_enabled
            || this.lastDateUnit !== DateUtil.getDateUnit()
            || (RequestLog.logfile !== null && fs.existsSync(RequestLog.logfile) == false)) {
            try {
                if(RequestLog.printWriter){
                    RequestLog.printWriter.close();
                }
                RequestLog.logfile = null;
                this.lastFileRotation = conf.reqlog_rotation_enabled;
                this.lastDateUnit = DateUtil.getDateUnit();
            } catch(e) {
                console.log(e);
            }
        }
        try {
            RequestLog.openFile();
        } catch(e) {
            console.log(e);
            return false;
        }
        return true;
    }
};

var RequestLog = {
    ONAME : null,
    logfile : null,
    lastLog : {},
    printWriter : null,
    setRecord : async function (ctx) {
        try{
            if(this.printWriter != null) {
                this.buildRecord(ctx).then(e => {
                    this.printWriter.write(e + '\n');
                }).catch((err)=> {
                    LOGGER.printError('[WHATAP-LOG]' ,'setRecord_1' , err , false);
                });
            } else {
                this.openFile();
            }
        } catch (e){
            LOGGER.printError('[WHATAP-LOG]' ,'setRecord_2' , err , false);
        }
    },
    checkOk : function (id, sec) {
        if(Object.keys(RequestLog.lastLog).length >= 1000) {
            RequestLog.lastLog = {};
        }

        if(sec > 0) {
            var last = RequestLog.lastLog[id];
            if(last == null) {
                last = 0;
            }
            var now = Date.now();
            if(now < last + sec * 1000) {
                return false;
            }
            RequestLog.lastLog[id] = now;
        }
        return true;
    },
    buildRecord : async function (ctx) {
        var str = '';
        let seperator = conf.reqlog_seperator;
        str += "stime=" + ctx.start_time;
		if (conf.reqlog_x_etime) {
            str += seperator + "etime=" + ctx.endTime;
		}
		if (conf.reqlog_x_elapsed) {
            str += seperator + "elapsed=" + ctx.elapsed;
		}
		if (conf.reqlog_x_url) {
            str += seperator + "url=" + ctx.service_name;
		}
		if (conf.reqlog_x_httphost && ctx.http_host!=null) {
            str += seperator + "httphost=" + ctx.http_host;
		}
		if (conf.reqlog_x_method) {
            str += seperator + "method=" + ctx.http_method;
		}
		if (conf.reqlog_x_ip && ctx.remoteIp != 0) {
            str += seperator + "ip=" + IPUtil.intToString(ctx.remoteIp);
		}
		if (conf.reqlog_x_status) {
            str += seperator + "status=" + ctx.status;
		}
        /*
		if (conf.reqlog_x_wcid && x.wclientId != 0) {
            str += seperator + "wcid=" + x.wclientId;
		}
        */
		if (conf.reqlog_x_login && ctx.login != null) {
            str += seperator + "login=" + ctx.login;
		}

		if (conf.reqlog_x_error && ctx.error != null && ctx.statusMessage !== undefined) {
            str += seperator + "errMsg=" + ctx.statusMessage;
		}
		if (conf.reqlog_x_useragent) {
            str += seperator + "userAgent=" + ctx.userAgentString;
		}
		if (conf.reqlog_x_txid) {
            str += seperator + "txid=" + ctx.txid;
		}
		if (ctx.custid != null) {
			if (conf.reqlog_x_custid) {
                str += seperator + "custid=" + ctx.custid;
			} else if (conf.reqlog_x_gtid) {
                str += seperator + "gtid=" + ctx.custid;
			}
		}
		if (conf.reqlog_x_mtid && ctx.mtid != 0) {
            str += seperator + "mtid=" + ctx.mtid;
			if (conf.reqlog_x_mdepth) {
                str += seperator + "mdepth=" + ctx.mdepth;
			}
		}
        /*
		if (conf.reqlog_x_dbc && x.dbc_time > 0) {
            str += seperator + "dbcTime=" + x.dbc_time;
		}
        */
		if (conf.reqlog_x_sql && ctx.sql_count > 0) {
            str += seperator + "sqlCnt=" + ctx.sql_count;
			str += seperator + "sqlTime=" + ctx.sql_time;
		}
		if (conf.reqlog_x_httpc && ctx.httpc_count > 0) {
            str += seperator + "httpCallCnt=" + ctx.httpc_count;
			str += seperator + "httpCallTime=" + ctx.httpc_time;
		}
		if (conf.reqlog_x_rs && ctx.rs_count > 0) {
            str += seperator + "rsCnt=" + ctx.rs_count;
			str += seperator + "rsTime=" + ctx.rs_time;
		}
		
		return str;
    },
    openFile : function () {
        if(conf.log_file_enabled === false ) { return; }
        var log_prefix = WHATAP_CONF+"-";

        var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
        if(root==null || root ==undefined){
            console.log('[WHATAP]RequestLog Error - WHATAP ROOT DIR IS NULL');
            return;
        }
        if(fs.existsSync(root) == false) {
            fs.mkdirSync(root, {recursive: true});
        }
        var dir = path.join(root, 'logs');
        if(fs.existsSync(dir) == false) {
            fs.mkdirSync(dir);
        }

        if(conf.reqlog_rotation_enabled) {
            var file = path.join(dir, log_prefix + DateUtil.yyyymmdd() + '.log');
            this.logfile = file;
            this.printWriter = fs.createWriteStream(file, {flags : 'a'});
        } else {
            var file = path.join(dir, 'reqlog.log');
            this.logfile = file;
            this.printWriter = fs.createWriteStream(file, {flags : 'a'});
        }

    },
    clearOldLog : function () {
        if(conf.reqlog_rotation_enabled === false || conf.reqlog_enabled === false) { return; }
        if(conf.reqlog_keep_days <= 0) { return; }

        var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
        if(root==null || root ==undefined){ return; }
        var nowUnit = DateUtil.getDateUnit(),
            dir = path.join(root, 'logs'),
            log_prefix = WHATAP_CONF+"-";

        fs.readdir(dir, function (err, files) {

            for(var i=0; i<files.length; i++) {
                var stat = fs.statSync(path.join(dir, files[i]));
                if(stat.isDirectory()) {
                    return true;
                }
                var name = files[i];
                if(name.indexOf(log_prefix) < 0) {
                    return true;
                }
                var x = name.lastIndexOf('.');
                if(x < 0) {
                    return true;
                }
                var date = name.substr(log_prefix.length + 1, (x - log_prefix.length - 1));
                if(date.length != 8) {
                    return true;
                }
                var d = DateUtil.yyyymmdd(date);
                var fileUnit = DateUtil.getDateUnit(d);
                try {
                    if (nowUnit - fileUnit > conflog_keep_days) {
                        fs.unlinkSync(path.join(dir, files[i]));
                    }
                } catch (e) { }
            }

        });
    },
    read : function( file,  endpos,  length , callback) {

		if ( file == null || length === 0)
			return null;
		if (file.startsWith(WHATAP_CONF) == false) return null;

        var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
        if(root==null ){
            return null;
        }
        var dir = path.join(root, 'logs');
        var fileFullPath = path.join(dir, file);

        if(fs.existsSync(fileFullPath) == false) {
            return null;
        }
        const stats = fs.statSync(fileFullPath);

        if (endpos < 0) {
            endpos = stats.size;
        }
        
		var start = Math.max(0, endpos - length);

		if ( stats.size < start)
            return null;
            
		var available = stats.size - start;
        var readable = Math.min(available, length);
        var next=-1;
        var buffer = Buffer.alloc(readable);
        fs.open(fileFullPath, 'r', function (err, fd) {
            fs.read(fd, buffer, 0, buffer.length, start,function(e,l,b){
                next = endpos + l;
                if (next > stats.size) {
                    next = -1;
                }
                callback(start, next,b.toString("utf8",0,l)) ;
            });
            fs.close(fd);
        });
       
	},
    getLogFiles : function () {
        var MapValue = require('./value/map-value');
        var log_prefix = WHATAP_CONF+"-";

        var o = new MapValue();
        if(conf.log_file_enabled === false ) { return o; }
        var root = conf.getProperty('log_root', null) || process.env.WHATAP_HOME || conf['app.root'];
        if(root==null){
            return o;
        }
        var dir = path.join(root, 'logs');
        if(fs.existsSync(dir) === false) {
            return o;
        }
        var agoOneMonthTime=DateUtil.getMonth(Date.now(), -1);

        if(conf.reqlog_rotation_enabled) {
            var files = fs.readdirSync(dir);
            files.forEach(function (file) {
                if (file.startsWith(log_prefix) == false) {
                    return;
                }
                var x = file.lastIndexOf('.');
                if (x < 0) {
                    return;
                }
                var date = file.substring(log_prefix.length , x);
                if (date.length != 8) {
                    return;
                }
                if (DateUtil.yyyymmdd(date) < agoOneMonthTime) {
                    return;
                }
                const stats = fs.statSync(dir + '/'+file);
                if(stats){
                    o.putLong(file, stats.size);
                }
            });
        } else {
            if (fs.existsSync(dir + "/reqlog.log")) {
                const stats = fs.statSync(dir + "/reqlog.log");
                o.putLong(file, stats.size);
            }
        }
        return o;
    },
    initializer : initializer
};

module.exports = RequestLog;