#!/usr/bin/env bash
':' //; exec "$(command -v nodejs || command -v node || echo "ERROR node IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@"

// shebang hack from:
// http://unix.stackexchange.com/questions/65235/universal-node-js-shebang

// Initially this is run as a shell script.
// Then, the second line, finds nodejs or node or js in the system path
// and executes it with the shell parameters.

// netdata
// real-time performance and health monitoring, done right!
// (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
// SPDX-License-Identifier: GPL-3.0-or-later

// --------------------------------------------------------------------------------------------------------------------

'use strict';

// --------------------------------------------------------------------------------------------------------------------
// get NETDATA environment variables

var NETDATA_PLUGINS_DIR = process.env.NETDATA_PLUGINS_DIR || __dirname;
var NETDATA_USER_CONFIG_DIR = process.env.NETDATA_USER_CONFIG_DIR || '/etc/netdata';
var NETDATA_STOCK_CONFIG_DIR = process.env.NETDATA_STOCK_CONFIG_DIR || '/usr/lib/netdata/conf.d';
var NETDATA_UPDATE_EVERY = process.env.NETDATA_UPDATE_EVERY || 1;
var NODE_D_DIR = NETDATA_PLUGINS_DIR + '/../node.d';

// make sure the modules are found
process.mainModule.paths.unshift(NODE_D_DIR + '/node_modules');
process.mainModule.paths.unshift(NODE_D_DIR);


// --------------------------------------------------------------------------------------------------------------------
// load required modules

var fs = require('fs');
var url = require('url');
var util = require('util');
var http = require('http');
var path = require('path');
var extend = require('extend');
var netdata = require('netdata');


// --------------------------------------------------------------------------------------------------------------------
// configuration

function netdata_read_json_config_file(module_filename) {
    var f = path.basename(module_filename);

    var ufilename, sfilename;

    var m = f.match('.plugin' + '$');
    if(m !== null) {
        ufilename = netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
        sfilename = netdata.options.paths.stock_config + '/' + f.substring(0, m.index) + '.conf';
    }

    m = f.match('.node.js' + '$');
    if(m !== null) {
        ufilename = netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
        sfilename = netdata.options.paths.stock_config + '/node.d/' + f.substring(0, m.index) + '.conf';
    }

    try {
        netdata.debug('loading module\'s ' + module_filename + ' user-config ' + ufilename);
        return JSON.parse(fs.readFileSync(ufilename, 'utf8'));
    }
    catch(e) {
        netdata.error('Cannot read user-configuration file ' + ufilename + ': ' + e.message + '.');
        dumpError(e);
    }

    try {
        netdata.debug('loading module\'s ' + module_filename + ' stock-config ' + sfilename);
        return JSON.parse(fs.readFileSync(sfilename, 'utf8'));
    }
    catch(e) {
        netdata.error('Cannot read stock-configuration file ' + sfilename + ': ' + e.message + ', using internal defaults.');
        dumpError(e);
    }

    return {};
}

// internal defaults
extend(true, netdata.options, {
    filename: path.basename(__filename),

    update_every: NETDATA_UPDATE_EVERY,

    paths: {
        plugins: NETDATA_PLUGINS_DIR,
        config: NETDATA_USER_CONFIG_DIR,
        stock_config: NETDATA_STOCK_CONFIG_DIR,
        modules: []
    },

    modules_enable_autodetect: true,
    modules_enable_all: true,
    modules: {}
});

// load configuration file
netdata.options_loaded = netdata_read_json_config_file(__filename);
extend(true, netdata.options, netdata.options_loaded);

if(!netdata.options.paths.plugins)
    netdata.options.paths.plugins = NETDATA_PLUGINS_DIR;

if(!netdata.options.paths.config)
    netdata.options.paths.config = NETDATA_USER_CONFIG_DIR;

if(!netdata.options.paths.stock_config)
    netdata.options.paths.stock_config = NETDATA_STOCK_CONFIG_DIR;

// console.error('merged netdata object:');
// console.error(util.inspect(netdata, {depth: 10}));


// apply module paths to node.js process
function applyModulePaths() {
    var len = netdata.options.paths.modules.length;
    while(len--)
        process.mainModule.paths.unshift(netdata.options.paths.modules[len]);
}
applyModulePaths();


// --------------------------------------------------------------------------------------------------------------------
// tracing

function dumpError(err) {
    if (typeof err === 'object') {
        if (err.stack) {
            netdata.debug(err.stack);
        }
    }
}

// --------------------------------------------------------------------------------------------------------------------
// get command line arguments
{
    var found_myself = false;
    var found_number = false;
    var found_modules = false;
    process.argv.forEach(function (val, index, array) {
        netdata.debug('PARAM: ' + val);

        if(!found_myself) {
            if(val === __filename)
                found_myself = true;
        }
        else {
            switch(val) {
                case 'debug':
                    netdata.options.DEBUG = true;
                    netdata.debug('DEBUG enabled');
                    break;

                default:
                    if(found_number === true) {
                        if(found_modules === false) {
                            for(var i in netdata.options.modules)
                                netdata.options.modules[i].enabled = false;
                        }

                        if(typeof netdata.options.modules[val] === 'undefined')
                            netdata.options.modules[val] = {};

                        netdata.options.modules[val].enabled = true;
                        netdata.options.modules_enable_all = false;
                        netdata.debug('enabled module ' + val);
                    }
                    else {
                        try {
                            var x = parseInt(val);
                            if(x > 0) {
                                netdata.options.update_every = x;
                                if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
                                    netdata.options.update_every = NETDATA_UPDATE_EVERY;
                                    netdata.debug('Update frequency ' + x + 's is too low');
                                }

                                found_number = true;
                                netdata.debug('Update frequency set to ' + netdata.options.update_every + ' seconds');
                            }
                            else netdata.error('Ignoring parameter: ' + val);
                        }
                        catch(e) {
                            netdata.error('Cannot get value of parameter: ' + val);
                            dumpError(e);
                        }
                    }
                    break;
            }
        }
    });
}

if(netdata.options.update_every < 1) {
    netdata.debug('Adjusting update frequency to 1 second');
    netdata.options.update_every = 1;
}

// --------------------------------------------------------------------------------------------------------------------
// find modules

function findModules() {
    var found = 0;

    var files = fs.readdirSync(NODE_D_DIR);
    var len = files.length;
    while(len--) {
        var m = files[len].match('.node.js' + '$');
        if(m !== null) {
            var n = files[len].substring(0, m.index);

            if(typeof(netdata.options.modules[n]) === 'undefined')
                netdata.options.modules[n] = { name: n, enabled: netdata.options.modules_enable_all };

            if(netdata.options.modules[n].enabled === true) {
                netdata.options.modules[n].name = n;
                netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len];
                netdata.options.modules[n].loaded = false;

                // load the module
                try {
                    netdata.debug('loading module ' + netdata.options.modules[n].filename);
                    netdata.options.modules[n].module = require(netdata.options.modules[n].filename);
                    netdata.options.modules[n].module.name = n;
                    netdata.debug('loaded module ' + netdata.options.modules[n].name + ' from ' + netdata.options.modules[n].filename);
                }
                catch(e) {
                    netdata.options.modules[n].enabled = false;
                    netdata.error('Cannot load module: ' + netdata.options.modules[n].filename + ' exception: ' + e);
                    dumpError(e);
                    continue;
                }

                // load its configuration
                var c = {
                    enable_autodetect: netdata.options.modules_enable_autodetect,
                    update_every: netdata.options.update_every
                };

                var c2 = netdata_read_json_config_file(files[len]);
                extend(true, c, c2);

                // call module auto-detection / configuration
                try {
                    netdata.modules_configuring++;
                    netdata.debug('Configuring module ' + netdata.options.modules[n].name);
                    var serv = netdata.configure(netdata.options.modules[n].module, c, function() {
                        netdata.debug('Configured module ' + netdata.options.modules[n].name);
                        netdata.modules_configuring--;
                    });

                    netdata.debug('Configuring module ' + netdata.options.modules[n].name + ' reports ' + serv + ' eligible services.');
                }
                catch(e) {
                    netdata.modules_configuring--;
                    netdata.options.modules[n].enabled = false;
                    netdata.error('Failed module auto-detection: ' + netdata.options.modules[n].name + ' exception: ' + e + ', disabling module.');
                    dumpError(e);
                    continue;
                }

                netdata.options.modules[n].loaded = true;
                found++;
            }
        }
    }

    // netdata.debug(netdata.options.modules);
    return found;
}

if(findModules() === 0) {
    netdata.error('Cannot load any .node.js module from: ' + NODE_D_DIR);
    netdata.disableNodePlugin();
    process.exit(1);
}


// --------------------------------------------------------------------------------------------------------------------
// start

function start_when_configuring_ends() {
    if(netdata.modules_configuring > 0) {
        netdata.debug('Waiting modules configuration, still running ' + netdata.modules_configuring);
        setTimeout(start_when_configuring_ends, 500);
        return;
    }

    netdata.modules_configuring = 0;
    netdata.start();
}
start_when_configuring_ends();

//netdata.debug('netdata object:')
//netdata.debug(netdata);
