<?php

/**
 * i-doit
 *
 * DAO: global category for object vitalities
 *
 * @package    i-doit
 * @subpackage CMDB_Categories
 * @copyright  synetics GmbH
 * @license    http://www.i-doit.com/license
 */
class isys_cmdb_dao_category_g_object_vitality extends isys_cmdb_dao_category_g_virtual
{
    /**
     * Category's name. Will be used for the identifier, constant, main table, and many more.
     *
     * @var string
     */
    protected $m_category = 'object_vitality';

    /**
     * Executes the query to save the category entry given by its ID $p_cat_level.
     *
     * @param int    $p_cat_level
     * @param bool   $p_virtualHost
     * @param int    $p_connectedObjID
     * @param string $p_description
     *
     * @return bool
     */
    public function save($p_cat_level, $p_virtualHost, $p_connectedObjID, $p_description, $p_status = C__RECORD_STATUS__NORMAL)
    {
        return true;
    }

    /**
     * Gets member resources and for the current object.
     *
     * @param int $p_obj_id
     *
     * @return array
     */
    public function get_members_and_main_object($p_obj_id)
    {
        $language = isys_application::instance()->container->get('language');
        $l_quick_info = new isys_ajax_handler_quick_info();
        $l_dao_resource = new isys_cmdb_dao_category_g_computing_resources($this->get_database_component());

        $l_apps_vms = $this->get_data(null, $p_obj_id, "", null, C__RECORD_STATUS__NORMAL);

        $l_main_obj[$p_obj_id] = $this->getObjectResources($p_obj_id);

        while ($l_row = $l_apps_vms->get_row()) {
            if ($l_row["isys_obj_type__isys_obj_type_group__id"] == defined_or_default('C__OBJTYPE_GROUP__SOFTWARE')) {
                // Objects from group software.
                $l_resources_res = $l_dao_resource->get_data(null, $l_row["isys_obj__id"], "", null, C__RECORD_STATUS__NORMAL);

                $l_row2 = $l_resources_res->get_row();

                if ($l_resources_res->num_rows() > 0) {
                    if (strlen($l_row2["isys_obj__title"]) > 17) {
                        $l_obj_title = substr($l_row2["isys_obj__title"], 0, 14);
                        $l_obj_title .= "...";
                    } else {
                        $l_obj_title = $l_row2["isys_obj__title"];
                    }

                    $l_member[$l_row2["isys_obj__id"]]["link"] = $l_quick_info->get_quick_info($l_row2["isys_obj__id"], $l_obj_title, C__LINK__OBJECT);
                    $l_member[$l_row2["isys_obj__id"]]["type"] = $language->get($this->get_objtype_name_by_id_as_string($this->get_objTypeID($l_row2["isys_obj__id"])));

                    $l_member[$l_row["isys_obj__id"]]["memory"] = $this->processMemory($l_row2["isys_catg_computing_resources_list__ram"]);
                    $l_member[$l_row["isys_obj__id"]]["memory_rest"] = $l_row2["isys_catg_computing_resources_list__ram"];

                    $l_member[$l_row["isys_obj__id"]]["cpu"] = $this->processCpu($l_row2["isys_catg_computing_resources_list__cpu"]);
                    $l_member[$l_row["isys_obj__id"]]["cpu_rest"] = $l_row2["isys_catg_computing_resources_list__cpu"];

                    $l_member[$l_row["isys_obj__id"]]["bandwidth"] = $this->processPortSpeed($l_row2["isys_catg_computing_resources_list__network_bandwidth"]);
                    $l_member[$l_row["isys_obj__id"]]["bandwidth_rest"] = $l_row2["isys_catg_computing_resources_list__network_bandwidth"];

                    $l_member[$l_row["isys_obj__id"]]["disc_space"] = $this->processMemory($l_row2["isys_catg_computing_resources_list__disc_space"]);
                    $l_member[$l_row["isys_obj__id"]]["disc_space_rest"] = $l_row2["isys_catg_computing_resources_list__disc_space"];
                }
            } else {
                /**
                 * Virtual machines
                 */
                $l_member[$l_row["isys_obj__id"]] = $this->getObjectResources($l_row["isys_obj__id"]);
            }
        }

        $this->calculateConsumptionAndResources($l_member, $l_main_obj);

        $l_arr = [
            "members"  => $l_member,
            "main_obj" => $l_main_obj[$p_obj_id],
        ];

        return $l_arr;
    }

    /**
     * @param int $objectId
     *
     * @return int
     */
    public function get_count($objectId = null)
    {
        return count($this->get_data(null, ($objectId ?: $this->m_object_id)));
    }

    /**
     * Return Category Data.
     *
     * @param  int    $p_catg_list_id
     * @param  int    $p_obj_id
     * @param  string $p_condition
     * @param  mixed  $p_filter
     * @param  int    $p_status
     *
     * @return isys_component_dao_result
     * @throws isys_exception_database
     */
    public function get_data($p_catg_list_id = null, $p_obj_id = null, $p_condition = "", $p_filter = null, $p_status = null)
    {
        $l_sql = 'SELECT appobj.*, isys_obj_type.*
			FROM isys_catg_application_list AS app
			INNER JOIN isys_connection ON app.isys_catg_application_list__isys_connection__id = isys_connection__id
			INNER JOIN isys_obj AS appobj ON appobj.isys_obj__id = isys_connection__isys_obj__id
			INNER JOIN isys_obj_type ON appobj.isys_obj__isys_obj_type__id = isys_obj_type__id
			WHERE TRUE ' . $p_condition . ' ' . $this->prepare_filter($p_filter);

        if ($p_obj_id !== null) {
            $l_sql .= ' AND app.isys_catg_application_list__isys_obj__id = ' . $this->convert_sql_id($p_obj_id);
        }

        if ($p_status !== null) {
            $l_sql .= ' AND appobj.isys_obj__status = ' . $this->convert_sql_int($p_status) . '
				AND app.isys_catg_application_list__status = ' . $this->convert_sql_int($p_status);
        }

        $l_sql .= " UNION SELECT vmobj.*, isys_obj_type.* FROM isys_catg_virtual_machine_list AS vm
			INNER JOIN isys_connection ON isys_connection__id = vm.isys_catg_virtual_machine_list__isys_connection__id
			INNER JOIN isys_obj AS vmobj ON vm.isys_catg_virtual_machine_list__isys_obj__id = vmobj.isys_obj__id
			INNER JOIN isys_obj_type ON vmobj.isys_obj__isys_obj_type__id = isys_obj_type__id
			WHERE TRUE ";

        if ($p_obj_id !== null) {
            $l_sql .= ' AND isys_connection__isys_obj__id = ' . $this->convert_sql_id($p_obj_id);
        }

        if ($p_status !== null) {
            $l_sql .= ' AND vmobj.isys_obj__status = ' . $this->convert_sql_int($p_status);
        }

        return $this->retrieve($l_sql . ';');
    }

    /**
     * Gets resources from the referrenced object id
     *
     * @param int $p_obj_id
     *
     * @return array
     */
    private function getObjectResources($p_obj_id)
    {
        $language = isys_application::instance()->container->get('language');
        $l_quick_info = new isys_ajax_handler_quick_info();
        $l_dao_memory = new isys_cmdb_dao_category_g_memory($this->get_database_component());
        $l_dao_cpu = new isys_cmdb_dao_category_g_cpu($this->get_database_component());
        $l_dao_port = new isys_cmdb_dao_category_g_network_port($this->get_database_component());
        $l_dao_drive = new isys_cmdb_dao_category_g_drive($this->get_database_component());

        $l_memory_res = $l_dao_memory->get_data(null, $p_obj_id, "", null, C__RECORD_STATUS__NORMAL);
        $l_cpu_res = $l_dao_cpu->get_data(null, $p_obj_id, "", null, C__RECORD_STATUS__NORMAL);

        $l_memory = 0;
        $l_disc_space = 0;
        $l_cpu = 0;

        $l_obj_title = $this->get_obj_name_by_id_as_string($p_obj_id);

        if (strlen($l_obj_title) >= 20) {
            $l_obj_title = substr($l_obj_title, 0, 20);
            $l_obj_title .= "...";
        }

        $l_member["link"] = $l_quick_info->get_quick_info($p_obj_id, $l_obj_title, C__LINK__OBJECT);

        if ($p_obj_id == $_GET[C__CMDB__GET__OBJECT]) {
            $l_member["type"] = $language->get($this->get_objtype_name_by_id_as_string($this->get_objTypeID($p_obj_id)));
        } else {
            $l_member["type"] = $language->get("LC__CMDB__CATG__VIRTUAL_MACHINE");
        }

        /**
         * MEMORY
         */
        while ($l_memory_row = $l_memory_res->get_row()) {
            $l_memory += $l_memory_row["isys_catg_memory_list__capacity"];
        }
        $l_member["memory"] = $this->processMemory($l_memory);
        $l_member["memory_rest"] = $l_memory;

        /**
         * CPU
         */
        while ($l_cpu_row = $l_cpu_res->get_row()) {
            $l_cpu += $l_cpu_row["isys_catg_cpu_list__frequency"] * $l_cpu_row['isys_catg_cpu_list__cores'];
        }
        $l_member["cpu"] = $this->processCpu($l_cpu);
        $l_member["cpu_rest"] = $l_cpu;

        /**
         * BANDWIDTH
         */
        $totalPortBandwidth = 0;
        $portResource = $l_dao_port->get_data(null, $p_obj_id, '', null, C__RECORD_STATUS__NORMAL);

        while ($portRow = $portResource->get_row()) {
            $totalPortBandwidth += $portRow['isys_catg_port_list__port_speed_value'];
        }

        $l_member["bandwidth"] = $this->processPortSpeed($totalPortBandwidth);
        $l_member["bandwidth_rest"] = $totalPortBandwidth;

        /**
         * DRIVES
         */
        $l_system_drive_res = $l_dao_drive->get_system_drives($p_obj_id);

        while ($l_system_drive_row = $l_system_drive_res->get_row()) {
            $l_disc_space += $l_system_drive_row["isys_catg_drive_list__capacity"];
        }
        $l_member["disc_space"] = $this->processMemory($l_disc_space);
        $l_member["disc_space_rest"] = $l_disc_space;

        return $l_member;
    }

    /**
     * Recalculates the over consumption and determines the overall resources for every member.
     *
     * @param  array &$p_members
     * @param  array &$p_main_obj
     */
    private function calculateConsumptionAndResources(&$p_members, &$p_main_obj)
    {
        $language = isys_application::instance()->container->get('language');

        foreach ($p_main_obj as $l_main_obj_id => $l_main_data) {
            if (!is_array($p_members)) {
                $p_main_obj[$l_main_obj_id]["memory_consumption"] = [
                    'value' => 0,
                    'unit'  => $language->get('LC__CMDB__MEMORY_UNIT__KB')
                ];
                $p_main_obj[$l_main_obj_id]["cpu_consumption"] = [
                    'value' => 0,
                    'unit'  => $language->get('LC__CMDB__FREQUENCY_UNIT__KHZ')
                ];
                $p_main_obj[$l_main_obj_id]["bandwidth_consumption"] = [
                    'value' => 0,
                    'unit'  => $language->get('LC__CMDB__PORT_SPEED__KBITS')
                ];
                $p_main_obj[$l_main_obj_id]["disc_space_consumption"] = [
                    'value' => 0,
                    'unit'  => $language->get('LC__CMDB__MEMORY_UNIT__KB')
                ];

                $p_main_obj[$l_main_obj_id]["memory_rest"] = $this->processMemory($p_main_obj[$l_main_obj_id]["memory_rest"]);
                $p_main_obj[$l_main_obj_id]["cpu_rest"] = $this->processCpu($p_main_obj[$l_main_obj_id]["cpu_rest"]);
                $p_main_obj[$l_main_obj_id]["bandwidth_rest"] = $this->processPortSpeed($p_main_obj[$l_main_obj_id]["bandwidth_rest"]);
                $p_main_obj[$l_main_obj_id]["disc_space_rest"] = $this->processMemory($p_main_obj[$l_main_obj_id]["disc_space_rest"]);

                return;
            }

            foreach ($p_members as $l_obj_id => $l_data) {
                $p_main_obj[$l_main_obj_id]["memory_rest"] = $p_main_obj[$l_main_obj_id]["memory_rest"] - $l_data["memory_rest"];
                $p_main_obj[$l_main_obj_id]["memory_consumption"] = $p_main_obj[$l_main_obj_id]["memory_consumption"] + $l_data["memory_rest"] + 0;

                $p_main_obj[$l_main_obj_id]["cpu_rest"] = $p_main_obj[$l_main_obj_id]["cpu_rest"] - $l_data["cpu_rest"];
                $p_main_obj[$l_main_obj_id]["cpu_consumption"] = $p_main_obj[$l_main_obj_id]["cpu_consumption"] + $l_data["cpu_rest"] + 0;

                $p_main_obj[$l_main_obj_id]["bandwidth_rest"] = $p_main_obj[$l_main_obj_id]["bandwidth_rest"] - $l_data["bandwidth_rest"];
                $p_main_obj[$l_main_obj_id]["bandwidth_consumption"] = $p_main_obj[$l_main_obj_id]["bandwidth_consumption"] + $l_data["bandwidth_rest"] + 0;

                $p_main_obj[$l_main_obj_id]["disc_space_rest"] = $p_main_obj[$l_main_obj_id]["disc_space_rest"] - $l_data["disc_space_rest"];
                $p_main_obj[$l_main_obj_id]["disc_space_consumption"] = $p_main_obj[$l_main_obj_id]["disc_space_consumption"] + $l_data["disc_space_rest"] + 0;
            }

            $p_main_obj[$l_main_obj_id]["memory_rest"] = $this->processMemory($p_main_obj[$l_main_obj_id]["memory_rest"]);
            $p_main_obj[$l_main_obj_id]["memory_consumption"] = $this->processMemory($p_main_obj[$l_main_obj_id]["memory_consumption"]);

            $p_main_obj[$l_main_obj_id]["cpu_rest"] = $this->processCpu($p_main_obj[$l_main_obj_id]["cpu_rest"]);
            $p_main_obj[$l_main_obj_id]["cpu_consumption"] = $this->processCpu($p_main_obj[$l_main_obj_id]["cpu_consumption"]);
            $p_main_obj[$l_main_obj_id]["disc_space_rest"] = $this->processMemory($p_main_obj[$l_main_obj_id]["disc_space_rest"]);
            $p_main_obj[$l_main_obj_id]["disc_space_consumption"] = $this->processMemory($p_main_obj[$l_main_obj_id]["disc_space_consumption"]);
            $p_main_obj[$l_main_obj_id]["bandwidth_rest"] = $this->processPortSpeed($p_main_obj[$l_main_obj_id]["bandwidth_rest"]);
            $p_main_obj[$l_main_obj_id]["bandwidth_consumption"] = $this->processPortSpeed($p_main_obj[$l_main_obj_id]["bandwidth_consumption"]);
        }
    }

    /**
     * Helper method to convert port speed
     *
     * @param int $p_speed
     *
     * @return array
     */
    private function processPortSpeed($p_speed)
    {
        $l_negative = false;
        $language = isys_application::instance()->container->get('language');

        if ($p_speed < 0) {
            $p_speed = $p_speed * -1;
            $l_negative = true;
        }

        if ($p_speed > 1000) {
            $l_speed_unit = 'C__PORT_SPEED__KBIT_S';
            $l_speed_unit_l = 'LC__CMDB__PORT_SPEED__KBITS';

            if ($p_speed >= 1000000) {
                $l_speed_unit = 'C__PORT_SPEED__MBIT_S';
                $l_speed_unit_l = 'LC__CMDB__PORT_SPEED__MBITS';

                if ($p_speed >= 1000000000) {
                    $l_speed_unit = 'C__PORT_SPEED__GBIT_S';
                    $l_speed_unit_l = 'LC__CMDB__PORT_SPEED__GBITS';
                }
            }
        } else {
            return [
                'value'    => $p_speed,
                'unit'     => $language->get('LC__CMDB__PORT_SPEED__BITS'),
                'negative' => $l_negative
            ];
        }

        return [
            'value'    => isys_convert::speed($p_speed, $l_speed_unit, C__CONVERT_DIRECTION__BACKWARD),
            'unit'     => $language->get($l_speed_unit_l),
            'negative' => $l_negative
        ];
    }

    /**
     * Helper method for converting cpu frequency
     *
     * @param int $p_cpu
     *
     * @return array
     */
    private function processCpu($p_cpu)
    {
        $l_negative = false;
        $language = isys_application::instance()->container->get('language');

        if ($p_cpu < 0) {
            $p_cpu = $p_cpu * -1;
            $l_negative = true;
        }

        $l_frequency_unit = 'C__FREQUENCY_UNIT__KHZ';
        $l_frequency_unit_l = 'LC__CMDB__FREQUENCY_UNIT__KHZ';

        if ($p_cpu >= (isys_convert::HERTZ * isys_convert::HERTZ)) {
            $l_frequency_unit = 'C__FREQUENCY_UNIT__MHZ';
            $l_frequency_unit_l = 'LC__CMDB__FREQUENCY_UNIT__MHZ';

            if ($p_cpu >= (isys_convert::HERTZ * isys_convert::HERTZ * isys_convert::HERTZ)) {
                $l_frequency_unit = 'C__FREQUENCY_UNIT__GHZ';
                $l_frequency_unit_l = 'LC__CMDB__FREQUENCY_UNIT__GHZ';

                if ($p_cpu >= (isys_convert::HERTZ * isys_convert::HERTZ * isys_convert::HERTZ * isys_convert::HERTZ)) {
                    $l_frequency_unit = 'C__FREQUENCY_UNIT__THZ';
                    $l_frequency_unit_l = 'LC__CMDB__FREQUENCY_UNIT__THZ';
                }
            }
        }

        return [
            'value'    => isys_convert::frequency($p_cpu, $l_frequency_unit, C__CONVERT_DIRECTION__BACKWARD),
            'unit'     => $language->get($l_frequency_unit_l),
            'negative' => $l_negative
        ];
    }

    /**
     * Helper method for converting memory
     *
     * @param int $p_memory
     *
     * @return array
     */
    private function processMemory($p_memory)
    {
        $l_negative = false;
        $language = isys_application::instance()->container->get('language');

        if ($p_memory < 0) {
            $p_memory = $p_memory * -1;
            $l_negative = true;
        }

        if ($p_memory > isys_convert::BYTE) {
            $l_memory_unit = 'C__MEMORY_UNIT__KB';
            $l_memory_unit_l = 'LC__CMDB__MEMORY_UNIT__KB';

            if ($p_memory >= (isys_convert::BYTE * isys_convert::BYTE)) {
                $l_memory_unit = 'C__MEMORY_UNIT__MB';
                $l_memory_unit_l = 'LC__CMDB__MEMORY_UNIT__MB';

                if ($p_memory >= (isys_convert::BYTE * isys_convert::BYTE * isys_convert::BYTE)) {
                    $l_memory_unit = 'C__MEMORY_UNIT__GB';
                    $l_memory_unit_l = 'LC__CMDB__MEMORY_UNIT__GB';

                    if ($p_memory >= (isys_convert::BYTE * isys_convert::BYTE * isys_convert::BYTE * isys_convert::BYTE)) {
                        $l_memory_unit = 'C__MEMORY_UNIT__TB';
                        $l_memory_unit_l = 'LC__CMDB__MEMORY_UNIT__TB';
                    }
                }
            }
        } else {
            $l_memory_unit = 'C__MEMORY_UNIT__B';
            $l_memory_unit_l = 'LC__CMDB__MEMORY_UNIT__Bytes';
        }

        return [
            'value'    => isys_convert::memory($p_memory, $l_memory_unit, C__CONVERT_DIRECTION__BACKWARD),
            'unit'     => $language->get($l_memory_unit_l),
            'negative' => $l_negative
        ];
    }
}
