<?php


function is_xml_object($obj) {

    if (is_object($obj) && get_class($obj) == 'SimpleXMLElement')
        return true;

    return false;
}


// Gets value from array and give default
function grab_array_var($arr, $key, $default = '') {

    if (is_array($arr)) {
        if (isset($arr[$key]) || array_key_exists($key, $arr)) {
            return $arr[$key];
        }
    }

    return $default;
}


function random_string($len = 6, $additional_chars = '')
{
    $chars = "023456789abcdefghijklmnopqrstuv" . $additional_chars;
    $rnd = "";
    $charlen = strlen($chars);

    srand((double)microtime() * 1000000);

    for ($x = 0; $x < $len; $x++) {
        $num = rand() % $charlen;
        $ch = substr($chars, $num, 1);
        $rnd .= $ch;
    }

    return $rnd;
}


/**
 * A lot of times it is desirable to print a flash message and perform a callback and exit the script
 * This falls under the DRY category
 * flash_message_cb_and_exit() - flash a specific message, execute a callback, and cease script execution
 * @param string $callback - the function to execute (no arguments will be supplied to this function)
 * @param optional string $text The main text of the message to display
 * @param string $type The type of message: info, error, success
 * @param array $options The options for the message including details, persistent, dismissable, etc
 */
function flash_message_cb_and_exit($callback, $text = '', $type = 'info', $options = array()) {

    if (!empty($text))
        flash_message($text, $type, $options);

    if (!empty($callback)) {
        if (function_exists($callback)) {
            $callback();
        }
    }

    exit();
}

function reload_page($path, $fusionwindow = null, $base_dir = null, $exit = true) {

    if ($base_dir === null)
        $base_dir = get_base_url();

    $url = $base_dir;

    $url .= $path;

    if ($fusionwindow !== null)
        $url .= '?fusionwindow=' . $fusionwindow;

    echo '<script type="text/javascript">top.location="' . $url . '";</script>';

    if ($exit)
        exit();
}


/**
 *  Creates a new 'flash_message' to be displayed on the next page by default. It can also be set
 *  to be persistent accross multiple pages.
 *
 *  @param string $text The main text of the message to display
 *  @param string $type The type of message: info, error, success
 *  @param array $options The options for the message including details, persistent, dismissable, etc
 */
function flash_message($text, $type='info', $options=array())
{
    $valid_types = array('info', 'success', 'error');
    if (!in_array($type, $valid_types)) {
        $type = 'info';
    }

    // Create message array
    $msg = array(
        'message'       => $text,
        'type'          => $type,
        'persistent'    => false,
        'dismissable'   => true,
        );

    if (!empty($options)) {

        // Add details
        if (array_key_exists('details', $options)) {
            $msg['details'] = $options['details'];
        }

        // Persistence
        if (array_key_exists('persistent', $options)) {
            $msg['persistent'] = (bool) $options['persistent'];
        }

        // Dismissable
        if (array_key_exists('dismissable', $options)) {
            $msg['dismissable'] = (bool) $options['dismissable'];
        }

    }

    // Set session values
    $_SESSION['msg'] = $msg;
}


/**
 *  Generates the HTML for a flash message
 *
 *  @return string Full flash message HTML with details hidden if details exist
 */
function get_flash_message()
{
    $html = '';
    if (empty($_SESSION['msg'])) {
        return $html;
    } else {
        $msg = $_SESSION['msg'];
    }

    // Generate details html
    $details_html = '';
    if (!empty($msg['details'])) {
        $details_html = '<span class="msg-show-details">' . _('Show Details') . ' <i class="fa fa-chevron-up"></i></span>
            <div class="msg-details" style="margin-top: 20px; display: none;">' . $msg['details'] . '</div>';
    }

    // Can be dismissable
    $dismiss = '';
    if ($msg['dismissable']) {
        $dismiss = '<span class="msg-close tt-bind" onclick="$(this).parent().fadeOut(300);" title="' . _('Dismiss') . '" data-placement="left"><i class="fa fa-times"></i></span>';
    }

    // Generate full message
    $html = '<div id="head-msg" class="' . encode_html($msg['type']) . '">
                <span class="msg-text">
                    ' . $msg['message'] . '
                    ' . $details_html . '
                </span>
                ' . $dismiss . '
                <div class="clear"></div>
            </div>
            <script type="text/javascript">
            $(function() {
                $("body").on("click", ".msg-show-details", function() {
                    if ($(".msg-details").is(":visible")) {
                        $(".msg-show-details").html(' . json_encode(_('Show Details')) . ' + " <i class=\"fa fa-chevron-up\"></i>");
                        $(".msg-details").hide();
                    } else {
                        $(".msg-show-details").html(' . json_encode(_('Hide Details')) . ' + " <i class=\"fa fa-chevron-down\"></i>");
                        $(".msg-details").show();
                    }
                });
            });
            </script>';


    // Remove message
    if (!$msg['persistent']) {
        unset($_SESSION['msg']);
    }

    return $html;
}


function valid_email($email) {
    
    $ret = filter_var($email, FILTER_VALIDATE_EMAIL);
    if ($ret !== false)
        return true;

    // if we didn't validate an email, was because of a dotless domain name?
    // like: (localhost, machinename, etc)
    // these are valid for our purposes
    $at_pos = strrpos($email, '@');
    if ($at_pos !== false) {
        if (strpos(substr($email, $at_pos), '.') === false)
            return true;
    }

    return false;
}


function valid_url($url) {

    $ret = filter_var($url, FILTER_VALIDATE_URL);
    if ($ret !== false)
        return true;

    return false;
}


function get_root_dir() {

    global $cfg;

    $root_dir = '/usr/local/nagiosfusion';

    if (array_key_exists('root_dir', $cfg))
        $root_dir = $cfg['root_dir'];

    return $root_dir;
}


function get_base_dir() {

    $base_dir = get_root_dir() . '/html';

    if (defined('BACKEND') && BACKEND == true)
        $base_dir = substr($base_dir, 0, -8);

    return $base_dir;
}


function get_tmp_dir() {

    $tmp_dir = get_root_dir() . '/tmp';
    return $tmp_dir;
}


function get_scripts_dir() {

    $scripts_dir = get_root_dir() . '/scripts';
    return $scripts_dir;
}


function get_date_formats_as_array() {

    return array(
        DF_ISO8601  => 'YYYY-MM-DD HH:MM:SS',
        DF_US       => 'MM/DD/YYYY HH:MM:SS',
        DF_EURO     => 'DD/MM/YYYY HH:MM:SS',
        );
}


function get_number_formats_as_array() {

    return array(
        NF_1 => '1000.00',
        NF_2 => '1,000.00',
        NF_3 => '1.000,00',
        NF_4 => '1 000,00',
        NF_5 => "1'000,00",
        );
}


function one_line_print_r($arr) {

    $ret = '( ';

    foreach ($arr as $key => $val) {

        $ret .= "[{$key}] => ";

        if (is_array($val))
            $ret .= one_line_print_r($val);
        else
            $ret .= $val;

        $ret .= ', ';
    }

    $ret = rtrim($ret, ', ');
    $ret .= ' )';

    return $ret;
}

function is_selected($var1, $var2, $echo = true)
{
    $output = '';
    $selected = false;

    if (is_string($var1) || is_string($var2)) {
        if (!strcmp($var1, $var2)) {
            $selected = true;
        }
    } else if ($var1 == $var2) {
        $selected = true;
    }

    if ($selected)
        $output = ' selected="selected" ';

    if ($echo)
        echo $output;

    return $output;
}

function is_checked($var1, $var2 = true, $echo = true)
{
    $output = '';
    if ($var1 == $var2 || !strcmp($var1, $var2))
        $output = ' checked="checked" ';

    if ($echo)
        echo $output;

    return $output;
}


function checkbox_binary($var1)
{
    if (isset($var1)) {
        if (is_numeric($var1)) {
            if ($var1 == 1) {
                return 1;
            }
        } else if (is_string($var1) && $var1 == "on") {
            return 1;
        }
    }
    return 0;
}


function get_formatted_number($num = 0, $dec = -1, $format = NF_AUTO) {

    $str = "";

    // auto-determine decimal places
    if ($dec < 0) {
        if (is_string($num)) {
            $parts = explode(".", $num);
            $full = intval($parts[0]);
            $part = intval($parts[1]);
            $half = $part / pow(10, strlen($part));
            $num = ($full + $half);
            $dec = strlen($part);
        } else if (is_numeric($num))
            $dec = 0;
        else if (is_float($num))
            $dec = 4;
        else
            $dec = 0;
    }

    if ($format == NF_AUTO)
        $format = get_user_number_format();
    
    $format = intval($format);

    switch ($format) {
        case NF_1: // English (no commas)
            $str .= number_format(floatval($num), $dec, '.', '');
            break;
        case NF_3: // German
            $str .= number_format(floatval($num), $dec, ',', '.');
            break;
        case NF_4: // French
            $str .= number_format(floatval($num), $dec, ',', ' ');
            break;
        case NF_5: // Swiss
            $str .= number_format(floatval($num), $dec, ',', '\'');
            break;
        // default to English (w/ commas)
        default:
            $str .= number_format(floatval($num), $dec);
            break;
    }

    return $str;
}

function pack_array($arr) {

    if (!is_array($arr))
        return $arr;

    return base64_encode(serialize($arr));
}

function unpack_array($packed) {

    $decoded = base64_decode($packed);
    if ($decoded === false)
        return $packed;

    $unserialized = unserialize($decoded);
    if ($unserialized === false)
        return $packed;

    return $unserialized;
}

// works almost the same as array_replace_recursive except for 4 differences
// 1: the lhs operand is passed by reference
//    - this only makes a big difference with big arrays (funny thing, we have a lot of those in fusion)
// 2: we overwrite value instead of creating a subarray
//    - so whatever the value of a key is in arr2 (in main array or any sub array) will overwrite the same one in arr1
// 3: if keys are numeric, those arrays are merged (similarly to array_merge())
// 4: if values are numeric, they are added together (unless you disable this flag)
function array_append_recursive(&$arr1, $arr2, $sum_numeric_values = true) {

    foreach ($arr2 as $key => $value) {

        // if key is numeric, and exists in arr1
        // then we need to append this value instead of merge/replace/recursive
        if (is_numeric($key) && isset($arr1[$key])) {

            $max = max(array_keys($arr1));
            $arr1[$max + 1] = $value;
            continue;
        }

        // if both arr1[key] and arr2[key] are set and numeric
        // we add them together (if sum_numeric_values is true)
        if ($sum_numeric_values && is_numeric($value) && isset($arr1[$key]) && is_numeric($arr1[$key])) {

            $arr1[$key] += $value;
            continue;
        }

        // if arr1[key] isn't set
        // or if arr2[key] isn't an array
        // or if arr1[key] isn't an array
        // we just set the value and move on
        if (!isset($arr1[$key]) || !is_array($value) || !is_array($arr1[$key])) {

            $arr1[$key] = $value;
            continue;
        }

        array_append_recursive($arr1[$key], $value);
    }
}


// if you have more than 2 dependent fields, and one of the dependent arrays
// may have the same name as one of the others, you'll need to mask
// a good example in better words than that is in the perfgraph.inc.php dashlet include
function add_params_mask($str, $mask, $mask_seperator = '++') {
    return $mask . $mask_seperator . $str;
}

// use this to get rid of the params mask once the data has been passed to the dashlet
function remove_params_mask($str, $mask, $mask_seperator = '++') {
    return substr($str, strlen($mask . $mask_seperator));
}

// get the logo
// maybe it was overriden by customlogo? or some other component?
function get_nagios_logo() {

    $cbargs = null;
    do_callbacks(CALLBACK_FUSION_LOGO, $cbargs);

    $display_fusion_logo = true;
    if (isset($cbargs['display_fusion_logo']))
        $display_fusion_logo = $cbargs['display_fusion_logo'];

    $logo_img = get_base_url() . 'static/images/nagios_logo_white_transbg.png';
    if (isset($cbargs['logo_img']))
        $logo_img = $cbargs['logo_img'];

    $logo_text = ' ' . _('Fusion');
    if (isset($cbargs['logo_text']))
        $logo_text = $cbargs['logo_text'];

    $logo_alt = _('Nagios Fusion');
    if (isset($cbargs['logo_alt']))
        $logo_alt = $cbargs['logo_alt'];

    $logo_target = '_top';
    if (isset($cbargs['logo_target']))
        $logo_target = $cbargs['logo_target'];

    $logo_url = get_base_url();
    if (isset($cbargs['logo_url']))
        $logo_url = $cbargs['logo_url'];

    $fusion_logo = '<img src="' . get_base_url() . 'static/images/fusion-logo.png" border="0" class="fusion-logo">';
    if (!$display_fusion_logo)
        $fusion_logo = '';

    $logo_img = '<img src="' . $logo_img . '" class="xi-logo" border="0" alt="' . $logo_alt . '" title="' . $logo_alt . '">';


    $logo = '<a href="' . $logo_url . '" target="' . $logo_target . '">' . $logo_img . $logo_text . $fusion_logo . '</a>';

    return $logo;
}

// remove .. and / and \ from a filename
function sanitize_filename($filename) {

    $filename = str_replace('..', '', $filename);
    $filename = str_replace('/', '', $filename);
    $filename = str_replace('\\', '', $filename);

    return $filename;
}

function get_license_text() {

    $license_file = get_base_dir() . '/about/license.txt';

    $license = _('License text not found.');
    if (file_exists($license_file) && is_readable($license_file))
        $license = file_get_contents($license_file);

    return $license;
}

function get_slicense_text($needs_acknowledgement) {

    $slicense_file = get_base_dir() . '/about/slicense.txt';

    $slicense = _('License text not found.');
    if (file_exists($slicense_file) && is_readable($slicense_file))
        $slicense = file_get_contents($slicense_file);
        $nagios_link_text = '<a href="http://www.nagios.com" target="_blank" rel="noreferrer">www.nagios.com</a>';

        // make the link clickable
        $slicense = str_replace("www.nagios.com", $nagios_link_text, $slicense);
    
    return $slicense;
}

/**
 * Returns an array of available number formats
 *
 * @return  array   Available number formats
 */
function get_number_formats()
{
    $formats = array();
    $formats[NF_1] = _("1000.00");
    $formats[NF_2] = _("1,000.00");
    $formats[NF_3] = _("1.000,00");
    $formats[NF_4] = _("1 000,00");
    $formats[NF_5] = _("1'000,00");
    return $formats;
}

/**
 * Get an array of all the date/time formats available
 *
 * @return  array   Array of date/time formats available
 */
function get_date_formats()
{
    $formats = array();
    $formats[DF_ISO8601] = _("YYYY-MM-DD HH:MM:SS");
    $formats[DF_US] = _("MM/DD/YYYY HH:MM:SS");
    $formats[DF_EURO] = _("DD/MM/YYYY HH:MM:SS");
    return $formats;
}

/**
 * Check if the user has fips enabled on their server
 *
 * @return  boolean   Is fips enabled or not
 */
function get_fips_status() {
    $cmdline = sprintf("cat /proc/sys/crypto/fips_enabled");
    $output = array();
    exec($cmdline, $output, $return_code);
    
    $is_fips_enabled = 0;
    if ($output[0]) {
        $is_fips_enabled = $output[0];
    }
    
    return $is_fips_enabled;
}

/**
 * Build the fips warning banner
 *
 * @return  html   The html for the fips warning banner
 */
function get_fips_warning_banner($child=false) {
    if (!isset($_SESSION['ignore_fips_warning']) && isset($_SESSION['is_fips_enabled'])) {
        if ($child) {
            return '';
        } else {
            echo '<div class="contentheadernotice">'._('It appears FIPS mode is enabled on this system. Nagios Fusion does not support FIPS and having it enabled could negatively affect your user experience'). '!<div class="fr"><a href="#" id="closefipsnotice" title="'._("Close").'"><i class="fa fa-close"></i></a></div></div>';
        }
    }
}

/**
 * Build the refresh option for the server status pages
 *
 * @return  html   The html for the refresh option
 */
function get_server_status_refresh($child=false) {
    $refresh_rate = intval(get_option('status_pages_refresh_rate', 300));
	$refresh_rates = array(
		0   =>  "Don't Refresh",
        10       =>  '10s',
        30       =>  '30s', 
        60       =>  '1m',
        300      =>  '5m',
		600      =>  '10m',
        900      =>  '15m', 
        1800     =>  '30m',
	);

    return '
        <script>
            $(document).ready(function() {
                var active_status_refresh_timeout = "active_status_refresh_timeout"
                var refresh_rate =' . $refresh_rate . ' * 1000

                if (active_status_refresh_timeout && refresh_rate > 0) {
                    if (active_status_refresh_timeout)
                        clearTimeout(active_status_refresh_timeout);
                        active_status_refresh_timeout = setTimeout(function() { location.reload() }, refresh_rate);
                } else if (active_status_refresh_timeout && refresh_rate <= 0) {
                    if (active_status_refresh_timeout)
                        clearTimeout(active_status_refresh_timeout);            
                }
            });

            function update_page_refresh(refresh_rate) {
                post_ajax_data_with_callback("update_status_pages_refresh", {refresh_rate: refresh_rate}, function(){
                    location.reload()
                });
            }
        </script>
        <div class="fr" style="margin-left: auto; padding-left: 25px; display: flex; flex-direction: column;">
			<label for="status_refresh_rate" style="padding-bottom: 5px; min-width: 90px;">Refresh Rate:</label>
			<select name="status_refresh_rate" id="status_refresh_rate" class="dropdown form-control" onchange="update_page_refresh($(this).val())">
				' . get_options_from_array($refresh_rates, $refresh_rate) . '
			</select>
		</div>
    ';
}

/**
 * Replaces passed macro args inside a string of text
 *
 * @param   string  $text
 * @param   array   $args
 * @return  string
 */
function replace_array_macros($text, $args)
{
    foreach ($args as $var => $val) {
        $tvar = "%" . $var . "%";
        $text = str_replace($tvar, $val, $text);
    }
    return $text;
}