<?php

use idoit\Module\Pro\Algorithm\Filter;
use idoit\Module\Pro\Algorithm\Processor\TreeProcessor;
use idoit\Module\Pro\Algorithm\Visitor\TreeVisitor;

/**
 * i-doit
 *
 * Tree visualization class.
 *
 * @package     modules
 * @subpackage  pro
 * @author      Leonard Fischer <lfischer@i-doit.com>
 * @version     1.0
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 * @since       i-doit 1.5.0
 */
class isys_visualization_tree extends isys_visualization
{
    /**
     * This method will be called, if the current request is a AJAX request.
     *
     * @return  isys_visualization_tree
     * @author  Leonard Fischer <lfischer@i-doit.com>
     */
    public function process()
    {
        $l_service_filter = $l_profile_defaults = null;

        if (isset($_GET['profile']) && $_GET['profile'] > 0) {
            $l_profile = $_GET['profile'];
        } else {
            // Load the user-defined "default" profile.
            $l_profile = isys_usersettings::get('cmdb-explorer.default-profile', null);
        }

        if ($l_profile > 0) {
            $l_profile_defaults = isys_visualization_profile_model::instance($this->m_db)
                ->get_profile($l_profile)
                ->get_row_value('isys_visualization_profile__defaults');

            if ($l_profile_defaults && isys_format_json::is_json_array($l_profile_defaults)) {
                $l_profile_defaults = isys_format_json::decode($l_profile_defaults);

                if (isset($l_profile_defaults['obj-type-filter']) && is_array($l_profile_defaults['obj-type-filter'])) {
                    foreach ($l_profile_defaults['obj-type-filter'] as $l_object_type_id) {
                        $this->m_object_types[$l_object_type_id]['filtered'] = true;
                    }
                }

                if (isset($l_profile_defaults['service-filter'])) {
                    $l_service_filter = $l_profile_defaults['service-filter'];
                }
            }
        }

        // Add some rules to the smarty plugins...
        $l_rules = [
            'C_VISUALIZATION_OBJ_SELECTION'  => [
                'p_bDisableDetach'                                => true,
                'p_bInfoIconSpacer'                               => 0,
                'p_strValue'                                      => $_GET[C__CMDB__GET__OBJECT] ?: null,
                'p_strPlaceholder'                                => isys_application::instance()->container->get('language')
                    ->get('LC__CATG__CMDB__ODEP_ERROR_SELECT_OBJECT'),
                isys_popup_browser_object_ng::C__CALLBACK__ACCEPT => "idoit.callbackManager.triggerCallback('visualization-init-explorer');",
                'nowiki'                                          => true
            ],
            'C_VISUALIZATION_PROFILE'        => [
                C__CMDB__VISUALIZATION_TYPE => C__CMDB__VISUALIZATION_TYPE__TREE,
                'p_strSelectedID'           => $l_profile,
                'nowiki'                    => true,
                'p_strClass'                => 'input-small'
            ],
            'C_VISUALIZATION_SERVICE_FILTER' => [
                'p_strSelectedID' => $l_service_filter
            ]
        ];

        // And do the template assignments.
        $this->m_tpl->assign('visualization_type', 'isys_visualization_tree_model')
            ->assign('orientation', $l_profile_defaults['orientation'] ?: 'vertical')
            ->assign('object_types', $this->m_object_types)
            ->smarty_tom_add_rules('tom.content.top', $l_rules)
            ->include_template('contentbottomcontent', __DIR__ . '/assets/tree.tpl');

        return $this;
    }

    /**
     * This method will check, if the current request is a AJAX request and (if so) process the necessary logic.
     *
     * @author  Leonard Fischer <lfischer@i-doit.com>
     */
    public function process_ajax()
    {
        // We set the header information because we don't accept anything than JSON.
        header('Content-Type: application/json');

        $return = [
            'success' => true,
            'data'    => null,
            'message' => null
        ];

        try {
            $filter = $this->prepareFilter((int)$_POST['filter']);
            $language = isys_application::instance()->container->get('language');
            $objectId = (int)$_POST['object'];
            $profileId = (int)$_POST['profile'];

            $treeProcessor = new TreeProcessor($this->m_db, $language);
            $treeProcessor->setProfile($profileId);

            switch ($_GET['func']) {
                // Will be used for loading the initial data.
                case 'load-tree-data':
                    $treeProcessor->setFilter($filter);

                    // @see  ID-7223  Check if the object exists, before processing the rest.
                    if (!isys_cmdb_dao::instance($this->m_db)->obj_exists($objectId)) {
                        throw new Exception($language->get('LC__CMDB__OBJECT_DOES_NOT_EXIST', $objectId));
                    }

                    $explorerA = $treeProcessor->processAlgorithm($objectId, true, 0)->toArray();
                    $explorerB = $treeProcessor->processAlgorithm($objectId, false, 0)->toArray();

                    // We use the visitor for the "last inserted ID".
                    $return['data'] = [
                        'explorer_a'       => $explorerA,
                        'explorer_a_count' => \count($explorerA),
                        'explorer_b'       => $explorerB,
                        'explorer_b_count' => \count($explorerB),
                        'profile'          => isys_visualization_profile_model::instance($this->m_db)->get_profile_config($profileId)
                    ];
                    break;

                    // Will be used for loading parts of the tree.
                case 'load-tree-level':
                    $byMaster = (bool)$_POST['by_master'];
                    $lastId = (int)$_POST['last_id'];

                    $treeProcessor->setFilter($filter->setLevel(1));

                    $return['data'] = [
                        'nodes' => $treeProcessor->processAlgorithm($objectId, $byMaster, ($lastId + 10)),
                        'count' => TreeVisitor::getCounter()
                    ];
                    break;
            }
        } catch (Exception $e) {
            $return['success'] = false;
            $return['message'] = $e->getMessage();
        }

        echo isys_format_json::encode($return);
        die;
    }

    /**
     * @param int $filterId
     *
     * @return Filter
     */
    private function prepareFilter(int $filterId): Filter
    {
        $filter = new Filter();

        if ($filterId > 0) {
            $filterData = isys_itservice_dao_filter_config::instance($this->m_db)->get_data($filterId)['formatted__data'];
        }

        if (!isset($filterData['level']) || empty($filterData['level'])) {
            // @see  ID-8807  Limit the recursion run to something low, so we don't run into memory issues.
            $filterData['level'] = 2;

            // Also notify the user.
            $limitMessage = isys_application::instance()->container->get('language')->get('LC__VISUALIZATION__LEVEL_LIMITER');
            isys_notify::info($limitMessage, ['sticky' => true]);
        }

        if (is_numeric($filterData['priority'])) {
            $filter->setPriority((int)$filterData['priority']);
        }

        if (is_numeric($filterData['level'])) {
            $filter->setLevel((int)$filterData['level']);
        }

        if (is_array($filterData['object-type']) && count($filterData['object-type'])) {
            $filter->setObjectTypes($filterData['object-type']);
        }

        if (is_array($filterData['relation-type']) && count($filterData['relation-type'])) {
            $filter->setRelationTypes($filterData['relation-type']);
        }

        if (is_array($filterData['cmdb-status']) && count($filterData['cmdb-status'])) {
            $filter->setCmdbStatus($filterData['cmdb-status']);
        }

        return $filter;
    }
}
