<?php

register_fusioncore();
function register_fusioncore() {

	$component_args = array(

        COMPONENT_TYPE              => COMPONENT_CORE,
        COMPONENT_NAME              => 'fusioncore',
        COMPONENT_TITLE             => _('Nagios Fusion Core Component'),
        COMPONENT_VERSION           => '5.0.3',
        COMPONENT_DATE              => '01/25/2018',
        COMPONENT_AUTHOR            => 'Nagios Enterprises, LLC',
        COMPONENT_DESCRIPTION       => _('Provides core functions, callbacks, polling mechanisms and interface functionality for Nagios Fusion'),
        COMPONENT_REQUIRES_VERSION  => 5003,

        COMPONENT_FUNCTION          => 'fusioncore_successful_registration',
    );

    register_component($component_args);
}

function fusioncore_successful_registration() {

    register_fusioncore_poll_types();
    register_fusioncore_callbacks();
    register_fusioncore_polling_callbacks();
}

function register_fusioncore_menu($cb, &$menu) {

    $menu->add_link(menu_link(_('Tactical Overview'), 'includes/components/fusioncore/tactical_overview.php'), 'home-server-status');
    $menu->add_link(menu_link(_('Tactical Summary'), 'includes/components/fusioncore/tactical_summary.php'), 'home-server-status');

    $menu->add_link(menu_link(_('Recent Alerts'), 'includes/components/fusioncore/recent_alerts.php'), 'home-alerts');
    $menu->add_link(menu_link(_('Top Alert Producers'), 'includes/components/fusioncore/top_alerts.php'), 'home-alerts');

    $menu->add_link(menu_link(_('Host Health'), 'includes/components/fusioncore/host_health.php'), 'home-visualizations');
    $menu->add_link(menu_link(_('Service Health'), 'includes/components/fusioncore/service_health.php'), 'home-visualizations');
}

// register callbacks for fusion functionality
function register_fusioncore_callbacks() {

    register_callback(CALLBACK_MENU_INITIALIZED, 'register_fusioncore_menu');
    register_callback(CALLBACK_USER_CREATED, 'fusioncore_user_created');
    register_callback(CALLBACK_FOOTER_CONTENT_START, 'fusioncore_auto_logins');
    register_callback(CALLBACK_POLLED_POST, 'fusioncore_generate_dashlet_param_options');
    register_callback(CALLBACK_DBMAINT, 'fusioncore_delete_unnecessary_polled_extras');
}

// when a new user is created we need to do a few things
function fusioncore_user_created($cb, &$cbargs) {

    // create default views
    if (!empty($cbargs['user_id'])) {

        $user_id = intval($cbargs['user_id']);

        $default_views = get_default_views();
        foreach ($default_views as $view) {

            add_view($view['view_url'], $view['view_title'], $user_id);
        }
    }
}

// we create the param lists for the dashlets during each poll
// so that they don't have to be created on each page load everytime
// this normally isn't a big deal, but a few systems with 10k or more checks
// and it becomes a noticable problem quickly
function fusioncore_generate_dashlet_param_options($cb, &$cbargs) {

    // build a simple hosts array
    if (isset($cbargs['data']['host_status']) && is_array($cbargs['data']['host_status'])) {
        $cbargs['data']['dashlets_params_simple_hosts'] = array();
        foreach($cbargs['data']['host_status'] as $host_name => $host) {
            $cbargs['data']['dashlets_params_simple_hosts'][$host_name] = $host_name;
        }
    }

    // build simple hostgroups array
    if (isset($cbargs['data']['hostgroup_members']) && is_array($cbargs['data']['hostgroup_members'])) {
        $cbargs['data']['dashlets_params_simple_hostgroups'] = array();
        foreach($cbargs['data']['hostgroup_members'] as $hostgroup_name => $hostgroup) {
            $cbargs['data']['dashlets_params_simple_hostgroups'][$hostgroup_name] = $hostgroup_name;
        }
    }

    // build simple servicegroups array
    if (isset($cbargs['data']['servicegroup_members']) && is_array($cbargs['data']['servicegroup_members'])) {
        $cbargs['data']['dashlets_params_simple_servicegroups'] = array();
        foreach($cbargs['data']['servicegroup_members'] as $servicegroup_name => $servicegroup) {
            $cbargs['data']['dashlets_params_simple_servicegroups'][$servicegroup_name] = $servicegroup_name;
        }
    }

    // build advanced hosts/services array (utilizing add_params_mask)
    // this is necessary for any dashlet dropdown that utilizes a server > host > service dependency heirarchy (e.g.: perfgraph)
    if (isset($cbargs['server_id']) && isset($cbargs['data']['service_status']) && is_array($cbargs['data']['service_status'])) {

        $server_id = $cbargs['server_id'];

        $cbargs['data']['dashlets_params_masked_hosts'] = array();
        $cbargs['data']['dashlets_params_masked_services'] = array();

        foreach($cbargs['data']['service_status'] as $host => $svcs) {

            $cbargs['data']['dashlets_params_masked_hosts'][add_params_mask($host, $server_id)] = $host;
            foreach ($svcs as $service_description => $service) {
                $cbargs['data']['dashlets_params_masked_services'][add_params_mask($host, $server_id)][$service_description] = $service_description;
            }
        }
    }

    if (isset($cbargs['data']['nna_sources']) && is_array($cbargs['data']['nna_sources'])) {
        $cbargs['data']['dashlets_params_masked_sources'] = array();
        foreach($cbargs['data']['nna_sources'] as $source) {
            $cbargs['data']['dashlets_params_masked_sources'][$source['name']] = $source['name'];
        }
    }
}

// there are quite a few polled_extras we don't need to keep more than 1 of at any given time
// so we just delete them regularly
function fusioncore_delete_unnecessary_polled_extras($cb, $cbargs) {

    global $db;

    $unnecessary_polled_extra_poll_keys = array(
        'host_status',
        'service_status',
        'hostgroup_members',
        'servicegroup_members',
        'users',
        'info',
        'bpi',
        'dashlets_params_simple_hosts',
        'dashlets_params_simple_hostgroups',
        'dashlets_params_simple_servicegroups',
        'dashlets_params_masked_hosts',
        'dashlets_params_masked_services',
        'nna_sources',
        'nna_sources_bandwidth',
        'nna_cpu',
        'nna_memory',
        'nna_root_drive',
        'nna_alerts',
        'dashlets_params_masked_sources'
        );

    $deleted = 0;

    foreach (get_servers() as $server) {

        $mapped_users = get_server_mapped_users($server);
        if (!is_array($mapped_users) || empty($mapped_users))
            $mapped_users = array();

        // check each mapped user
        foreach ($mapped_users as $user) {

            // get the polled_data_id for this combo
            $bind_array = array(
                ':server_id' => $server['server_id'],
                ':username' => $user,
                );

            $polled_data_id = $db->exec_query('SELECT polled_data_id 
                FROM polled_data 
                WHERE server_id = :server_id 
                AND username = :username 
                ORDER BY polled_time DESC
                LIMIT 1', $bind_array);

            if ($polled_data_id) {
                $polled_data_id = $polled_data_id[0]['polled_data_id'];
            } else {
                log_debug(LOG_TYPE_SYSTEM, "fusioncore_delete_unnecessary_polled_extras(): unable to grab polled_data_id for server = {$server['server_id']}, user = {$user}");
                continue;
            }

            // now we cycle through our list of deletable poll_keys
            // and get rid of any of them that point to a polled_data_id less than this
            // we don't want to delete any that may have been created during this check

            $bind_array[':polled_data_id'] = $polled_data_id;

            foreach ($unnecessary_polled_extra_poll_keys as $poll_key) {

                $bind_array[':poll_key'] = $poll_key;

                $poll_key_deleted = $db->exec_query('DELETE 
                    FROM polled_extras
                    WHERE polled_data_id < :polled_data_id
                    AND poll_key = :poll_key
                    AND polled_data_id 
                    IN (
                        SELECT polled_data_id
                        FROM polled_data 
                        WHERE server_id = :server_id 
                        AND username = :username 
                    )', $bind_array);

                if (!is_numeric($poll_key_deleted))
                    log_debug(LOG_TYPE_SYSTEM, "fusioncore_delete_unnecessary_polled_extras(): unable to execute: polled_data_id < {$polled_data_id}, poll_key = {$poll_key}");
                else
                    $deleted += $poll_key_deleted;
            }
        }
    }
    // Optimize table after clearing unnecessary polled_extras data to reclaim disk space
    $db->exec_query('OPTIMIZE TABLE polled_extras');

    log_debug(LOG_TYPE_SYSTEM, "fusioncore_delete_unnecessary_polled_extras(): deleted {$deleted} rows from polled_extras");
}

function fusioncore_auto_logins($cb, $cbargs) {

    // make sure we are logged in, and on a parent page
    if (is_authenticated() && isset($cbargs['child']) && $cbargs['child'] == false) {

        $global_auto_login = get_option('auto_login');
        if (!empty($global_auto_login) || true) {

            $auto_login_interval = 5 * 60; // 5 min

            $auto_logins = get_auto_logins();
            foreach ($auto_logins as $index => $auto_login) {

                $username = $auto_login['username'];
                $password = _decrypt($auto_login['password']);

                $server_id = $auto_login['server_id'];
                $server = get_server($server_id);

                if ($server === false)
                    continue;

                $url = get_server_base_url($server, false, $username, $password);

                switch ($server['server_type']) {

                    case SERVER_TYPE_XI:
                        // Check for 5.5+
                        // If we are on 5.5 or later, we need to use auth token authentication
                        $version = get_version($server_id);
                        if (version_compare($version, '5.5.0', '>=') > 0 || strtolower($version) == 'cloud') {
                            // Due to CORS issues, Fusion to XI auto-login has to be handled differently and has been moved to header.parent.inc.php:261-283 - AC
                            
                        } else {
                            $check_url = $url . "backend/?cmd=getProgramstatus";
                            $url .= "backend/?cmd=invalid&username={$username}&password=" . md5($password) . "&req_frame_access=" . $_SERVER['SERVER_ADDR'];
                        }

                        // create url with auth token
                        // proceed as usual
                        break;

                    case SERVER_TYPE_CORE:
                        $check_url = '';
                        $url .= "images/enabled.gif";
                        echo '<img class="auto_login" src="' . $url . '" data-server-id="'.$auto_login['server_id'].'" data-check="'.$check_url.'" data-src="' . $url . '" />';
                        break;

                    default:
                        continue 2;
                }
            }

            echo '
                <script type="text/javascript">
                $(function() {
                    validate_auto_logins();
                    setInterval("update_auto_logins", ' . ($auto_login_interval * 1000) . ');
                });

                function update_auto_logins() {
                    $("img.auto_login").each(function() {
                        $(this).attr("src", $(this).data("src") + "?r=" + Math.random());
                    });
                    validate_auto_logins();
                }

                function validate_auto_logins() {
                    $("img.auto_login").each(function() {
                        var server_id = $(this).data("server-id");
                        /*
                        $.get($(this).data("check"), {}, function(data) {
                            var x = $("#server-al-"+server_id+" span i");
                            if ($(data).find("errormessage").text() == "Authentication Failure") {
                                x.removeClass("fa-check").addClass("fa-times");
                                $("#server-al-"+server_id+" span").attr("title", "'._("Could not login").'").tooltip("fixTitle");
                            } else {
                                console.log(x.hasClass("fa-times"));
                                if (x.hasClass("fa-times")) {
                                    x.removeClass("fa-times").addClass("fa-check");
                                    $("#server-al-"+server_id+" span").attr("title", "'._("Auto logged in").'").tooltip("fixTitle");
                                }
                            }
                        });
                        */
                    });
                }
                </script>';
        }
    }
}

// register our necessary poll types
function register_fusioncore_poll_types() {

    register_poll_type(
        POLL_TYPE_INFO, 
        "api/v1/system/info",
        "backend/?cmd=getProductInfo",
        "",
        "",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );

    register_poll_type(
        POLL_TYPE_HOSTSTATUS, 
        "api/v1/objects/hoststatus",
        "backend/?cmd=getHostStatus",
        "statusjson.cgi?query=hostlist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ true,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_SERVICESTATUS, 
        "api/v1/objects/servicestatus",
        "backend/?cmd=getServiceStatus",
        "statusjson.cgi?query=servicelist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ true,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );
    
    /*
    $logentry_type_list = '1024,2048,4096,8192,32768,65536,16384';
    $logentry_type_list = implode(',', array(
        NSLOG_HOST_UP, NSLOG_HOST_DOWN, NSLOG_HOST_UNREACHABLE,
        NSLOG_SERVICE_OK, NSLOG_SERVICE_WARNING, NSLOG_SERVICE_CRITICAL, NSLOG_SERVICE_UNKNOWN,
        ));
    */

    register_poll_type(
        POLL_TYPE_ALERTS, 
        "api/v1/objects/logentries?logentry_type=in:1024,2048,4096,8192,32768,65536,16384",
        "backend/?cmd=getLogEntries?logentry_type=in:1024,2048,4096,8192,32768,65536,16384",
        "archivejson.cgi?query=alertlist",
        "api/backend/nagioslogserver/alert/_search",
        "api/checks/read",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_ALERT_HISTORY,
        "",
        "",
        "",
        "api/backend/nagioslogserver_history_alert/_search?sort=ran:desc&size=100",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_CLUSTER_HEALTH, 
        "",
        "",
        "",
        "api/backend/_cluster/health",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_CLUSTER_STATS, 
        "",
        "",
        "",
        "api/backend/_cluster/stats",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_INDEX_STATS, 
        "",
        "",
        "",
        "api/backend/_all/_stats/docs,store,indexing,get,search/",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_SNMP_RECEIVERS, 
        "",
        "",
        "",
        "api/check/get_snmp_receivers",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_NRDP_SERVERS, 
        "",
        "",
        "",
        "api/check/get_nrdp",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    /*
    $logentry_type_list = '524288,1048576';
    $logentry_type_list = implode(',', array(
        NSLOG_HOST_NOTIFICATION, NSLOG_SERVICE_NOTIFICATION,
        ));
    */

    register_poll_type(
        POLL_TYPE_NOTIFICATIONS, 
        "api/v1/objects/logentries?logentry_type=in:524288,1048576",
        "backend/?cmd=getLogEntries?logentry_type=in:524288,1048576",
        "archivejson.cgi?query=notificationlist",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ true,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_COMMENT, 
        "api/v1/objects/comment",
        "backend/?cmd=getComments",
        "statusjson.cgi?query=commentlist",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_DOWNTIME, 
        "api/v1/objects/downtime",
        "backend/?cmd=getScheduledDowntime",
        "statusjson.cgi?query=downtimelist",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_CONTACT, 
        "api/v1/objects/contact",
        "backend/?cmd=getContacts",
        "objectjson.cgi?query=contactlist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_HOST, 
        "api/v1/objects/host",
        "backend/?cmd=getHosts",
        "objectjson.cgi?query=hostlist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_SERVICE, 
        "api/v1/objects/service",
        "backend/?cmd=getServices",
        "objectjson.cgi?query=servicelist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_HOSTGROUP, 
        "api/v1/objects/hostgroup",
        "backend/?cmd=getHostgroups",
        "objectjson.cgi?query=hostgrouplist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_SERVICEGROUP, 
        "api/v1/objects/servicegroup",
        "backend/?cmd=getServicegroups",
        "objectjson.cgi?query=servicegrouplist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_CONTACTGROUP, 
        "api/v1/objects/contactgroup",
        "backend/?cmd=getContactgroups",
        "objectjson.cgi?query=contactgrouplist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_HOSTGROUPMEMBERS, 
        "api/v1/objects/hostgroupmembers",
        "backend/?cmd=getHostgroupMembers",
        "objectjson.cgi?query=hostgrouplist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_SERVICEGROUPMEMBERS, 
        "api/v1/objects/servicegroupmembers",
        "backend/?cmd=getServicegroupMembers",
        "objectjson.cgi?query=servicegrouplist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_CONTACTGROUPMEMBERS, 
        "api/v1/objects/contactgroupmembers",
        "backend/?cmd=getContactgroupMembers",
        "objectjson.cgi?query=contactgrouplist&details=true",
        "",
        /* $records = */ true,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ true
    );

    register_poll_type(
        POLL_TYPE_STATUS, 
        "api/v1/system/status",
        "backend/?cmd=getProgramStatus",
        "statusjson.cgi?query=programstatus",
        "",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );

    register_poll_type(
        POLL_TYPE_USER, 
        "api/v1/system/user",
        "backend/?cmd=getUsers",
        "",
        "api/user/get_all_users",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );
    
    register_poll_type (
        POLL_TYPE_NNA_SOURCES, 
        "",
        "",
        "",
        "",
        "api/sources/read",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );
    
    register_poll_type (
        POLL_TYPE_NNA_SOURCES_BANDWIDTH, 
        "",
        "",
        "",
        "",
        "api/graphs/execute_all",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );
    
    register_poll_type (
        POLL_TYPE_NNA_CPU, 
        "",
        "",
        "",
        "",
        "api/system/cpu_status",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );
    
    register_poll_type (
        POLL_TYPE_NNA_MEMORY, 
        "",
        "",
        "",
        "",
        "api/system/memory_status",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );
    
    register_poll_type (
        POLL_TYPE_NNA_ROOT_DRIVE, 
        "",
        "",
        "",
        "",
        "api/system/root_drive_status",
        /* $records = */ false,
        /* $brevity = */ false,
        /* $time_limits = */ false,
        /* $fusekey_specify_user = */ false
    );

}

/*

in mysql, run the following insert statement:
 insert into servers (server_id, name, address, server_type, authentication_type, url, logserver_token, username) values (89, 'LogServer', '192.168.124.102', 8, 3, 'http://192.168.124.102/nagioslogserver/', 'e892b2b34a76ae85941c5c10aa62af53257c9bc3', 'nagiosadmin');

and then run

php /usr/local/nagiosfusion/cron/poll_subsys.php --server 89 --user nagiosadmin --debug


*/

// register our core component polling related callbacks
function register_fusioncore_polling_callbacks() {

    // include necessary files
    $fusioncore_dir = get_component_dir_base('fusioncore');
    require_once("{$fusioncore_dir}/poll_callbacks/hoststatus.php");
    require_once("{$fusioncore_dir}/poll_callbacks/servicestatus.php");
    require_once("{$fusioncore_dir}/poll_callbacks/status.php");
    require_once("{$fusioncore_dir}/poll_callbacks/info.php");
    require_once("{$fusioncore_dir}/poll_callbacks/user.php");
    require_once("{$fusioncore_dir}/poll_callbacks/alerts.php");
    require_once("{$fusioncore_dir}/poll_callbacks/stats.php");
    require_once("{$fusioncore_dir}/poll_callbacks/sources.php");
    require_once("{$fusioncore_dir}/poll_callbacks/hostgroupmembers.php");
    require_once("{$fusioncore_dir}/poll_callbacks/servicegroupmembers.php");
    require_once("{$fusioncore_dir}/poll_callbacks/hostgroup.php");
    require_once("{$fusioncore_dir}/poll_callbacks/servicegroup.php");

    // register poll callbacks    
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_HOSTSTATUS, 'fusioncore_poll_hoststatus');
    register_poll_callback(SERVER_TYPE_CORE, POLL_TYPE_HOSTSTATUS, 'fusioncore_poll_hoststatus');

    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_SERVICESTATUS, 'fusioncore_poll_servicestatus');
    register_poll_callback(SERVER_TYPE_CORE, POLL_TYPE_SERVICESTATUS, 'fusioncore_poll_servicestatus');

    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_STATUS, 'fusioncore_poll_status');
    register_poll_callback(SERVER_TYPE_CORE, POLL_TYPE_STATUS, 'fusioncore_poll_status');

    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_USER, 'fusioncore_users');
    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_USER, 'nls_users');

    register_poll_callback(SERVER_TYPE_XI,  POLL_TYPE_INFO, 'xi_info');

    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_ALERTS, 'fusioncore_poll_alerts');
    register_poll_callback(SERVER_TYPE_CORE, POLL_TYPE_ALERTS, 'fusioncore_poll_alerts');
    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_ALERTS, 'nls_alerts');
    register_poll_callback(SERVER_TYPE_NNA,  POLL_TYPE_ALERTS, 'nna_alerts');

    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_ALERT_HISTORY, 'nls_alert_history');

    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_CLUSTER_HEALTH, 'nls_cluster_health');

    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_CLUSTER_STATS, 'nls_cluster_stats');

    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_INDEX_STATS, 'nls_index_stats');

    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_SNMP_RECEIVERS, 'nls_snmp_receivers');

    register_poll_callback(SERVER_TYPE_NLS,  POLL_TYPE_NRDP_SERVERS, 'nls_nrdp_servers');
    
    // NNA INTEGRATION
    register_poll_callback(SERVER_TYPE_NNA,  POLL_TYPE_NNA_SOURCES, 'nna_sources_f');
    register_poll_callback(SERVER_TYPE_NNA,  POLL_TYPE_NNA_SOURCES_BANDWIDTH, 'nna_sources_bandwidth_f');
    register_poll_callback(SERVER_TYPE_NNA,  POLL_TYPE_NNA_CPU, 'nna_cpu_stats');
    register_poll_callback(SERVER_TYPE_NNA,  POLL_TYPE_NNA_MEMORY, 'nna_memory_stats');
    register_poll_callback(SERVER_TYPE_NNA,  POLL_TYPE_NNA_ROOT_DRIVE, 'nna_root_drive_stats');
    
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_HOSTGROUPMEMBERS, 'fusioncore_poll_hostgroupmembers');
    register_poll_callback(SERVER_TYPE_CORE, POLL_TYPE_HOSTGROUPMEMBERS, 'fusioncore_poll_hostgroupmembers');

    // TODO:
    // we use these to override the alias - since xi doesn't supply it when getting the hostgroup members data
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_HOSTGROUP,    'fusioncore_poll_hostgroup');
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_SERVICEGROUP, 'fusioncore_poll_servicegroup');

    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_SERVICEGROUPMEMBERS, 'fusioncore_poll_servicegroupmembers');
    register_poll_callback(SERVER_TYPE_CORE, POLL_TYPE_SERVICEGROUPMEMBERS, 'fusioncore_poll_servicegroupmembers');

    // PLANNED FOR A FUTURE RELEASE:
    // register_poll_callback(SERVER_TYPE_XI, POLL_TYPE_NOTIFICATIONS, 'fusioncore_poll_notifications');
    // register_poll_callback(SERVER_TYPE_CORE, POLL_TYPE_NOTIFICATIONS, 'fusioncore_poll_notifications');

    /*
    some examples:
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_ALERTS);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_NOTIFICATIONS);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_STATEHISTORY);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_COMMENT);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_DOWNTIME);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_CONTACT);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_HOST);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_SERVICE);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_HOSTGROUP);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_SERVICEGROUP);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_CONTACTGROUP);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_HOSTGROUPMEMBERS);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_SERVICEGROUPMEMBERS);
    register_poll_callback(SERVER_TYPE_XI,   POLL_TYPE_CONTACTGROUPMEMBERS);
    */

    // set averages/deltas we know we want to track
    /*
    register_poll_average('hosts_count');
    register_poll_delta('hosts_count');

    register_poll_average('hosts_up');
    register_poll_delta('hosts_up');
    */

    // register callbacks for pre and post poll
    register_callback(CALLBACK_POLLED_PRE, 'fusioncore_polled_pre_callback');
    register_callback(CALLBACK_POLLED_POST, 'fusioncore_polled_post_callback');
}

// callback right before server is polled
// args is array('server' => $server_array, 'user' => $username_connecting_to_server)
function fusioncore_polled_pre_callback($cbtype, &$args) {

}

// callback right after server was polled
// args is the return array from poll_server() function
function fusioncore_polled_post_callback($cbtype, &$args) {

    fusioncore_calculate_averages($args);
    fusioncore_calculate_deltas($args);

    /*

    echo "\n*****\nFUSIONCORE POLLED POST CALLBACK\n";
    print_r($args);
    echo "*****\n";

    */
}

// calculate all registered keys for determining averages
// via register_poll_average($key)
// will append subarray to $args like this: 
// $args['averages'][KEYNAME] = array(
//    'average' => average_value,
//    'count' => count,
//    );
// TODO: fix naming inconsitencies between poll_averages and polled_averages and same for deltas
function fusioncore_calculate_averages(&$args) {

    global $poll_averages;

    if (!isset($poll_averages) || !is_array($poll_averages))
        return;
 
    if (is_array($poll_averages) && count($poll_averages) == 0)
        return;

    $server_id = $args['server_id'];
    $username = $args['username'];
    $data = $args['data'];

    global $db;

    foreach ($poll_averages as $poll_key) {

        if (empty($poll_key) || (!is_string($poll_key) && !is_numeric($poll_key)))
            continue;

        // if our registered key doesn't exist in the $data array
        // or if it contains a non numeric value
        if (!isset($data[$poll_key]) || !is_numeric($data[$poll_key]))
            continue;

        $bind_array = array(
            ':server_id'  => $server_id,
            ':username'   => $username,
            ':poll_key'   => $poll_key,
            );
        $averages_rows = $db->exec_query('SELECT * FROM polled_averages 
            WHERE server_id = :server_id AND username = :username AND poll_key = :poll_key', $bind_array);

        if ($averages_rows === false)
            continue;

        // if $args doesn't already have an averages sub array..
        if (!isset($args['averages']))
            $args['averages'] = array();

        $current_value = $data[$poll_key];

        if (count($averages_rows) == 0) {

            // how exciting! no average existed yet! the dawn of a new era!
            $args['averages'][$poll_key] = array(
                'count'         => 1,
                'average_value' => $current_value,
                );

        } else {

            // well we need to get the data to calculate the new average
            $count = $averages_rows[0]['count'];
            $average = $averages_rows[0]['average_value'];

            $new_count = $count + 1;
            $new_average = ($average * $count + $current_value) / $new_count;

            $args['averages'][$poll_key] = array(
                'count'         => $new_count,
                'average_value' => $new_average,
                );
        }
    }
}

// calculate all registered keys for determining deltas
// via register_poll_delta($key)
// will append subarray to $args like this: 
// $args['deltas'][KEYNAME] = array(
//    'delta' => [change from last value]
//    );
function fusioncore_calculate_deltas(&$args) {

    global $poll_deltas;

    if (!isset($poll_deltas) || !is_array($poll_deltas))
        return;
 
    if (is_array($poll_deltas) && count($poll_deltas) == 0)
        return;

    $server_id = $args['server_id'];
    $username = $args['username'];
    $data = $args['data'];

    global $db;

    // first we need to see if we even have any existing polled data
    // based on our current criteria
    $bind_array = array(
        ':server_id'  => $server_id,
        ':username'   => $username,
        );
    $polled_rows = $db->exec_query('SELECT * FROM polled_data 
        WHERE server_id = :server_id AND username = :username ORDER BY polled_time DESC LIMIT 1', $bind_array);

    if ($polled_rows === false || (is_array($polled_rows) && count($polled_rows) == 0))
        return;

    foreach ($poll_deltas as $poll_key) {

        if (empty($poll_key) || (!is_string($poll_key) && !is_numeric($poll_key)))
            continue;

        // if our registered key doesn't exist in the $data array
        // or if it contains a non numeric value
        if (!isset($data[$poll_key]) || !is_numeric($data[$poll_key]))
            continue;

        $current_value = $data[$poll_key];
        $last_polled_value = null;

        // check if our poll_key exists as one of the columns from our polled_rows select earlier        
        if (isset($polled_rows[0][$poll_key]) && is_numeric($polled_rows[0][$poll_key])) {

            $last_polled_value = $polled_rows[0][$poll_key];

        } else {

            // if it doesn't, then we need to attempt a different sql query to try and find it
            $polled_data_id = $polled_rows[0]['polled_data_id'];
            $bind_array = array(
                ':polled_data_id'   => $polled_data_id,
                ':poll_key'         => $poll_key,
                );
            $polled_extras_rows = $db->exec_query('SELECT extra_value FROM polled_extras 
                WHERE polled_data_id = :polled_data_id AND poll_key = :poll_key LIMIT 1', $bind_array);

            if (is_array($polled_extras_rows) && count($polled_extras_rows) > 0) {
                if (is_numeric($polled_extras_rows[0]['extra_value'])) {
                    $last_polled_value = $polled_extras_rows[0]['extra_value'];
                }
            }
        }

        // if we didn't get a last polled value we have nothing to compare to..
        if ($last_polled_value === null)
            continue;

        // if $args doesn't already have a deltas sub array..
        if (!isset($args['deltas']))
            $args['deltas'] = array();

        $args['deltas'][$poll_key] = array(
            'delta' => $current_value - $last_polled_value,
            );
    }
}


// used for generating links in tactical overview and summary
function get_tactical_link($data, $server, $xi_url = '', $core_url = '') {

    $server = get_server($server);
    if ($server === false)
        return $data;

    $url = get_server_base_url($server, $core_include_cgi = true, $core_username = '', $core_password = '', $include_basic_credentials = false);
    $orig_url = $url;

    $server_type = $server['server_type'];
    $authentication_type = $server['authentication_type'];

    $url = get_appended_server_url($url, $server_type, $authentication_type, $xi_url, $xi_url, $core_url);

    if ($orig_url == $url)
        $url = '';

    if ($server['server_type'] == SERVER_TYPE_XI)
        $url = $orig_url . '?xiwindow=' . urlencode($url);

    if (!empty($url))
        return '<a href="' . $url . '" target="_blank">' . $data . '</a>';

    return $data;
}


function alert_list_to_human_readable($val) {

    if (isset($val['alert_list']))
        $val['alert_list'] = unpack_array($val['alert_list']);

    return $val;
}

