<?php

use idoit\Module\Cmdb\Component\Table\Config\Refresher;
use idoit\Module\CustomFields\PropertyTypes;

/**
 * i-doit
 *
 * Custom fields.
 *
 * @package     i-doit
 * @subpackage  Modules
 * @author      Dennis Stücken <dstuecken@i-doit.org>
 * @author      Leonard Fischer <lfischer@i-doit.org>
 * @version     0.9
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 */
class isys_module_custom_fields extends isys_module
{
    // Define, if this module shall be displayed in the named menus.
    const DISPLAY_IN_MAIN_MENU   = false;
    const DISPLAY_IN_SYSTEM_MENU = true;
    const LABEL_POSITION_LEFT = 'left';
    const LABEL_POSITION_TOP = 'top';

    /**
     * @var  boolean
     */
    protected static $m_licenced = true;

    /**
     * @var  isys_module_request
     */
    private $m_userrequest;

    /**
     * This method builds the tree for the menu.
     *
     * @param   isys_component_tree $p_tree
     * @param   boolean             $p_system_module
     * @param   integer             $p_parent
     *
     * @author  Leonard Fischer <lfischer@i-doit.org>
     * @since   0.9.9-7
     * @see     isys_module::build_tree()
     */
    public function build_tree(isys_component_tree $p_tree, $p_system_module = true, $p_parent = null)
    {
        $l_parent = -1;

        if ($p_system_module) {
            $l_parent = $p_tree->find_id_by_title('Modules');
        }
        $moduleId = defined_or_default('C__MODULE__CUSTOM_FIELDS');

        if ($p_parent !== null && is_int($p_parent)) {
            $l_root = $p_parent;
        } else {
            $l_root = $p_tree->add_node($moduleId . '0', $l_parent, $this->language->get('LC__CMDB__TREE__SYSTEM__CUSTOM_CATEGORIES'));
        }

        $p_tree->add_node(
            $moduleId . '1',
            $l_root,
            $this->language->get('LC__CMDB__TREE__SYSTEM__CUSTOM_CATEGORIES'),
            isys_helper_link::create_url([
                C__GET__MODULE_ID     => defined_or_default('C__MODULE__SYSTEM'),
                C__GET__MODULE_SUB_ID => $moduleId,
                C__GET__TREE_NODE     => $moduleId . '1'
            ]),
            '',
            'images/icons/silk/application_form_add.png'
        );
    }

    /**
     * Starts module process.
     */
    public function start()
    {
        isys_auth_system_globals::instance()
            ->customfields(isys_auth::VIEW);

        if ($_GET[C__GET__MODULE_ID] != defined_or_default('C__MODULE__SYSTEM')) {
            $l_template = $this->m_userrequest->get_template();
            $l_tree = $this->m_userrequest->get_menutree();

            $this->build_tree($l_tree, false);

            // Assign tree.
            $l_template->assign("menu_tree", $l_tree->process($_GET[C__GET__TREE_NODE]));
        }

        // Handle requests.
        $this->process();
    }

    /**
     * List generation.
     *
     * @return  mixed
     */
    public function get_category_list()
    {
        $l_dao = new isys_custom_fields_dao(isys_application::instance()->container->get('database'));

        $l_data = $l_dao->get_data();

        if (is_countable($l_data) && count($l_data)) {
            $listDao = new isys_cmdb_dao_list_catg_custom_fields(isys_application::instance()->container->get('database'));
            $listDao->set_properties([
                'isysgui_catg_custom__title'            => [
                    C__PROPERTY__INFO => [
                        C__PROPERTY__INFO__TITLE => 'LC__CMDB__CATG__CATEGORY'
                    ]
                ],
                'isysgui_catg_custom__list_multi_value' => [
                    C__PROPERTY__INFO => [
                        C__PROPERTY__INFO__TITLE => 'LC__CMDB__CUSTOM_CATEGORIES__MULTIVALUE'
                    ]
                ],
                'isys__field_count'                     => [
                    C__PROPERTY__INFO => [
                        C__PROPERTY__INFO__TITLE => $this->language->get('LC__CMDB__CATG__QUANTITY') . ' ' . $this->language->get('LC__CMDB__CATG__CUSTOM_FIELDS')
                    ]
                ],
                'isys__assignment'                      => [
                    C__PROPERTY__INFO => [
                        C__PROPERTY__INFO__TITLE => 'LC__CMDB__CATG__CUSTOM_FIELDS__ASSIGNED_OBJECT_TYPES'
                    ]
                ]
            ]);

            $listLink = isys_helper_link::create_url([
                C__GET__MODULE_ID      => defined_or_default('C__MODULE__SYSTEM'),
                C__GET__MODULE_SUB_ID  => defined_or_default('C__MODULE__CUSTOM_FIELDS'),
                C__GET__TREE_NODE      => $_GET[C__GET__TREE_NODE],
                'id'                   => '[{isysgui_catg_custom__id}]'
            ]);

            $l_objList = new isys_component_list(null, $l_data);
            $l_objList->set_row_modifier($this, 'row_mod');
            $l_objList->config(
                [
                    'isysgui_catg_custom__title'            => 'LC__CMDB__CATG__CATEGORY',
                    'isysgui_catg_custom__list_multi_value' => 'LC__CMDB__CUSTOM_CATEGORIES__MULTIVALUE',
                    'isys__field_count'                     => $this->language->get('LC__CMDB__CATG__QUANTITY') . ' ' . $this->language->get('LC__CMDB__CATG__CUSTOM_FIELDS'),
                    'isys__assignment'                      => 'LC__CMDB__CATG__CUSTOM_FIELDS__ASSIGNED_OBJECT_TYPES',
                ],
                $listLink,
                '[{isysgui_catg_custom__id}]'
            );

            $l_objList->setRouteParams(['id' => null]);
            $l_objList->createTempTable();

            return $l_objList->getTempTableHtml();
        }

        isys_component_template_navbar::getInstance()
            ->set_active(false, C__NAVBAR_BUTTON__PURGE);

        return '<div class="p10">' . $this->language->get('LC__CMDB__FILTER__NOTHING_FOUND_STD') . '</div>';
    }

    /**
     * Initializes the module.
     *
     * @param   isys_module_request &$p_req
     *
     * @return  boolean
     */
    public function init(isys_module_request $p_req)
    {
        if (is_object($p_req)) {
            $this->m_userrequest = &$p_req;

            return true;
        }

        return false;
    }

    /**
     * Row modifier.
     *
     * @param  array &$p_row
     */
    public function row_mod(&$p_row)
    {
        global $g_dirs;

        $l_add_dots = false;
        $config = unserialize($p_row['isysgui_catg_custom__config']);
        $p_row['isys__field_count'] = is_countable($config) ? count($config) : 0;

        $l_assigns = isys_custom_fields_dao::instance(isys_application::instance()->container->get('database'))
            ->get_assignments($p_row['isysgui_catg_custom__id']);
        $l_obj_types = [];

        while ($l_a = $l_assigns->get_row()) {
            if (count($l_obj_types) > 10) {
                $l_add_dots = true;
                break;
            }

            $l_obj_types[] .= $this->language->get($l_a['isys_obj_type__title']);
        }

        sort($l_obj_types);

        if ($l_add_dots) {
            $l_obj_types[] = '...';
        }

        $p_row['isys__assignment'] = implode(', ', $l_obj_types);
        $p_row['isysgui_catg_custom__list_multi_value'] = $p_row['isysgui_catg_custom__list_multi_value'] ?
            '<span class="vam text-green"><img src="' . $g_dirs['images'] . 'icons/silk/bullet_green.png" class="vam mr5" />' . $this->language->get('LC__UNIVERSAL__YES') . '</span>' :
            '<span class="vam text-red"><img src="' . $g_dirs['images'] . 'icons/silk/bullet_red.png" class="vam mr5" />' . $this->language->get('LC__UNIVERSAL__NO') . '</span>';
    }

    /**
     * @param array  $configuration
     * @param string $categoryConstant
     *
     * @return array[]
     */
    public function prepare_api_example_for_config($configuration, $categoryConstant)
    {
        $apiExample = [
            'method'  => 'cmdb.category.save',
            'params'  => [
                'language' => isys_application::instance()->language,
                'apikey'   => 'your-key',
                'category' => 'C__CATG__CUSTOM_FIELDS_' . $categoryConstant,
                'object'   => 'your-object-id',
                'data'     => []
            ],
            'id'      => 1,
            'version' => '2.0'
        ];

        if (is_array($configuration)) {
            foreach ($configuration as $key => $field) {
                // @see  API-201 / ID-7100  Skip properties that don't contain data.
                if (in_array($field['type'], ['html', 'hr', 'script'], true)) {
                    continue;
                }

                $exampleContent = null;

                switch ($field['type']) {
                    case 'f_link':
                    case 'f_password':
                    case 'f_text':
                    case 'f_textarea':
                    case 'f_wysiwyg':
                        $exampleContent = 'textual-content';
                        break;
                    case 'f_popup':

                        if ($field['popup'] === 'dialog_plus') {
                            if ($field['extra'] === 'yes-no') {
                                $exampleContent = rand(0, 1);
                            } else {
                                $exampleContent = rand(1, 10);
                            }
                        }

                        if ($field['popup'] === 'calendar') {
                            if ($field['default'] == '1') {
                                $exampleContent = date('Y-m-d H:i:s');
                            } else {
                                $exampleContent = date('Y-m-d');
                            }
                        }
                        break;
                }

                if (isset($exampleContent)) {
                    $apiExample['params']['data'][$field['type'] . '_' . $key] = $exampleContent;
                } else {
                    $apiExample['params']['data'][$field['type'] . '_' . $key] = null;
                }
            }
        }

        $return = [
            'create' => $apiExample,
            'read' => $apiExample
        ];

        $return['read']['method'] = 'cmdb.category.read';
        unset($return['read']['params']['data']);

        return $return;
    }

    /**
     * Process custom field configuration
     */
    public function process()
    {
        try {
            $navbar = isys_component_template_navbar::getInstance();
            $template = isys_application::instance()->container->get('template');
            $database = isys_application::instance()->container->get('database');
            $htmlPurifier = isys_application::instance()->container->get('htmlpurifier');

            $l_dao = new isys_custom_fields_dao($database);

            $l_process_filter = (isset($_POST['filter']) && !empty($_POST['filter']));

            // Delete a custom category.
            if ($_POST[C__GET__NAVMODE] == C__NAVMODE__PURGE) {
                if (isset($_POST["id"]) && is_array($_POST["id"])) {
                    foreach ($_POST["id"] as $l_id) {
                        $l_dao->delete($l_id);
                    }
                }
            }

            $l_id = 0;
            if ($_POST[C__GET__NAVMODE] != C__NAVMODE__NEW) {
                $l_id = $_POST[C__GET__ID] ?: $_GET[C__GET__ID];
                if (is_array($l_id)) {
                    $l_id = $l_id[0];
                }
            }

            // Switch back to list on cancel.
            if ($_POST[C__GET__NAVMODE] == C__NAVMODE__CANCEL || $_POST[C__GET__NAVMODE] == C__NAVMODE__PURGE) {
                unset($_GET["id"]);
                $l_id = null;
            }

            // Save custom fields and category.
            if ($_POST[C__GET__NAVMODE] == C__NAVMODE__SAVE && !$l_process_filter) {
                $l_id = $_POST[C__GET__ID];

                if (is_array($_POST['field_title'])) {
                    foreach ($_POST['field_title'] as $l_field_key => $l_field_title) {
                        // Removing line breaks and tabs to prevent that the config can not be loaded
                        // Key fields should not have any line breaks or tabs
                        $l_field_title = str_replace(["\r", "\n", "\t"], '', $l_field_title);

                        /*
                         * This is necessary, for one reason:
                         *
                         * If we don't pre- or append a string the key will be an integer. This is a problem because:
                         * When we serialize integers errors might appear, when we change from a 32 to a 64 bit machine!
                         */
                        $l_key = 'c_' . ltrim($l_field_key, 'c_');

                        // Check if theres a corresponding type.
                        if (isset($_POST['field_type'][$l_field_key])) {
                            $l_type = $_POST['field_type'][$l_field_key];

                            // If type contains a comma, its a popup which needs more infos.
                            if (false !== strpos($l_type, ',')) {
                                $l_data = explode(',', $l_type);

                                if ($l_data[1] === 'yes-no') {
                                    $l_config[$l_key] = [
                                        'type'    => $l_data[0],
                                        'extra'   => $l_data[1],
                                        'title'   => $l_field_title,
                                        'default' => $_POST['field_dialog_default'][$l_field_key]
                                    ];
                                } elseif ($l_data[1] === 'date-datetime') {
                                    $l_config[$l_key] = [
                                        'type'    => $l_data[0],
                                        'popup'   => $l_data[2],
                                        'extra'   => $l_data[1],
                                        'title'   => $l_field_title,
                                        'default' => $_POST['field_dialog_default'][$l_field_key]
                                    ];
                                } else {
                                    $l_config[$l_key] = [
                                        'type'  => $l_data[0],
                                        'popup' => $l_data[1],
                                        'title' => $l_field_title
                                    ];
                                }
                                // Dialog or Dialog+?
                                if (in_array($l_data[1], ['dialog', 'dialog_plus', 'report_browser', 'checkboxes'], true)) {
                                    if (isset($_POST['field_dialog_identifier'][$l_field_key])) {
                                        $l_identifier = $_POST['field_dialog_identifier'][$l_field_key];

                                        if (empty($l_identifier) && $l_data[1] != 'report_browser') {
                                            $l_identifier = isys_glob_strip_accent(isys_glob_replace_accent($l_field_title), '_');
                                        }

                                        $l_config[$l_key]["identifier"] = $l_identifier;
                                    }

                                    if ($l_data[2] == 1) {
                                        $l_config[$l_key]['multiselection'] = 1;
                                    }
                                }

                                // Normal Object browser or with relation?
                                if ($l_data[1] === 'browser_object') {
                                    if ($l_data[2] == 1) {
                                        $l_identifier = $_POST["field_relation"][$l_field_key];
                                        $l_config[$l_key]["identifier"] = $l_identifier;
                                    }

                                    if ($l_data[3] == 1) {
                                        $l_config[$l_key]['multiselection'] = 1;
                                    }
                                }
                            } else {
                                $l_config[$l_key] = [
                                    "type"  => $l_type,
                                    "title" => $htmlPurifier->purify($l_field_title)
                                ];
                            }

                            if (isset($_POST['field_visibility'][$l_field_key])) {
                                $l_config[$l_key]['visibility'] = $_POST['field_visibility'][$l_field_key];
                            }
                        }

                        // Save show_in_list config.
                        if (isset($_POST["field_show_in_list"][$l_field_key])) {
                            $l_config[$l_key]['show_in_list'] = 1;
                        } else {
                            $l_config[$l_key]['show_in_list'] = 0;
                        }

                        // @see  ID-641  Save the 'inline' configuration.
                        $l_config[$l_key]['show_inline'] = (int)$_POST['field_show_inline'][$l_field_key];
                    }
                }

                if (isset($l_config) && is_countable($l_config) && count($l_config) > 0) {
                    try {
                        if ($l_id > 0) {
                            $l_dao->save($l_id, $_POST["category_title"], $l_config, 0, 0, $_POST["multivalued"], $_POST['category_constant'], $_POST['label_position']);
                        } else {
                            $l_id = $l_dao->create($_POST["category_title"], $l_config, 0, 0, $_POST["multivalued"], $_POST['category_constant'], $_POST['label_position']);
                        }

                        // Clear all object type assignments.
                        $l_dao->clear_assignments($l_id);

                        // (Re-)Add selected object type assignments.
                        $l_otypes = explode(",", $_POST["object_types__selected_values"]);

                        // Add Generic template.
                        if (defined('C__OBJTYPE__GENERIC_TEMPLATE')) {
                            if (!in_array(C__OBJTYPE__GENERIC_TEMPLATE, $l_otypes)) {
                                $l_otypes[] = C__OBJTYPE__GENERIC_TEMPLATE;
                            }
                        }

                        if (is_array($l_otypes)) {
                            foreach ($l_otypes as $l_obj_type) {
                                if ($l_obj_type > 0) {
                                    $l_dao->assign($l_id, $l_obj_type);
                                }
                            }
                            $l_dao->clearUnassignedOverviewTypes($l_id, $l_otypes);
                        }

                        // Update constant cache:
                        isys_component_constant_manager::instance()->clear_dcm_cache();

                        // @see  ID-6382  Refresh the table configurations of the assigned object types.
                        $refresher = new Refresher($database);

                        $sql = 'SELECT GROUP_CONCAT(isys_obj_type__const) AS constantList 
                            FROM isys_obj_type 
                            WHERE isys_obj_type__id ' . $l_dao->prepare_in_condition($l_otypes) . ';';

                        $constantList = $l_dao
                            ->retrieve($sql)
                            ->get_row_value('constantList');

                        $objectTypeConstants = explode(',', $constantList);

                        foreach ($objectTypeConstants as $objectTypeConstant) {
                            $refresher->processByObjectTypeConstant($objectTypeConstant);
                        }

                        isys_notify::success($this->language->get('LC__INFOBOX__DATA_WAS_SAVED'));
                        unset($_GET["id"], $l_id);
                    } catch (Exception $e) {
                        isys_notify::error($e->getMessage(), ['sticky' => true]);
                    }
                } else {
                    isys_application::instance()->container['notify']->error("Specify your fields, please.");
                }
            }

            $l_edit_right = isys_auth_system::instance()
                ->is_allowed_to(isys_auth::EDIT, 'GLOBALSETTINGS/CUSTOMFIELDS');
            $l_delete_right = isys_auth_system::instance()
                ->is_allowed_to(isys_auth::DELETE, 'GLOBALSETTINGS/CUSTOMFIELDS');

            $relationData = [];
            $labelPosition = self::LABEL_POSITION_LEFT;

            $l_dao_rel = new isys_cmdb_dao_category_g_relation(isys_application::instance()->container->get('database'));
            $relationTypeData = $l_dao_rel->get_relation_types_as_array(null);

            // Necessary logic for displaying a sorted list of relation types.
            foreach ($relationTypeData as $relationTypeId => $relationType) {
                $relationData[strtolower($relationType['title_lang'])] = [
                    'id'    => $relationTypeId,
                    'title' => $relationType['title_lang']
                ];
            }

            ksort($relationData);

            $propertyTypes = PropertyTypes::getAll($this->language);

            // Sort the properties.
            usort($propertyTypes, function ($a, $b) {
                return strcasecmp($a['title'], $b['title']);
            });

            $template
                ->assign('relation_types', array_values($relationData))
                ->assign('propertyTypes', $propertyTypes)
                ->assign('id', null);

            // Init vars
            $l_multivalued = 0;
            $l_title = $l_selected = $l_constant = null;

            // New or Edit.
            if (isset($l_id) && $l_id > 0 && $_POST[C__GET__NAVMODE] != C__NAVMODE__NEW) {
                $l_data = $l_dao->get_data($l_id);
                $l_row = $l_data->get_row();
                $labelPosition = $l_row['isysgui_catg_custom__label_position'];
                $l_title = $l_row['isysgui_catg_custom__title'];
                $l_multivalued = $l_row['isysgui_catg_custom__list_multi_value'];
                $l_constant = $l_row['isysgui_catg_custom__const'];

                if (strpos($l_constant, 'C__CATG__CUSTOM_FIELDS_') === 0) {
                    $l_constant = substr($l_constant, 23);
                } else {
                    isys_notify::warning($this->language->get('LC__CMDB__CUSTOM_CATEGORIES_OLD_CONSTANT_WARNING'), ['sticky' => true]);
                }

                $l_row['isysgui_catg_custom__config'] = str_replace("'", '"', $l_row['isysgui_catg_custom__config']);
                $l_config = $l_example_config = unserialize($l_row['isysgui_catg_custom__config']);

                foreach ($l_config as $l_key => $l_value) {
                    // @see  API-201 / ID-7100  Skip properties that don't contain data.
                    if (in_array($l_value['type'], ['html', 'hr', 'script'], true)) {
                        unset($l_example_config[$l_key]);
                    }
                }

                $template
                    ->assign('category_config', $l_config)
                    ->assign('apiExample', $this->prepare_api_example_for_config($l_config, $l_constant))
                    ->assign('apiExampleConfig', $l_example_config)
                    ->assign('id', $l_id)
                    ->assign('entryCount', $l_dao->count($l_id))
                    ->assign('valueCount', $l_dao->count_values($l_id));

                $navbar
                    ->set_active($l_edit_right, C__NAVBAR_BUTTON__SAVE)
                    ->set_active(true, C__NAVBAR_BUTTON__CANCEL)
                    ->set_visible(true, C__NAVBAR_BUTTON__SAVE);
            } elseif ($_POST[C__GET__NAVMODE] == C__NAVMODE__NEW) {
                $_GET[C__CMDB__GET__EDITMODE] = 1;
                $navbar
                    ->set_active($l_edit_right, C__NAVBAR_BUTTON__SAVE)
                    ->set_active(true, C__NAVBAR_BUTTON__CANCEL)
                    ->set_visible(true, C__NAVBAR_BUTTON__SAVE);
            } else {
                $l_list = $this->get_category_list();

                $template
                    ->assign('g_list', $l_list)
                    ->smarty_tom_add_rule('tom.content.bottom.buttons.*.p_bInvisible=1');

                $navbar
                    ->set_active($l_delete_right, C__NAVBAR_BUTTON__PURGE)
                    ->set_active($l_edit_right, C__NAVBAR_BUTTON__EDIT)
                    ->set_active($l_edit_right, C__NAVBAR_BUTTON__NEW)
                    ->set_visible(true, C__NAVBAR_BUTTON__PURGE)
                    ->set_visible(true, C__NAVBAR_BUTTON__EDIT)
                    ->set_visible(true, C__NAVBAR_BUTTON__NEW)
                    // We use this line to prevent the breadcrumb from loading - because this will trigger a "History.pushState()" call.
                    ->set_js_onclick(
                        "$('sort').setValue(''); $('navMode').setValue('" . C__NAVMODE__EDIT . "'); form_submit(false, false, false, true);",
                        C__NAVBAR_BUTTON__EDIT
                    );
            }

            $l_cmdb_dao = isys_cmdb_dao::instance(isys_application::instance()->container->get('database'));
            $l_object_types = $l_cmdb_dao->get_objtype();
            $l_otypes = [];

            while ($l_row = $l_object_types->get_row()) {
                if (defined('C__OBJTYPE__GENERIC_TEMPLATE') && $l_row['isys_obj_type__id'] == C__OBJTYPE__GENERIC_TEMPLATE) {
                    // Skip generic Template.
                    continue;
                }

                if (isset($l_id) && $l_id > 0) {
                    $l_sel = $l_dao->get_assignments($l_id, $l_row['isys_obj_type__id']);
                    $l_selected = ($l_sel->num_rows() > 0);
                }

                $l_row['isys_obj_type__title'] = $this->language->get($l_row['isys_obj_type__title']);

                $l_otypes[$l_row['isys_obj_type__title']] = [
                    'val' => $l_row['isys_obj_type__title'],
                    'hid' => 0,
                    'sel' => $l_selected,
                    'id'  => $l_row['isys_obj_type__id']
                ];
            }

            ksort($l_otypes);

            // Set smarty rules
            $l_rules = [
                'category_title'    => [
                    'p_strValue' => $l_title,
                    'p_strClass' => 'input-small'
                ],
                'object_types'      => [
                    'p_arData'   => array_values($l_otypes),
                    'p_strClass' => 'input-small'
                ],
                'category_constant' => [
                    'p_strValue' => $l_constant,
                    'p_strClass' => 'input-small'
                ],
                'multivalued'       => [
                    'p_arData'        => get_smarty_arr_YES_NO(),
                    'p_strSelectedID' => $l_multivalued,
                    'p_bDbFieldNN'    => true,
                    'p_strClass'      => 'input-small'
                ],
                'label_position'    => [
                    'p_arData'        => [
                        self::LABEL_POSITION_LEFT => 'LC__UNIVERSAL__LEFT',
                        self::LABEL_POSITION_TOP  => 'LC__UNIVERSAL__TOP'
                    ],
                    'p_strSelectedID' => $labelPosition,
                    'p_bDbFieldNN'    => true,
                    'p_strClass'      => 'input-small'
                ],
                'count_of_custom_fields' => [
                    'p_strClass' => 'input-mini'
                ]
            ];
            $template
                ->activate_editmode()
                ->assign('content_title', $this->language->get('LC__CMDB__TREE__SYSTEM__CUSTOM_CATEGORIES'))
                ->include_template('contentbottomcontent', self::getPath() . 'templates/config.tpl')
                ->smarty_tom_add_rule('tom.content.navbar.cRecStatus.p_bInvisible=1')
                ->smarty_tom_add_rules('tom.content.bottom.content', $l_rules);
        } catch (Exception $e) {
            throw $e;
        }
    }
}
