<?php
//
// Time utility functions
// Copyright (c) 2014-2018 Nagios Enterprises, LLC. All rights reserved.
//


/**
 * String to time alternative. This checks the users current settings for time and then
 * calculates the timestamp based off that. This is useful since strtotime() cannot convert
 * strings that use the DD/MM/YYYY format.
 *
 * @param   string  $val    The MM/DD/YYYY string value to convert to timestamp 
 * @return  int             The converted timestamp value
 */
function nstrtotime($val)
{
    if (empty($val)) { return $val; }

    // Get timezone datepicker format
    if (isset($_SESSION['date_format'])) {
        $format = $_SESSION['date_format'];
    } else {
        if (is_null($format = get_user_meta('date_format'))) {
            $format = get_option('default_date_format');
        }
    }
    
    // Set the date format to the user's preference so we can convert properly
    // Y-m-d H:i:s
    if ($format == DF_ISO8601 || strpos($val, '-') == 4) {
        $ts = strtotime($val);
    // m/d/Y H:i:s
    } else if ($format == DF_US) {
        list($d, $t) = explode(' ', $val);
        list($month, $day, $year) = explode('/', $d);
        $v = explode(':', $t);
        $hour = $v[0];
        $min = $v[1];
        if (array_key_exists(2, $v)) {
            $sec = $v[2];
        }
        $ts = mktime($hour, $min, $sec, $month, $day, $year);
    // d/m/Y H:i:s
    } else if ($format == DF_EURO) {
        list($d, $t) = explode(' ', $val);
        list($day, $month, $year) = explode('/', $d);
        $v = explode(':', $t);
        $hour = $v[0];
        $min = $v[1];
        if (array_key_exists(2, $v)) {
            $sec = $v[2];
        }
        $ts = mktime($hour, $min, $sec, $month, $day, $year);
    }

    return $ts;
}


/**
 * Returns an array of all available timezones with proper names
 *
 * @return  array       List of available timezones
 */
function get_timezones()
{
    return array(
        '(UTC-11:00) Midway Island' => 'Pacific/Midway',
        '(UTC-11:00) Samoa' => 'Pacific/Samoa',
        '(UTC-10:00) Hawaii' => 'Pacific/Honolulu',
        '(UTC-09:00) Alaska' => 'US/Alaska',
        '(UTC-08:00) Pacific Time (US &amp; Canada)' => 'America/Los_Angeles',
        '(UTC-08:00) Tijuana' => 'America/Tijuana',
        '(UTC-07:00) Arizona' => 'US/Arizona',
        '(UTC-07:00) Chihuahua' => 'America/Chihuahua',
        '(UTC-07:00) La Paz' => 'America/Chihuahua',
        '(UTC-07:00) Mazatlan' => 'America/Mazatlan',
        '(UTC-07:00) Mountain Time (US &amp; Canada)' => 'US/Mountain',
        '(UTC-06:00) Central America' => 'America/Managua',
        '(UTC-06:00) Central Time (US &amp; Canada)' => 'US/Central',
        '(UTC-06:00) Guadalajara' => 'America/Mexico_City',
        '(UTC-06:00) Mexico City' => 'America/Mexico_City',
        '(UTC-06:00) Monterrey' => 'America/Monterrey',
        '(UTC-06:00) Saskatchewan' => 'Canada/Saskatchewan',
        '(UTC-05:00) Bogota' => 'America/Bogota',
        '(UTC-05:00) Eastern Time (US &amp; Canada)' => 'US/Eastern',
        '(UTC-05:00) Indiana (East)' => 'US/East-Indiana',
        '(UTC-05:00) Lima' => 'America/Lima',
        '(UTC-05:00) Quito' => 'America/Bogota',
        '(UTC-04:00) Atlantic Time (Canada)' => 'Canada/Atlantic',
        '(UTC-04:30) Caracas' => 'America/Caracas',
        '(UTC-04:00) La Paz' => 'America/La_Paz',
        '(UTC-04:00) Santiago' => 'America/Santiago',
        '(UTC-03:30) Newfoundland' => 'Canada/Newfoundland',
        '(UTC-03:00) Brasilia' => 'America/Sao_Paulo',
        '(UTC-03:00) Buenos Aires' => 'America/Argentina/Buenos_Aires',
        '(UTC-03:00) Georgetown' => 'America/Argentina/Buenos_Aires',
        '(UTC-03:00) Greenland' => 'America/Godthab',
        '(UTC-02:00) Mid-Atlantic' => 'America/Noronha',
        '(UTC-01:00) Azores' => 'Atlantic/Azores',
        '(UTC-01:00) Cape Verde Is.' => 'Atlantic/Cape_Verde',
        '(UTC+00:00) Casablanca' => 'Africa/Casablanca',
        '(UTC+00:00) Edinburgh' => 'Europe/London',
        '(UTC+00:00) Greenwich Mean Time : Dublin' => 'Etc/Greenwich',
        '(UTC+00:00) Lisbon' => 'Europe/Lisbon',
        '(UTC+00:00) London' => 'Europe/London',
        '(UTC+00:00) Monrovia' => 'Africa/Monrovia',
        '(UTC+00:00) UTC' => 'UTC',
        '(UTC+01:00) Amsterdam' => 'Europe/Amsterdam',
        '(UTC+01:00) Belgrade' => 'Europe/Belgrade',
        '(UTC+01:00) Berlin' => 'Europe/Berlin',
        '(UTC+01:00) Bern' => 'Europe/Berlin',
        '(UTC+01:00) Bratislava' => 'Europe/Bratislava',
        '(UTC+01:00) Brussels' => 'Europe/Brussels',
        '(UTC+01:00) Budapest' => 'Europe/Budapest',
        '(UTC+01:00) Copenhagen' => 'Europe/Copenhagen',
        '(UTC+01:00) Ljubljana' => 'Europe/Ljubljana',
        '(UTC+01:00) Madrid' => 'Europe/Madrid',
        '(UTC+01:00) Paris' => 'Europe/Paris',
        '(UTC+01:00) Prague' => 'Europe/Prague',
        '(UTC+01:00) Rome' => 'Europe/Rome',
        '(UTC+01:00) Sarajevo' => 'Europe/Sarajevo',
        '(UTC+01:00) Skopje' => 'Europe/Skopje',
        '(UTC+01:00) Stockholm' => 'Europe/Stockholm',
        '(UTC+01:00) Vienna' => 'Europe/Vienna',
        '(UTC+01:00) Warsaw' => 'Europe/Warsaw',
        '(UTC+01:00) West Central Africa' => 'Africa/Lagos',
        '(UTC+01:00) Zagreb' => 'Europe/Zagreb',
        '(UTC+02:00) Athens' => 'Europe/Athens',
        '(UTC+02:00) Bucharest' => 'Europe/Bucharest',
        '(UTC+02:00) Cairo' => 'Africa/Cairo',
        '(UTC+02:00) Harare' => 'Africa/Harare',
        '(UTC+02:00) Helsinki' => 'Europe/Helsinki',
        '(UTC+02:00) Istanbul' => 'Europe/Istanbul',
        '(UTC+02:00) Jerusalem' => 'Asia/Jerusalem',
        '(UTC+02:00) Kyiv' => 'Europe/Helsinki',
        '(UTC+02:00) Pretoria' => 'Africa/Johannesburg',
        '(UTC+02:00) Riga' => 'Europe/Riga',
        '(UTC+02:00) Sofia' => 'Europe/Sofia',
        '(UTC+02:00) Tallinn' => 'Europe/Tallinn',
        '(UTC+02:00) Vilnius' => 'Europe/Vilnius',
        '(UTC+03:00) Baghdad' => 'Asia/Baghdad',
        '(UTC+03:00) Kuwait' => 'Asia/Kuwait',
        '(UTC+03:00) Minsk' => 'Europe/Minsk',
        '(UTC+03:00) Nairobi' => 'Africa/Nairobi',
        '(UTC+03:00) Riyadh' => 'Asia/Riyadh',
        '(UTC+03:00) Volgograd' => 'Europe/Volgograd',
        '(UTC+03:30) Tehran' => 'Asia/Tehran',
        '(UTC+04:00) Abu Dhabi' => 'Asia/Muscat',
        '(UTC+04:00) Baku' => 'Asia/Baku',
        '(UTC+04:00) Moscow' => 'Europe/Moscow',
        '(UTC+04:00) Muscat' => 'Asia/Muscat',
        '(UTC+04:00) Tbilisi' => 'Asia/Tbilisi',
        '(UTC+04:00) Yerevan' => 'Asia/Yerevan',
        '(UTC+04:30) Kabul' => 'Asia/Kabul',
        '(UTC+05:00) Islamabad' => 'Asia/Karachi',
        '(UTC+05:00) Karachi' => 'Asia/Karachi',
        '(UTC+05:00) Tashkent' => 'Asia/Tashkent',
        '(UTC+05:30) Chennai' => 'Asia/Calcutta',
        '(UTC+05:30) Kolkata' => 'Asia/Kolkata',
        '(UTC+05:30) Mumbai' => 'Asia/Calcutta',
        '(UTC+05:30) New Delhi' => 'Asia/Calcutta',
        '(UTC+05:30) Sri Jayawardenepura' => 'Asia/Calcutta',
        '(UTC+05:45) Kathmandu' => 'Asia/Katmandu',
        '(UTC+06:00) Almaty' => 'Asia/Almaty',
        '(UTC+06:00) Astana' => 'Asia/Dhaka',
        '(UTC+06:00) Dhaka' => 'Asia/Dhaka',
        '(UTC+06:00) Ekaterinburg' => 'Asia/Yekaterinburg',
        '(UTC+06:30) Rangoon' => 'Asia/Rangoon',
        '(UTC+07:00) Bangkok' => 'Asia/Bangkok',
        '(UTC+07:00) Hanoi' => 'Asia/Bangkok',
        '(UTC+07:00) Jakarta' => 'Asia/Jakarta',
        '(UTC+07:00) Novosibirsk' => 'Asia/Novosibirsk',
        '(UTC+08:00) Beijing' => 'Asia/Hong_Kong',
        '(UTC+08:00) Chongqing' => 'Asia/Chongqing',
        '(UTC+08:00) Hong Kong' => 'Asia/Hong_Kong',
        '(UTC+08:00) Krasnoyarsk' => 'Asia/Krasnoyarsk',
        '(UTC+08:00) Kuala Lumpur' => 'Asia/Kuala_Lumpur',
        '(UTC+08:00) Perth' => 'Australia/Perth',
        '(UTC+08:00) Singapore' => 'Asia/Singapore',
        '(UTC+08:00) Taipei' => 'Asia/Taipei',
        '(UTC+08:00) Ulaan Bataar' => 'Asia/Ulan_Bator',
        '(UTC+08:00) Urumqi' => 'Asia/Urumqi',
        '(UTC+09:00) Irkutsk' => 'Asia/Irkutsk',
        '(UTC+09:00) Osaka' => 'Asia/Tokyo',
        '(UTC+09:00) Sapporo' => 'Asia/Tokyo',
        '(UTC+09:00) Seoul' => 'Asia/Seoul',
        '(UTC+09:00) Tokyo' => 'Asia/Tokyo',
        '(UTC+09:30) Adelaide' => 'Australia/Adelaide',
        '(UTC+09:30) Darwin' => 'Australia/Darwin',
        '(UTC+10:00) Brisbane' => 'Australia/Brisbane',
        '(UTC+10:00) Canberra' => 'Australia/Canberra',
        '(UTC+10:00) Guam' => 'Pacific/Guam',
        '(UTC+10:00) Hobart' => 'Australia/Hobart',
        '(UTC+10:00) Melbourne' => 'Australia/Melbourne',
        '(UTC+10:00) Port Moresby' => 'Pacific/Port_Moresby',
        '(UTC+10:00) Sydney' => 'Australia/Sydney',
        '(UTC+10:00) Yakutsk' => 'Asia/Yakutsk',
        '(UTC+11:00) Vladivostok' => 'Asia/Vladivostok',
        '(UTC+12:00) Auckland' => 'Pacific/Auckland',
        '(UTC+12:00) Fiji' => 'Pacific/Fiji',
        '(UTC+12:00) International Date Line West' => 'Pacific/Kwajalein',
        '(UTC+12:00) Kamchatka' => 'Asia/Kamchatka',
        '(UTC+12:00) Magadan' => 'Asia/Magadan',
        '(UTC+12:00) Marshall Is.' => 'Pacific/Fiji',
        '(UTC+12:00) New Caledonia' => 'Asia/Magadan',
        '(UTC+12:00) Solomon Is.' => 'Asia/Magadan',
        '(UTC+12:00) Wellington' => 'Pacific/Auckland',
        '(UTC+13:00) Nuku\'alofa' => 'Pacific/Tongatapu'
    );
}


/**
 * Get the user's date time format for returning formatted date
 *
 * @param   int     $user_id    User id or 0 for current session
 * @return  string              Users specified date time format
 */
function get_user_date_format($user_id = 0)
{
    $format = get_option('default_date_format', DF_ISO8601);
    $user_format = get_user_meta('date_format', DF_AUTO, $user_id);
    if ($user_format != DF_AUTO) {
        $format = $user_format;
    }
    return $format;
}


/**
 * Get the user's date() format string based on their selected format
 *
 * @param   int     $user_id    User id or 0 for current session
 * @param   bool    $date_only  True to only show date and not the time
 * @return  string              Date time format string for date()
 */
function get_user_date_format_string($user_id = 0, $date_only = false)
{
    $format = get_user_date_format($user_id);
    switch ($format) {

        case DF_ISO8601:
            $df = 'Y-m-d';
            break;

        case DF_US:
            $df = 'm/d/Y';
            break;

        case DF_EURO:
            $df = 'd/m/Y';
            break;

    }

    if (!$date_only) {
        $df .= ' H:i:s';
    }

    return $df;
}


/**
 * Converts a timestamp to a human-readable data time string based on user's settings
 * for the date time format
 *
 * @param   int     $time       The timestamp to convert
 * @param   int     $user_id    The user ID or 0 for session user
 * @param   bool    $date_only  True to only show date and not the time
 * @return  string              The converted datetime string
 */
function user_date($time = null, $user_id = 0, $date_only = false)
{
    if (empty($time)) {
        $time = time();
    }

    return date(get_user_date_format_string($user_id, $date_only), $time);

}


// if you get a time string from a server (via api->notification/alert)
// pass it here to have it shown in the local timezone as a timestring
// it doesn't handle errors. if something goes wrong, it just pretends
// the server was in local timezone to begin with.
// worst case scenario: it works exactly like fusion prior to 4
function convert_server_timestring_to_local_timestring($server, $timestring)
{
    $server = get_server($server);
    if ($server === false)
        return $timestring;

    $local_timezone = get_current_timezone();

    // See if the user has one set that is different
    if (isset($_SESSION['user_id']))
        $local_timezone = get_user_meta('timezone', $local_timezone);

    $server_timezone = get_server_attr('timezone', $server);

    if (empty($server_timezone))
        $server_timezone = $local_timezone;

    $calc = calculate_timezone_offset($local_timezone, $server_timezone);
    return date('Y-m-d H:i:s', strtotime("$calc seconds", strtotime($timestring)));
}


/**
 * Convert a specific time from this server's default to local preferences
 *
 * @param   string  $timestring     Timestamp
 * @param   bool    $format         Use user specific format
 * @return  string                  Date time string in user format and user timezone
 */
function convert_timestring_to_local_users_time($timestring, $format=true)
{
    $server_timezone = get_current_timezone();
    
    $user_timezone = $server_timezone;
    if (isset($_SESSION['user_id']))
        $user_timezone = get_user_meta('timezone', $user_timezone);

    if ($user_timezone === $server_timezone)
        return $timestring;

    $calc = calculate_timezone_offset($user_timezone, $server_timezone);

    $df = 'Y-m-d H:i:s';
    if ($format) {
        $df = get_user_date_format_string();
    }

    return date($df, strtotime("$calc seconds", strtotime($timestring)));
}


// convert FROM timezone_a TO timezone_b
// this returns a value in seconds with a -/+ prefixed
// suitable for passing to strtotime
function calculate_timezone_offset($timezone_a, $timezone_b) {

    $timestamp_a = 0;
    $timestamp_b = 0;
    
    // if someone passes a bad timezone, then thats too bad
    // ignore the error and return 0 difference
    try {

        $date_a = new DateTime('now', new DateTimeZone($timezone_a));
        $date_a = $date_a->format('Y-m-d H:i:s');
        $timestamp_a = strtotime($date_a);

        $date_b = new DateTime('now', new DateTimeZone($timezone_b));
        $date_b = $date_b->format('Y-m-d H:i:s');
        $timestamp_b = strtotime($date_b);

    } catch (Exception $e) {

        $timestamp_a = 0;
        $timestamp_b = 0;
    }

    $diff = $timestamp_a - $timestamp_b;
    if ($diff >= 0)
        $diff = "+$diff";

    return $diff;
}


/**
 * Check if a timezone is a valid timezone
 *
 * @param   string  $tz     Timezone name
 * @return  bool            True if the timezone is valid
 */
function is_valid_timezone($tz) {
    
    // Changed to 'get_current_timezone()' to make sure we are getting the timezone set in fusions options -AC 08/28/2023
    $current_tz = get_current_timezone();
    $valid_tz = false;

    if (@date_default_timezone_set($tz))
        $valid_tz = true;

    date_default_timezone_set($current_tz);
    return $valid_tz;
}


/**
 * Used for building dropdowns regarding timezones, if you leave timezone blank
 * (or if it's invalid) it sets to the system default
 *
 * @param   array   $timezones      An array of available timezones
 * @param   string  $timezone       Timezone name
 */
function get_timezones_and_selected(&$timezones, &$timezone)
{
    $timezones = array_flip(get_timezones());

    if (empty($timezone) || !is_valid_timezone($timezone))
        $timezone = get_current_timezone();
    if (isset($timezones[$timezone]))
        return;

    $timezones[$timezone] = $timezone;
}


/**
 * Updates the current timezone of the server by passing a job to the
 * command subsys to run
 *
 * @param   string  $timezone   Timezone name
 */
function update_timezone($timezone)
{
    $current_timezone = get_current_timezone();

    if (!empty($timezone) && $current_timezone != $timezone) {
        submit_command(COMMAND_CHANGE_TIMEZONE, $timezone);
        
        //set fusions default timezone option -AC
        set_option('default_timezone', $timezone);
    }
}

/**
 * Used for getting the current set fusion timezone (default_timezone) 
 *
 * @return  string     The current set Timezone
 */
function get_current_timezone() 
{
    return get_option('default_timezone');
}
