<?php

/*****************************************************************************
 *
 * NagVisHost.php - Class of a Host in NagVis with all necessary information
 *                  which belong to the object handling in NagVis
 *
 * Copyright (c) 2004-2016 NagVis Project (Contact: info@nagvis.org)
 *
 * License:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *****************************************************************************/

class NagVisHost extends NagVisStatefulObject
{
    /** @var string */
    protected $type = 'host';

    protected static $langType = null;
    protected static $langSelf = null;
    protected static $langChild = null;

    /** @var string */
    protected static $langHostStateIs = null;

    /** @var string */
    protected static $langServices = null;

    /** @var string */
    protected $host_name;

    /** @var string */
    protected $alias;

    /** @var NagVisService[] */
    protected $members = [];

    /**
     * @param array $backend_id
     * @param string $hostName
     */
    public function __construct($backend_id, $hostName)
    {
        $this->backend_id = $backend_id;
        $this->host_name = $hostName;
        parent::__construct();
    }

    /**
     * Fetches the summary state and output from the already set state counts
     *
     * @return void
     * @throws NagVisException
     * @author  Lars Michelsen <lm@larsmichelsen.com>
     */
    public function fetchSummariesFromCounts()
    {
        // Generate summary output
        // Only create summary output from members when the summary output is empty.
        // It might be generated by the backend.
        if ($this->sum[OUTPUT] === null) {
            $this->fetchSummaryOutputFromCounts();
        }

        // Only create summary from members when the summary_state is empty.
        // It might be generated by the backend.
        if ($this->sum[STATE] === null) {
            // Add host state to counts
            // This should be done after output generation and before
            // summary state fetching. It could confuse the output fetching but
            // is needed for the summary state
            $this->addHostStateToStateCounts();

            // Calculate summary state
            $this->fetchSummaryStateFromCounts();
        }
    }

    /**
     * Queues the state fetching to the backend.
     *
     * @param bool $bFetchObjectState Optional flag to disable fetching of the object status
     * @param bool $bFetchMemberState Optional flag to disable fetching of member status
     * @return void
     * @author  Lars Michelsen <lm@larsmichelsen.com>
     */
    public function queueState($bFetchObjectState = true, $bFetchMemberState = true)
    {
        global $_BACKEND;
        $queries = [];

        if ($bFetchObjectState) {
            $queries['hostState'] = true;
        }

        if ($this->recognize_services) {
            $queries['hostMemberState'] = true;
        }

        if (
            $this->hover_menu == 1
            && $this->hover_childs_show == 1
            && $bFetchMemberState
            && !$this->hasMembers()
        ) {
            $queries['hostMemberDetails'] = true;
        }

        $_BACKEND->queue($queries, $this);
    }

    /**
     * Applies the fetched state
     *
     * @return void
     * @throws NagVisException
     * @author  Lars Michelsen <lm@larsmichelsen.com>
     */
    public function applyState()
    {
        if ($this->problem_msg) {
            $this->sum[STATE] = ERROR;
            $this->sum[OUTPUT] = $this->problem_msg;
            $this->members = [];
            return;
        }

        if ($this->hasMembers()) {
            foreach ($this->getMembers() as $MOBJ) {
                $MOBJ->applyState();
            }
        }

        // Use state summaries when some are available to
        // calculate summary state and output
        if ($this->aStateCounts !== null) {
            $this->fetchSummariesFromCounts();
        } else {
            if ($this->sum[STATE] === null) {
                $this->fetchSummaryState();
            }
            if ($this->sum[OUTPUT] === null) {
                $this->fetchSummaryOutput();
            }
        }
    }

    # End public methods
    # #########################################################################

    /**
     * Fetches the summary state from all services
     *
     * @return void
     * @author    Lars Michelsen <lm@larsmichelsen.com>
     */
    private function fetchSummaryState()
    {
        // Get Host state
        $this->sum[STATE] = $this->state[STATE];
        $this->sum[ACK] = $this->state[ACK];
        $this->sum[DOWNTIME] = $this->state[DOWNTIME];

        // Only merge host state with service state when recognize_services is set to 1
        if ($this->recognize_services) {
            $this->calcSummaryState();
        }
    }

    /**
     * Adds the current host state to the member state counts
     *
     * @return void
     * @author    Lars Michelsen <lm@larsmichelsen.com>
     */
    private function addHostStateToStateCounts()
    {
        $sState = $this->state[STATE];
        $sSubState = $this->getSubState();
        if (!isset($this->aStateCounts[$sState])) {
            $this->aStateCounts[$sState] = [$sSubState => 1];
        } elseif (!isset($this->aStateCounts[$sState][$sSubState])) {
            $this->aStateCounts[$sState][$sSubState] = 1;
        } else {
            $this->aStateCounts[$sState][$sSubState] += 1;
        }
    }

    /**
     * Fetches the summary output from the object state counts
     *
     * @return void
     * @author    Lars Michelsen <lm@larsmichelsen.com>
     */
    private function fetchSummaryOutputFromCounts()
    {
        if (NagVisHost::$langHostStateIs === null) {
            NagVisHost::$langHostStateIs = l('hostStateIs');
        }

        // Write host state
        $this->sum[OUTPUT] = NagVisHost::$langHostStateIs . ' ' . state_str($this->state[STATE]) . '. ';

        // Only merge host state with service state when recognize_services is set
        // to 1
        if ($this->recognize_services) {
            $iNumServices = 0;
            $arrServiceStates = [];

            // Loop all major states
            if ($this->aStateCounts !== null) {
                foreach ($this->aStateCounts as $sState => $aSubstates) {
                    if (is_host_state($sState)) {
                        continue;
                    }

                    // Loop all substates (normal,ack,downtime,...)
                    foreach ($aSubstates as $sSubState => $iCount) {
                        // Found some objects with this state+substate
                        if ($iCount > 0) {
                            if (!isset($arrServiceStates[$sState])) {
                                $arrServiceStates[$sState] = $iCount;
                                $iNumServices += $iCount;
                            } else {
                                $arrServiceStates[$sState] += $iCount;
                                $iNumServices += $iCount;
                            }
                        }
                    }
                }
            }

            if ($iNumServices > 0) {
                if (NagVisHost::$langServices === null) {
                    NagVisHost::$langServices = l('services');
                }

                $this->mergeSummaryOutput($arrServiceStates, NagVisHost::$langServices);
            } else {
                $this->sum[OUTPUT] .= l('hostHasNoServices', 'HOST~' . $this->getName());
            }
        }
    }

    /**
     * Fetches the summary output from host and all services
     *
     * @return void
     * @author    Lars Michelsen <lm@larsmichelsen.com>
     */
    private function fetchSummaryOutput()
    {
        // Write host state
        $this->sum[OUTPUT] = l('hostStateIs') . ' ' . state_str($this->state[STATE]) . '. ';

        // Only merge host state with service state when recognize_services is set
        // to 1
        if ($this->recognize_services) {
            // If there are services write the summary state for them
            if ($this->hasMembers()) {
                $arrStates = [
                    CRITICAL => 0, DOWN => 0, WARNING => 0,
                    UNKNOWN => 0, UP => 0, OK => 0,
                    ERROR => 0, PENDING => 0, UNCHECKED => 0
                ];

                foreach ($this->members as &$SERVICE) {
                    $arrStates[$SERVICE->getSummaryState()]++;
                }

                $this->mergeSummaryOutput($arrStates, l('services'));
            } else {
                $this->sum[OUTPUT] .= l('hostHasNoServices', 'HOST~' . $this->getName());
            }
        }
    }
}
