<?php

/*
 * Copyright 2005 - 2025 Centreon (https://www.centreon.com/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For more information : contact@centreon.com
 *
 */

require_once realpath(__DIR__ . '/../../../../../../bootstrap.php');
include_once _CENTREON_PATH_ . 'www/class/centreonXMLBGRequest.class.php';
include_once _CENTREON_PATH_ . 'www/class/centreonInstance.class.php';
include_once _CENTREON_PATH_ . 'www/class/centreonCriticality.class.php';
include_once _CENTREON_PATH_ . 'www/class/centreonMedia.class.php';
include_once _CENTREON_PATH_ . 'www/include/common/common-Func.php';
include_once _CENTREON_PATH_ . 'www/class/centreonUtils.class.php';

// Create XML Request Objects
CentreonSession::start();

if (! isset($_SESSION['centreon'])) {
    exit;
}
$centreon = $_SESSION['centreon'];

$obj = new CentreonXMLBGRequest($dependencyInjector, session_id(), 1, 1, 0, 1);
if (! isset($obj->session_id) || ! CentreonSession::checkSession($obj->session_id, $obj->DB)) {
    echo 'Bad Session ID';

    exit();
}

$criticality = new CentreonCriticality($obj->DB);
$instanceObj = CentreonInstance::getInstance($obj->DB, $obj->DBC);
$media = new CentreonMedia($obj->DB);
$hostObj = new CentreonHost($obj->DB);

// Set Default Poller
$obj->getDefaultFilters();

// Check Arguments From GET tab
$o = isset($_GET['o']) ? HtmlAnalyzer::sanitizeAndRemoveTags($_GET['o']) : 'h';
$p = filter_input(INPUT_GET, 'p', FILTER_VALIDATE_INT, ['options' => ['default' => 2]]);
$num = filter_input(INPUT_GET, 'num', FILTER_VALIDATE_INT, ['options' => ['default' => 0]]);
$limit = filter_input(INPUT_GET, 'limit', FILTER_VALIDATE_INT, ['options' => ['default' => 20]]);
$criticalityId = filter_input(
    INPUT_GET,
    'criticality',
    FILTER_VALIDATE_INT,
    ['options' => ['default' => $obj->defaultCriticality]]
);
// if instance value is not set, displaying all active pollers linked resources
$instance = filter_var($obj->defaultPoller ?? -1, FILTER_VALIDATE_INT);
$hostgroups = filter_var($obj->defaultHostgroups ?? 0, FILTER_VALIDATE_INT);

$search = isset($_GET['search']) ? HtmlAnalyzer::sanitizeAndRemoveTags($_GET['search']) : '';
$statusHost = isset($_GET['statusHost']) ? HtmlAnalyzer::sanitizeAndRemoveTags($_GET['statusHost']) : '';
$statusFilter = isset($_GET['statusFilter']) ? HtmlAnalyzer::sanitizeAndRemoveTags($_GET['statusFilter']) : '';
$order = isset($_GET['order']) && $_GET['order'] === 'DESC' ? 'DESC' : 'ASC';

if (isset($_GET['sort_type']) && $_GET['sort_type'] === 'host_name') {
    $sort_type = 'name';
} elseif ($o === 'hpb' || $o === 'h_unhandled') {
    $sort_type = $obj->checkArgument('sort_type', $_GET, '');
} else {
    $sort_type = $obj->checkArgument('sort_type', $_GET, 'host_name');
}
// Store in session the last type of call
$_SESSION['monitoring_host_status'] = $statusHost;
$_SESSION['monitoring_host_status_filter'] = $statusFilter;

// Backup poller selection
$obj->setInstanceHistory($instance);
$obj->setHostGroupsHistory($hostgroups);
$obj->setCriticality($criticalityId);

// saving bound values
$queryValues = [];

// Get Host status
$rq1 = <<<'SQL_WRAP'
        SELECT SQL_CALC_FOUND_ROWS DISTINCT
            1 AS REALTIME,
            h.state,
            h.acknowledged,
            h.passive_checks,
            h.active_checks,
            h.notify,
            h.last_state_change,
            h.last_hard_state_change,
            h.output,
            h.last_check,
            h.address,
            h.name,
            h.alias,
            h.action_url,
            h.notes_url,
            h.notes,
            h.icon_image,
            h.icon_image_alt,
            h.max_check_attempts,
            h.state_type,
            h.check_attempt,
            h.scheduled_downtime_depth,
            h.host_id,
            h.flapping,
            hph.parent_id AS is_parent,
            i.name AS instance_name,
            cv.value AS criticality,
            cv.value IS NULL AS isnull
            FROM instances i
        INNER JOIN hosts h
            ON h.instance_id = i.instance_id
    SQL_WRAP;

if (! $obj->is_admin) {
    $ids = $obj->access->getAccessGroups()->getIds();
    $accessGroupIds = empty($ids) ? '0' : implode(',', $ids);
    $rq1 .= <<<SQL

        INNER JOIN centreon_acl
            ON centreon_acl.host_id = h.host_id
            AND centreon_acl.group_id IN ({$accessGroupIds})
        SQL;
}

if ($hostgroups) {
    $rq1 .= <<<'SQL'

        INNER JOIN hosts_hostgroups hhg
            ON hhg.host_id = h.host_id
        INNER JOIN hostgroups hg
            ON hg.hostgroup_id = :hostgroup
            AND hg.hostgroup_id = hhg.hostgroup_id
        SQL;
    $queryValues['hostgroup'] = [PDO::PARAM_INT => $hostgroups];
}

if ($criticalityId) {
    $rq1 .= <<<'SQL'

        INNER JOIN customvariables cvs
            ON cvs.host_id = h.host_id
            AND cvs.name = 'CRITICALITY_ID'
            AND cvs.service_id = 0
            AND cvs.value = :criticalityId
        SQL;
    $queryValues['criticalityId'] = [PDO::PARAM_STR => $criticalityId];
}

$rq1 .= <<<SQL
    
    LEFT JOIN hosts_hosts_parents hph
        ON hph.parent_id = h.host_id
    LEFT JOIN `customvariables` cv
        ON (cv.host_id = h.host_id AND cv.service_id = 0 AND cv.name = 'CRITICALITY_LEVEL')
    WHERE h.name NOT LIKE '\_Module\_%'
        AND h.instance_id = i.instance_id
    SQL;

if ($search != '') {
    $rq1 .= ' AND (h.name LIKE :search
        OR h.alias LIKE :search
        OR h.address LIKE :search) ';
    $queryValues['search'] = [PDO::PARAM_STR => '%' . $search . '%'];
}

if ($statusHost == 'h_unhandled') {
    $rq1 .= " AND h.state = 1
        AND h.state_type = '1'
        AND h.acknowledged = 0
        AND h.scheduled_downtime_depth = 0";
} elseif ($statusHost == 'hpb') {
    $rq1 .= ' AND (h.state != 0 AND h.state != 4) ';
}

if ($statusFilter == 'up') {
    $rq1 .= ' AND h.state = 0 ';
} elseif ($statusFilter == 'down') {
    $rq1 .= ' AND h.state = 1 ';
} elseif ($statusFilter == 'unreachable') {
    $rq1 .= ' AND h.state = 2 ';
} elseif ($statusFilter == 'pending') {
    $rq1 .= ' AND h.state = 4 ';
}

if ($instance != -1 && ! empty($instance)) {
    $rq1 .= ' AND h.instance_id = :instance ';
    $queryValues['instance'] = [
        PDO::PARAM_INT => $instance,
    ];
}
$rq1 .= ' AND h.enabled = 1';
switch ($sort_type) {
    case 'name':
        $rq1 .= ' ORDER BY h.name ' . $order;
        break;
    case 'current_state':
        $rq1 .= ' ORDER BY h.state ' . $order . ',h.name';
        break;
    case 'last_state_change':
        $rq1 .= ' ORDER BY h.last_state_change ' . $order . ',h.name';
        break;
    case 'last_hard_state_change':
        $rq1 .= ' ORDER BY h.last_hard_state_change ' . $order . ',h.name';
        break;
    case 'last_check':
        $rq1 .= ' ORDER BY h.last_check ' . $order . ',h.name';
        break;
    case 'current_check_attempt':
        $rq1 .= ' ORDER BY h.check_attempt ' . $order . ',h.name';
        break;
    case 'ip':
        // Not SQL portable
        $rq1 .= ' ORDER BY IFNULL(inet_aton(h.address), h.address) ' . $order . ',h.name';
        break;
    case 'plugin_output':
        $rq1 .= ' ORDER BY h.output ' . $order . ',h.name';
        break;
    case 'criticality_id':
    default:
        $rq1 .= ' ORDER BY isnull ' . $order . ', criticality ' . $order . ', h.name';
        break;
}
$rq1 .= ' LIMIT :numLimit, :limit';
$queryValues['numLimit'] = [
    PDO::PARAM_INT => (int) ($num * $limit),
];
$queryValues['limit'] = [
    PDO::PARAM_INT => (int) $limit,
];

$dbResult = $obj->DBC->prepare($rq1);
foreach ($queryValues as $bindId => $bindData) {
    foreach ($bindData as $bindType => $bindValue) {
        $dbResult->bindValue($bindId, $bindValue, $bindType);
    }
}
$dbResult->execute();

$ct = 0;
$flag = 0;
$numRows = (int) $obj->DBC->query('SELECT FOUND_ROWS() AS REALTIME')->fetchColumn();

/**
 * Get criticality ids
 */
$critRes = $obj->DBC->query(
    "SELECT value, host_id
    FROM customvariables
    WHERE name = 'CRITICALITY_ID'
    AND service_id = 0"
);
$criticalityUsed = 0;
$critCache = [];
if ($obj->DBC->numberRows()) {
    $criticalityUsed = 1;
    while ($critRow = $critRes->fetch()) {
        $critCache[$critRow['host_id']] = $critRow['value'];
    }
}

$obj->XML->startElement('reponse');
$obj->XML->startElement('i');
$obj->XML->writeElement('numrows', $numRows);
$obj->XML->writeElement('num', $num);
$obj->XML->writeElement('limit', $limit);
$obj->XML->writeElement('p', $p);
$obj->XML->writeElement('o', $o);
$obj->XML->writeElement('sort_type', $sort_type);
$obj->XML->writeElement('hard_state_label', _('Hard State Duration'));
$obj->XML->writeElement('parent_host_label', _('Top Priority Hosts'));
$obj->XML->writeElement('regular_host_label', _('Secondary Priority Hosts'));
$obj->XML->writeElement('http_action_link', _('HTTP Action Link'));
$obj->XML->writeElement('notif_disabled', _('Notification is disabled'));
$obj->XML->writeElement('use_criticality', $criticalityUsed);
$obj->XML->endElement();

$delimInit = 0;
while ($data = $dbResult->fetch()) {
    if ($data['last_state_change'] > 0 && time() > $data['last_state_change']) {
        $duration = CentreonDuration::toString(time() - $data['last_state_change']);
    } else {
        $duration = 'N/A';
    }

    if (($data['last_hard_state_change'] > 0) && ($data['last_hard_state_change'] >= $data['last_state_change'])) {
        $hard_duration = CentreonDuration::toString(time() - $data['last_hard_state_change']);
    } elseif ($data['last_hard_state_change'] > 0) {
        $hard_duration = ' N/A ';
    } else {
        $hard_duration = 'N/A';
    }

    if ($data['is_parent']) {
        $delimInit = 1;
    }

    $class = null;
    if ($data['scheduled_downtime_depth'] > 0) {
        $class = 'line_downtime';
    } elseif ($data['state'] == 1) {
        $class = $data['acknowledged'] == 1 ? 'line_ack' : 'list_down';
    } elseif ($data['acknowledged'] == 1) {
        $class = 'line_ack';
    }

    $obj->XML->startElement('l');
    $trClass = $obj->getNextLineClass();
    if (isset($class)) {
        $trClass = $class;
    }
    $obj->XML->writeAttribute('class', $trClass);
    $obj->XML->writeElement('o', $ct++);
    $obj->XML->writeElement('hc', $obj->colorHost[$data['state']]);
    $obj->XML->writeElement('f', $flag);
    $obj->XML->writeElement('hid', $data['host_id']);
    $obj->XML->writeElement('hn', CentreonUtils::escapeSecure($data['name']), false);
    $obj->XML->writeElement('hnl', CentreonUtils::escapeSecure(urlencode($data['name'])));
    $obj->XML->writeElement('a', ($data['address'] ? CentreonUtils::escapeSecure($data['address']) : 'N/A'));
    $obj->XML->writeElement('ou', ($data['output'] ? CentreonUtils::escapeSecure($data['output']) : 'N/A'));
    $obj->XML->writeElement(
        'lc',
        ($data['last_check'] != 0 ? CentreonDuration::toString(time() - $data['last_check']) : 'N/A')
    );
    $obj->XML->writeElement('cs', _($obj->statusHost[$data['state']]), false);
    $obj->XML->writeElement('pha', $data['acknowledged']);
    $obj->XML->writeElement('pce', $data['passive_checks']);
    $obj->XML->writeElement('ace', $data['active_checks']);
    $obj->XML->writeElement('lsc', ($duration ?: 'N/A'));
    $obj->XML->writeElement('lhs', ($hard_duration ?: 'N/A'));
    $obj->XML->writeElement('ha', $data['acknowledged']);
    $obj->XML->writeElement('hdtm', $data['scheduled_downtime_depth']);
    $obj->XML->writeElement(
        'hdtmXml',
        './include/monitoring/downtime/xml/broker/makeXMLForDowntime.php?hid=' . $data['host_id']
    );
    $obj->XML->writeElement('hdtmXsl', './include/monitoring/downtime/xsl/popupForDowntime.xsl');
    $obj->XML->writeElement(
        'hackXml',
        './include/monitoring/acknowlegement/xml/broker/makeXMLForAck.php?hid=' . $data['host_id']
    );
    $obj->XML->writeElement('hackXsl', './include/monitoring/acknowlegement/xsl/popupForAck.xsl');
    $obj->XML->writeElement('hae', $data['active_checks']);
    $obj->XML->writeElement('hpe', $data['passive_checks']);
    $obj->XML->writeElement('ne', $data['notify']);
    $obj->XML->writeElement(
        'tr',
        $data['check_attempt'] . '/' . $data['max_check_attempts'] . ' (' . $obj->stateType[$data['state_type']] . ')'
    );

    if (isset($data['criticality']) && $data['criticality'] != '' && isset($critCache[$data['host_id']])) {
        $obj->XML->writeElement('hci', 1); // has criticality
        $critData = $criticality->getData($critCache[$data['host_id']]);
        $obj->XML->writeElement('ci', $media->getFilename($critData['icon_id']));
        $obj->XML->writeElement('cih', CentreonUtils::escapeSecure($critData['name']));
    } else {
        $obj->XML->writeElement('hci', 0); // has no criticality
    }
    $obj->XML->writeElement('ico', $data['icon_image']);
    $obj->XML->writeElement('isp', $data['is_parent'] ? 1 : 0);
    $obj->XML->writeElement('isf', $data['flapping']);
    $parenth = 0;
    if ($ct === 1 && $data['is_parent']) {
        $parenth = 1;
    }
    if (! $sort_type && $delimInit && ! $data['is_parent']) {
        $delim = 1;
        $delimInit = 0;
    } else {
        $delim = 0;
    }
    $obj->XML->writeElement('parenth', $parenth);
    $obj->XML->writeElement('delim', $delim);

    if ($data['notes'] != '') {
        $obj->XML->writeElement(
            'hnn',
            CentreonUtils::escapeSecure(
                $hostObj->replaceMacroInString(
                    $data['host_id'],
                    str_replace(
                        'HOSTNAME$',
                        $data['name'],
                        str_replace('$HOSTADDRESS$', $data['address'], $data['notes'])
                    )
                )
            )
        );
    } else {
        $obj->XML->writeElement('hnn', 'none');
    }

    if ($data['notes_url'] != '') {
        $str = str_replace('$HOSTNAME$', $data['name'], $data['notes_url']);
        $str = str_replace('$HOSTALIAS$', $data['alias'], $str);
        $str = str_replace('$HOSTADDRESS$', $data['address'], $str);
        $str = str_replace('$HOSTNOTES$', $data['notes'], $str);
        $str = str_replace('$INSTANCENAME$', $data['instance_name'], $str);

        $str = str_replace('$HOSTSTATEID$', $data['state'], $str);
        $str = str_replace('$HOSTSTATE$', $obj->statusHost[$data['state']], $str);

        $str = str_replace(
            '$INSTANCEADDRESS$',
            $instanceObj->getParam($data['instance_name'], 'ns_ip_address'),
            $str
        );
        $obj->XML->writeElement(
            'hnu',
            CentreonUtils::escapeSecure($hostObj->replaceMacroInString($data['host_id'], $str))
        );
    } else {
        $obj->XML->writeElement('hnu', 'none');
    }

    if ($data['action_url'] != '') {
        $str = $data['action_url'];
        $str = str_replace('$HOSTNAME$', $data['name'], $str);
        $str = str_replace('$HOSTALIAS$', $data['alias'], $str);
        $str = str_replace('$HOSTADDRESS$', $data['address'], $str);
        $str = str_replace('$HOSTNOTES$', $data['notes'], $str);
        $str = str_replace('$INSTANCENAME$', $data['instance_name'], $str);

        $str = str_replace('$HOSTSTATEID$', $data['state'], $str);
        $str = str_replace('$HOSTSTATE$', $obj->statusHost[$data['state']], $str);

        $str = str_replace(
            '$INSTANCEADDRESS$',
            $instanceObj->getParam($data['instance_name'], 'ns_ip_address'),
            $str
        );
        $obj->XML->writeElement(
            'hau',
            CentreonUtils::escapeSecure($hostObj->replaceMacroInString($data['host_id'], $str))
        );
    } else {
        $obj->XML->writeElement('hau', 'none');
    }
    $obj->XML->writeElement('chartIcon', returnSvg('www/img/icons/chart.svg', 'var(--icons-fill-color)', 18, 18));
    $obj->XML->endElement();
}
$dbResult->closeCursor();

if (! $ct) {
    $obj->XML->writeElement('infos', 'none');
}
$obj->XML->endElement();

$obj->header();
$obj->XML->output();
