<?php
/**
 * i-doit - Documentation and CMDB solution for IT environments
 *
 * This file is part of the i-doit framework. Modify at your own risk.
 *
 * Please visit http://www.i-doit.com/license for a full copyright and license information.
 *
 * @version     1.10
 * @package     i-doit
 * @author      synetics GmbH
 * @copyright   synetics GmbH
 * @url         http://www.i-doit.com
 * @license     http://www.i-doit.com/license
 */

namespace idoit\Module\Nagios\Console\Command;

use Exception;
use idoit\Console\Command\AbstractCommand;
use isys_cmdb_dao_category_g_nagios;
use isys_component_dao_logbook;
use isys_component_dao_ndo;
use isys_factory;
use isys_monitoring_helper;
use isys_monitoring_ndo;
use isys_nagios_helper;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class NagiosCommand extends AbstractCommand
{
    const NAME = 'nagios-ndoutils';

    /**
     * @var OutputInterface
     */
    private $output;

    /**
     * NDO component DAO.
     *
     * @var  isys_component_dao_ndo
     */
    private $m_comp_dao_ndo;
    /**
     * Logbook DAO.
     *
     * @var  isys_component_dao_logbook
     */
    private $m_dao_logbook;
    /**
     * Nagios category DAO.
     *
     * @var  isys_cmdb_dao_category_g_nagios
     */
    private $m_dao_nagios;

    /**
     * Get name for command
     *
     * @return string
     */
    public function getCommandName()
    {
        return self::NAME;
    }

    /**
     * Get description for command
     *
     * @return string
     */
    public function getCommandDescription()
    {
        return 'Imports monitoring status changes from NDOUtils into the i-doit logbook';
    }

    /**
     * Retrieve Command InputDefinition
     *
     * @return InputDefinition
     */
    public function getCommandDefinition()
    {
        $definition = new InputDefinition();

        return $definition;
    }

    /**
     * Checks if a command can have a config file via --config
     *
     * @return bool
     */
    public function isConfigurable()
    {
        return true;
    }

    /**
     * Returns an array of command usages
     *
     * @return string[]
     */
    public function getCommandUsages()
    {
        return [];
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->output = $output;
        $this->output->writeln("Setting up system environment");

        // Get daos, because now we are logged in.
        $this->m_dao_nagios  = new isys_cmdb_dao_category_g_nagios($this->container->database);
        $this->m_dao_logbook = new isys_component_dao_logbook($this->container->database);

        $this->output->writeln("Nagios-Handler initialized (" . date("Y-m-d H:i:s") . ")");

        // Check status and add to logbook.
        $this->processStateHistory();
    }

    /**
     * Process state history method.
     *
     * @throws  Exception
     */
    private function processStateHistory()
    {
        $l_monitoring_dao = isys_factory::get_instance('isys_cmdb_dao_category_g_monitoring', $this->container->database);

        $l_hosts_res = $l_monitoring_dao->get_data(
            null,
            null,
            'AND isys_monitoring_hosts__active = 1 AND isys_monitoring_hosts__type = ' . $l_monitoring_dao->convert_sql_text(C__MONITORING__TYPE_NDO),
            null,
            C__RECORD_STATUS__NORMAL
        );

        $l_hosts_num = count($l_hosts_res);

        // We need to initialize the nagios helper.
        isys_nagios_helper::init();

        $this->output->writeln('Found ' . $l_hosts_num . ($l_hosts_num == 1 ? ' host' : ' hosts'));

        if ($l_hosts_num > 0)
        {
            while ($l_row = $l_hosts_res->get_row())
            {
                $l_objID    = $l_row["isys_obj__id"];
                $l_hostname = isys_monitoring_helper::render_export_hostname($l_row['isys_obj__id']);

                $this->output->writeln('Processing "' . $l_hostname . '"');

                try
                {
                    try
                    {
                        if ($l_row["isys_catg_monitoring_list__isys_monitoring_hosts__id"] > 0)
                        {
                            $this->output->writeln('..', false);
                            $l_ndo_instance = isys_monitoring_ndo::factory($l_row["isys_catg_monitoring_list__isys_monitoring_hosts__id"]);
                        }
                        else
                        {
                            $this->output->writeln(' ..this object has no assigned monitoring host [SKIP]');
                            continue;
                        } // if
                    }
                    catch (Exception $e)
                    {
                        $this->output->writeln('  ' . $l_hostname . ': ' . $e->getMessage() . ' [SKIP]');
                        continue;
                    } // try

                    $this->m_comp_dao_ndo = new isys_component_dao_ndo($l_ndo_instance->get_db_connection(), $l_ndo_instance->get_db_prefix());

                    if (!$this->m_comp_dao_ndo->hostExists($l_hostname))
                    {
                        throw new Exception("  Host does not exist in your NDO database [SKIP]");
                    } // if

                    $l_hist = $this->m_comp_dao_ndo->getHostStateHistory($l_hostname);
                    $l_date = $this->m_dao_logbook->getDateOfLastNDOEntry($l_objID);

                    foreach ($l_hist as $val)
                    {
                        if ($val["state_time"] <= $l_date)
                        {
                            break;
                        } // if

                        switch ($val["state"])
                        {
                            case "0":
                                $this->output->writeln("  is UP");
                                $this->m_dao_logbook->set_entry(
                                    $l_hostname . ": UP",
                                    "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                    $val["state_time"],
                                    C__LOGBOOK__ALERT_LEVEL__1,
                                    $l_objID,
                                    null,
                                    null,
                                    null,
                                    C__LOGBOOK_SOURCE__NDO
                                );
                                break;

                            case "1":
                                $this->output->writeln("  is DOWN");
                                $this->m_dao_logbook->set_entry(
                                    $l_hostname . ": DOWN",
                                    "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                    $val["state_time"],
                                    C__LOGBOOK__ALERT_LEVEL__3,
                                    $l_objID,
                                    null,
                                    null,
                                    null,
                                    C__LOGBOOK_SOURCE__NDO
                                );
                                break;

                            case "2":
                                $this->output->writeln("  is UNREACHABLE");
                                $this->m_dao_logbook->set_entry(
                                    $l_hostname . ": UNREACHABLE",
                                    "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                    $val["state_time"],
                                    C__LOGBOOK__ALERT_LEVEL__2,
                                    $l_objID,
                                    null,
                                    null,
                                    null,
                                    C__LOGBOOK_SOURCE__NDO
                                );
                                break;

                            default:
                                throw new Exception("Error");
                        } // switch
                    } // foreach

                    $l_service_res = $this->m_dao_nagios->getActiveServices($l_objID);

                    if (count($l_service_res) > 0)
                    {
                        while ($l_service_row = $l_service_res->get_row())
                        {
                            if (!$this->m_comp_dao_ndo->serviceExists($l_hostname, $l_service_row["service_description"]))
                            {
                                continue;
                            } // if

                            $l_hist = $this->m_comp_dao_ndo->getServiceStateHistory($l_hostname, $l_service_row["service_description"]);
                            $l_date = $this->m_dao_logbook->getDateOfLastNDOEntry($l_service_row["service_obj_id"]);

                            foreach ($l_hist as $val)
                            {
                                if ($val["state_time"] <= $l_date)
                                {
                                    break;
                                } // if

                                switch ($val["state"])
                                {
                                    case "0":
                                        $this->m_dao_logbook->set_entry(
                                            $l_service_row["service_description"] . "(" . $l_hostname . "): OK",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                            $val["state_time"],
                                            C__LOGBOOK__ALERT_LEVEL__1,
                                            $l_service_row["service_obj_id"],
                                            null,
                                            null,
                                            null,
                                            C__LOGBOOK_SOURCE__NDO
                                        );
                                        break;

                                    case "1":
                                        $this->m_dao_logbook->set_entry(
                                            $l_service_row["service_description"] . "(" . $l_hostname . "): WARNING",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                            $val["state_time"],
                                            C__LOGBOOK__ALERT_LEVEL__2,
                                            $l_service_row["service_obj_id"],
                                            null,
                                            null,
                                            null,
                                            C__LOGBOOK_SOURCE__NDO
                                        );

                                        break;

                                    case "2":
                                        $this->m_dao_logbook->set_entry(
                                            $l_service_row["service_description"] . "(" . $l_hostname . "): CRITICAL",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                            $val["state_time"],
                                            C__LOGBOOK__ALERT_LEVEL__3,
                                            $l_service_row["service_obj_id"],
                                            null,
                                            null,
                                            null,
                                            C__LOGBOOK_SOURCE__NDO
                                        );

                                        break;

                                    case "3":
                                        $this->m_dao_logbook->set_entry(
                                            $l_service_row["service_description"] . "(" . $l_hostname . "): UNKNOWN",
                                            "State time: " . $val["state_time"] . "<br/>" . $val["output"],
                                            $val["state_time"],
                                            C__LOGBOOK__ALERT_LEVEL__2,
                                            $l_service_row["service_obj_id"],
                                            null,
                                            null,
                                            null,
                                            C__LOGBOOK_SOURCE__NDO
                                        );

                                        break;

                                    default:
                                        $this->output->writeln("Processing of " . $val["isys_catg_application_list__service_description"] . " on " . $l_hostname . " failed");
                                } // switch
                            } // foreach
                        } // while
                    } // if
                }
                catch (Exception $e)
                {
                    $this->output->writeln('  ' . $l_hostname . ': ' . $e->getMessage());
                } // try
            } // while
        } // if
    } // function
}
