<?php

// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation for version 2.
// 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.
// Load global vars
global $config;

check_login();

if (! check_acl($config['id_user'], 0, 'AW')) {
    db_pandora_audit(
        'ACL Violation',
        'Trying to access massive plugin edition section'
    );
    include 'general/noaccess.php';
    return;
}

$plugin_id = (int) get_parameter('plugin_id');
$agent_ids = get_parameter('agent_ids', []);
$module_ids = get_parameter('module_ids', []);
$module_names = get_parameter('module_names', []);

if (is_ajax()) {
    $get_plugin = (bool) get_parameter('get_plugin');
    $get_agents = (bool) get_parameter('get_agents');
    $get_modules = (bool) get_parameter('get_modules');
    $get_module_plugin_macros = (bool) get_parameter('get_module_plugin_macros');

    if ($get_plugin) {
        $plugin = db_get_row('tplugin', 'id', $plugin_id);

        if (empty($plugin)) {
            $plugin = [];
        }

        if (isset($plugin['description'])) {
            $plugin['description'] = io_safe_output($plugin['description']);
            $plugin['description'] = str_replace("\n", '<br>', $plugin['description']);
        }

        if (isset($plugin['macros'])) {
            $macros = json_decode($plugin['macros'], true);
            if (!empty($macros)) {
                $macros = array_values($macros);

                if (!empty($macros)) {
                    $plugin['macros'] = $macros;
                }
            }
        }

        echo io_json_mb_encode($plugin);
        return;
    }

    if ($get_agents) {
        $sql = "SELECT ta.id_agente, ta.alias AS agent_alias,
					tam.nombre AS module_name
				FROM tagente ta
				INNER JOIN tagente_modulo tam
					ON ta.id_agente = tam.id_agente
						AND tam.id_plugin = $plugin_id
				ORDER BY ta.alias, tam.nombre";
        $result = db_get_all_rows_sql($sql);
        if (empty($result)) {
            $result = [];
        }

        $agents = [];

        $current_element = [];
        foreach ($result as $key => $value) {
            $id = (int) $value['id_agente'];
            $name = io_safe_output($value['agent_alias']);
            $module_name = $value['module_name'];

            if (!empty($current_element) && $current_element['id'] !== $id) {
                $agents[] = $current_element;
                $current_element = [];
            }

            $current_element['id'] = $id;
            $current_element['name'] = $name;

            if (!isset($current_element['module_names'])) {
                $current_element['module_names'] = [];
            }

            $current_element['module_names'][] = $module_name;
        }

        if (!empty($current_element)) {
            $agents[] = $current_element;
        }

        echo io_json_mb_encode($agents);
        return;
    }

    if ($get_module_plugin_macros) {
        $fields = ['macros'];
        $filter = [
            'id_plugin' => $plugin_id,
            'id_agente' => $agent_ids,
            'nombre'    => $module_names,
        ];
        $module_plugin_macros = db_get_all_rows_filter('tagente_modulo', $filter, $fields);
        $module_plugin_macros = io_safe_output($module_plugin_macros);
        if (empty($module_plugin_macros)) {
            $module_plugin_macros = [];
        }

        $module_plugin_macros = array_reduce(
            $module_plugin_macros,
            function ($carry, $item) {
                $macros = json_decode($item['macros'], true);
                if (!empty($macros)) {
                    $macros = array_values($macros);
                    if (!empty($macros)) {
                        $carry[] = $macros;
                    }
                }

                return $carry;
            },
            []
        );

        echo io_json_mb_encode($module_plugin_macros);
        return;
    }

    return;
}

$update = (bool) get_parameter('update');

if ($update) {
    try {
        $plugin = db_get_row('tplugin', 'id', $plugin_id);
        // Macros retrieved from the plugin definition
        $plugin_macros = [];
        if (isset($plugin['macros'])) {
            $plugin_macros = json_decode($plugin['macros'], true);
            if (!empty($plugin_macros)) {
                $plugin_macros = array_values($plugin_macros);
            }
        }

        // Error
        if (empty($plugin_macros)) {
            throw new Exception(__('Error retrieving the plugin macros'));
        }

        // Macros returned by the form
        $macros = get_parameter('macros', []);

        // Error
        if (empty($macros)) {
            throw new Exception(__('Error retrieving the modified macros'));
        }

        $fields = [
            'id_agente_modulo',
            'macros',
        ];
        $filter = [
            'id_plugin' => $plugin_id,
            'id_agente' => $agent_ids,
            'nombre'    => $module_names,
        ];
        $module_plugin_macros = db_get_all_rows_filter(
            'tagente_modulo',
            $filter,
            $fields
        );
        if (empty($module_plugin_macros)) {
            $module_plugin_macros = [];
        }

        // Error
        if (empty($module_plugin_macros)) {
            throw new Exception(__('Error retrieving the module plugin macros'));
        }

        // Begin transaction
        // db_process_sql_begin();
        $errors = 0;
        $count = 0;

        foreach ($module_plugin_macros as $item) {
            $module_id = $item['id_agente_modulo'];
            $module_macros_str = $item['macros'];
            // Macros retrieved from the agent module
            $module_macros = json_decode($module_macros_str, true);


            // Error
            if (empty($module_macros)) {
                throw new Exception(
                    __('Error retrieving the module plugin macros data')
                );
            }


            // Get the new module plugin macros
            $result_macros = array_map(
                function ($item) use ($macros, $module_macros) {
                    $result = [
                        'macro' => $item['macro'],
                        'desc'  => $item['desc'],
                        'help'  => $item['help'],
                        'hide'  => $item['hide'],
                    ];

                    // Get the default value os the module plugin macro
                    $default = array_reduce(
                        $module_macros,
                        function ($carry, $module_macro) use ($result) {
                            if (isset($module_macro['macro']) && $module_macro['macro'] == $result['macro']) {
                                $carry = $module_macro['value'];
                            }

                            return $carry;
                        },
                        ''
                    );

                    set_if_defined($result['value'], $macros[$item['macro']]);
                    set_unless_defined($result['value'], $default);

                    return $result;
                },
                $plugin_macros
            );

            // Error
            if (empty($result_macros)) {
                throw new Exception(__('Error building the new macros'));
            }



            $module_macros = io_json_mb_encode($result_macros, JSON_FORCE_OBJECT);
            if (empty($module_macros)) {
                $module_macros = $module_macros_str;
            }

            $values = ['macros' => $module_macros];
            $where = ['id_agente_modulo' => $module_id];
            // $result = db_process_sql_update('tagente_modulo', $values, $where, 'AND', false);
            $result = db_process_sql_update('tagente_modulo', $values, $where);

            if (!$result) {
                $errors++;
            } else {
                $count += $result;
            }
        }

        // if (!$errors) {
        // db_process_sql_commit();
        // }
        // else {
        // db_process_sql_rollback();
        // }
        // Result message
        ui_print_info_message(sprintf(__('%d modules updated'), $count));
    } catch (Exception $e) {
        ui_print_error_message($e->getMessage());
    }
}

$table = new StdClass();
$table->id = 'massive_plugin_edition';
$table->width = '100%';
$table->rowstyle = [];
$table->data = [];

// Plugins
$filter = ['order' => 'name'];
$fields = [
    'id',
    'name',
];
$plugins = db_get_all_rows_filter('tplugin', $filter, $fields);

if (empty($plugins)) {
    ui_print_empty_data(__('There are not registered plugins'));
    return;
}

$plugins_aux = [];
foreach ($plugins as $plugin) {
    $plugins_aux[$plugin['id']] = $plugin['name'];
}

$plugins = $plugins_aux;
unset($plugins_aux);

$plugins_select = html_print_select(
    $plugins,
    'plugin_id',
    $plugin_id,
    '',
    __('None'),
    0,
    true,
    false,
    false
);

$row = [];
$row[] = '<b>'.__('Plugin').'</b>';
$row[] = $plugins_select;

$table->data['plugin-ids-row'] = $row;

// Agents & modules
$row = [];

// Agents
$agents_select = html_print_select(
    $agent_ids,
    'agent_ids[]',
    false,
    '',
    '',
    0,
    true,
    true,
    false
);

$row[] = '<b>'.__('Agents').'</b>';
$row[] = $agents_select;

// Modules
// $modules_select = html_print_select ($module_ids, 'module_ids',
// false, '', '', 0, true, true, false);
$modules_select = html_print_select(
    $module_names,
    'module_names[]',
    false,
    '',
    '',
    0,
    true,
    true,
    false
);

$row[] = '<b>'._('Modules').'</b>';
$row[] = $modules_select;

$table->rowstyle['agents-modules-row'] = 'vertical-align: top; display: none';
$table->data['agents-modules-row'] = $row;

echo '<form method="POST" id="form-massive_plugin_edition"
	action="index.php?sec=gmassive&sec2=godmode/massive/massive_operations&tab=massive_plugins&option=edit_plugins">';

html_print_table($table);

echo "<div style='text-align: right; width: ".$table->width."'>";
html_print_input_hidden('update', 1);
html_print_submit_button(__('Update'), 'upd-btn', false, 'class="sub upd"');
echo '</div>';

echo '</form>';

?>

<script type="text/javascript">
    
    var $table = $('table#massive_plugin_edition'),
        $form = $('form#form-massive_plugin_edition'),
        $submitButton = $('input#submit-upd-btn'),
        $agentModulesRow = $('tr#massive_plugin_edition-agents-modules-row'),
        $pluginsSelect = $('select#plugin_id'),
        $agentsSelect = $('select#agent_ids'),
        $modulesSelect = $('select#module_names');
    
    var agents = [],
        ajaxPage = "<?php echo $config['homeurl'].'/'; ?>ajax.php",
        canSubmit = false,
        pluginXHR,
        agentsXHR,
        modulesXHR,
        modulePluginMacrosXHR;
    
    var allowSubmit = function (val) {
        if (typeof val === 'undefined')
            val = true;
        
        canSubmit = val;
        $submitButton.prop('disabled', !val);
    }

    var showSpinner = function () {
        var $loadingSpinner = $pluginsSelect.siblings('img#loading_spinner');
        
        if ($loadingSpinner.length > 0) {
            // Display inline instead using the show function
            // cause its absolute positioning.
            $loadingSpinner.css('display', 'inline');
            return;
        }
        
        $loadingSpinner = $('<img />');
            
        $loadingSpinner
            .prop('id', 'loading_spinner')
            .css('padding-left', '5px')
            .css('position', 'absolute')
            .css('top', $pluginsSelect.position().top + 'px')
            .prop('src', "<?php echo $config['homeurl'].'/'; ?>images/spinner.gif");
        
        $pluginsSelect.parent().append($loadingSpinner);
    }
    
    var hideSpinner = function () {
        var $loadingSpinner = $pluginsSelect.siblings('img#loading_spinner');
        
        if ($loadingSpinner.length > 0)
            $loadingSpinner.hide();
    }
    
    var clearModulePluginMacrosValues = function () {
        $('input.plugin-macro')
            .val('')
            .prop('disabled', true)
            .data('multiple_values', false)
            .prop('placeholder', '')
            .css('width', '99%')
            .siblings('button')
                .remove();
    }
    
    var hidePluginData = function () {
        $('table#massive_plugin_edition tr.plugin-data-row').hide();
    }
    
    var clearPluginData = function () {
        hidePluginData();
        clearModulePluginMacrosValues();
        $('table#massive_plugin_edition tr.plugin-data-row').remove();
    }
    
    var clearAgentsData = function () {
        $agentsSelect.empty();
    }
    
    var clearModulesData = function () {
        $modulesSelect.empty();
    }
    
    // Creates the plugin info and macros columns
    var fillPlugin = function (plugin) {
        clearPluginData();
        
        if (typeof plugin === 'undefined'
                || typeof plugin.execute === 'undefined'
                || typeof plugin.parameters === 'undefined'
                || typeof plugin.description === 'undefined'
                || typeof plugin.macros === 'undefined')
            throw new Error('<?php echo __('Invalid plugin data'); ?>');
        
        if (_.isString(plugin.macros)) {
            plugin.macros = JSON.parse(plugin.macros);
        }
        
        var $commandRow = $('<tr></tr>'),
            $commandCellTitle = $('<td></td>'),
            $commandCellData = $('<td></td>'),
            $descriptionRow = $('<tr></tr>'),
            $descriptionCellTitle = $('<td></td>'),
            $descriptionCellData = $('<td></td>');
        
        $commandCellTitle
            .addClass('plugin-data-cell')
            .css('font-weight', 'bold')
            .html('<?php echo __('Command'); ?>');
        $commandCellData
            .addClass('plugin-data-cell')
            .prop('colspan', 3)
            .css('font-style', 'italic')
            .html(plugin.execute + " " + plugin.parameters);
        $commandRow
            .addClass('plugin-data-row')
            .css('vertical-align', 'top')
            .append($commandCellTitle, $commandCellData);
        
        $descriptionCellTitle
            .addClass('plugin-data-cell')
            .css('font-weight', 'bold')
            .html('<?php echo __('Description'); ?>');
        $descriptionCellData
            .addClass('plugin-data-cell')
            .prop('colspan', 3)
            .html(plugin.description);
        $descriptionRow
            .addClass('plugin-data-row')
            .css('vertical-align', 'top')
            .append($descriptionCellTitle, $descriptionCellData);
        
        $table.append($commandRow, $descriptionRow);
        
        _.each(plugin.macros, function (macro, index) {
            var $macroRow = $('<tr></tr>'),
                $macroCellTitle = $('<td></td>'),
                $macroCellData = $('<td></td>'),
                $macroInput = $('<input>'),
                $macroIdentifier = $('<span></span>');
            
            $macroInput
                .prop('id', macro.macro)
                .prop('name', 'macros[' + macro.macro + ']')
                .addClass('plugin-macro')
                .addClass('plugin-data-input')
                .prop('type', function () {
                    if (Number(macro.hide))
                        return 'password';
                    else
                        return 'text';
                })
                .css('width', '99%')
                .prop('disabled', true)
                .autocomplete({
                    source: [],
                    minLength: 0,
                    disabled: true
                })
                .bind('focus', function() {
                    $(this).autocomplete("search");
                });
            
            $macroIdentifier
                .css('font-weight', 'normal')
                .css('padding-left', '5px')
                .append('(' + macro.macro + ')');
            
            $macroCellTitle
                .addClass('plugin-data-cell')
                .css('font-weight', 'bold')
                .html(macro.desc)
                .append($macroIdentifier);
            $macroCellData
                .addClass('plugin-data-cell')
                .prop('colspan', 3)
                .html($macroInput);
            $macroRow
                .addClass('plugin-data-row')
                .append($macroCellTitle, $macroCellData);
            
            $table.append($macroRow);
        });
    }
    
    var removeMultipleElementsButton = function (element) {
        element
            .css('width', '99%')
            .siblings('button')
                .remove();
    }
    
    // This button removes the special properties of the multiple values macro input
    var addMultipleElementsButton = function (element) {
        $button = $('<button>');
        
        $button
            .css('display', 'inline')
            .css('margin-left', '3px')
            .text("<?php echo __('Clear'); ?>")
            .click(function (e) {
                e.stopImmediatePropagation();
                e.preventDefault();
                
                if (!confirm("<?php echo __('Are you sure?'); ?>"))
                    return false;
                
                removeMultipleElementsButton(element);
                
                element
                    .val('')
                    .data('multiple_values', false)
                    .prop('placeholder', '');
            });
        
        element
            .css('width', '90%')
            .css('display', 'inline')
            .parent()
                .append($button);
    }
    
    // Fills the module plugin macros values
    var fillPluginMacros = function (moduleMacros) {
        clearModulePluginMacrosValues();
        
        if (!(moduleMacros instanceof Array))
            throw new Error('<?php echo __('Invalid macros array'); ?>');
        
        $("input.plugin-macro").each(function(index, el) {
            var id = $(el).prop('id');
            
            var values = _.chain(moduleMacros)
                .flatten()
                .where({ macro: id })
                .pluck('value')
                .uniq()
                .value();
            
            $(el).prop('disabled', false);
            
            // Remove the [""] element
            if (values.length == 1 && _.first(values) === '') {
                values = [];
            }
            
            if (values.length == 1) {
                $(el).val(_.first(values));
            }
            else if (values.length > 1) {
                $(el).val('')
                    .data('multiple_values', true)
                    .prop('placeholder', "<?php echo __('Multiple values'); ?>");
                addMultipleElementsButton($(el));
            }
            else {
                $(el).val('');
            }
            
            if ($(el).prop('type') !== 'password' && values.length > 0) {
                
                $(el).autocomplete("option", {
                        disabled: false,
                        source: values
                    });
            }
            else {
                $(el).autocomplete("option", { disabled: true });
            }
        });
        
        $(".ui-autocomplete")
            .css('max-height', '100px')
            .css('overflow-y', 'auto')
            .css('overflow-x', 'hidden')
            .css('padding-right', '20px')
            .css('text-align', 'left');
    }
    
    // Fills the agents select
    var fillAgents = function (agents, selected) {
        clearAgentsData();
        
        if (!(agents instanceof Array))
            throw new Error('<?php echo __('Invalid agents array'); ?>');
        
        _.each(agents, function (agent, index) {
            if (typeof agent.id !== 'undefined' && typeof agent.name !== 'undefined') {
                $('<option>')
                    .val(agent.id)
                    .text(agent.name)
                    .prop('selected', function () {
                        if (typeof selected !== 'undefined')
                            return false;
                        
                        return _.contains(selected, agent.id.toString());
                    })
                    .appendTo($agentsSelect);
            }
            else {
                throw new Error('<?php echo __('Invalid agent element'); ?>');
                return false;
            }
        });
    }
    
    // Fills the modules select
    var fillModules = function (modules, selected) {
        clearModulesData();
        
        if (!(modules instanceof Array))
            throw new Error('<?php echo __('Invalid modules array'); ?>');
        
        _.each(modules, function (module, index) {
            if (_.isString(module)) {
                $('<option>')
                    .val(module)
                    .text(module)
                    .prop('selected', function () {
                        if (typeof selected === 'undefined')
                            return false;
                        
                        return _.contains(selected, module);
                    })
                    .appendTo($modulesSelect);
            }
            else if (typeof module.id !== 'undefined' && typeof module.name !== 'undefined') {
                $('<option>')
                    .val(module.name)
                    .text(module.name)
                    .prop('selected', function () {
                        if (typeof selected === 'undefined')
                            return false;
                        
                        return _.contains(selected, module.name);
                    })
                    .appendTo($modulesSelect);
            }
            else {
                throw new Error('<?php echo __('Invalid module element'); ?>');
                return false;
            }
        });
        
    }
    
    var processGet = function (params, callback) {
        return jQuery.post(ajaxPage, params, 'json')
            .done(function (data, textStatus, jqXHR) {
                try {
                    data = JSON.parse(data);
                    callback(null, data);
                }
                catch (err) {
                    callback(err);
                }
            })
            .fail(function (jqXHR, textStatus, errorThrown) {
                if (textStatus !== 'abort')
                    callback(errorThrown);
            })
            .always(function (jqXHR, textStatus) {
                
            });
    }
    
    var getPlugin = function (pluginID, callback) {
        var params = {
            page: 'godmode/massive/massive_edit_plugins',
            get_plugin: 1,
            plugin_id: pluginID
        };
        
        pluginXHR = processGet(params, function (error, data) {
            callback(error, data);
        });
    }
    
    var getAgents = function (pluginID, callback) {
        var params = {
            page: 'godmode/massive/massive_edit_plugins',
            get_agents: 1,
            plugin_id: pluginID
        };
        
        agentsXHR = processGet(params, function (error, data) {
            callback(error, data);
        });
    }
    
    var getModules = function (pluginID, agentIDs, callback) {
        var params = {
            page: 'godmode/massive/massive_edit_plugins',
            get_modules: 1,
            plugin_id: pluginID,
            agent_ids: agentIDs
        };
        
        modulesXHR = processGet(params, function (error, data) {
            callback(error, data);
        });
    }
    
    var getModulePluginMacros = function (pluginID, agentIDs, moduleNames, callback) {
        var params = {
            page: 'godmode/massive/massive_edit_plugins',
            get_module_plugin_macros: 1,
            plugin_id: pluginID,
            agent_ids: agentIDs,
            module_names: moduleNames
        };
        
        modulePluginMacrosXHR = processGet(params, function (error, data) {
            callback(error, data);
        });
    }
    
    // Extract the a module names array from the agents
    var moduleNamesFromAgents = function (agents) {
        if (!(agents instanceof Array))
            throw new Error('<?php echo __('Invalid agents array'); ?>');
        
        var moduleNames = _.map(agents, function (agent) {
                return agent['module_names'];
            });
        moduleNames = _.intersection.apply(_, moduleNames);
        moduleNames = _.chain(moduleNames)
            .flatten()
            .uniq()
            .value();
        
        return moduleNames;
    }
    
    var agentsFilteredWithAgents = function (agents, agentIDs) {
        if (!(agents instanceof Array))
            throw new Error('<?php echo __('Invalid agents array'); ?>');
        
        var agentsFiltered = _.filter(agents, function (agent) {
            return _.contains(agentIDs, agent.id.toString());
        });
        
        // Hack. Is possible that find returns an object instead of an array
        // when the only array item is an object. Probably an Underscore.js bug
        if (typeof agentsFiltered !== 'undefined'
                && !(agentsFiltered instanceof Array)
                && (agentsFiltered instanceof Object))
            agentsFiltered = [agentsFiltered];
        
        return agentsFiltered;
    }
    
    var resetController = function () {
        if (typeof pluginXHR !== 'undefined') {
            pluginXHR.abort();
            pluginXHR = undefined;
        }
        if (typeof agentsXHR !== 'undefined') {
            agentsXHR.abort();
            agentsXHR = undefined;
        }
        if (typeof modulesXHR !== 'undefined') {
            modulesXHR.abort();
            modulesXHR = undefined;
        }
        if (typeof modulePluginMacrosXHR !== 'undefined') {
            modulePluginMacrosXHR.abort();
            modulePluginMacrosXHR = undefined;
        }
        
        allowSubmit(false);
        
        agents = [];
        
        hideSpinner();
        clearPluginData();
        
        $agentModulesRow.hide();
        clearAgentsData();
        clearModulesData();
    }
    
    var errorHandler = function (error) {
        console.log("<?php echo __('Error'); ?>: " + error.message);
        // alert("<?php echo __('Error'); ?>: " + err.message);
        
        // Init the plugin id select
        $pluginsSelect.val(0).change();
    }
    
    $pluginsSelect.change(function (e) {
        allowSubmit(false);
        
        // Plugin id
        var currentVal = $(this).val();
        
        resetController();
        
        if (currentVal == 0)
            return;
        
        try {
            showSpinner();
            
            // This asyc functions are executed at the same time
            getPlugin(currentVal, function (error, data) {
                if (error) {
                    errorHandler(error);
                    return;
                }
                
                plugin = data;
                
                try {
                    fillPlugin(plugin);
                    
                    // Hide spinner only if the another call has finished
                    if (typeof agentsXHR === 'undefined'
                            || agentsXHR.state() === 'resolved'
                            || agentsXHR.state() === 'rejected') {
                        hideSpinner();
                    }
                }
                catch (err) {
                    errorHandler(err);
                    return;
                }
            });
            
            // This asyc functions are executed at the same time
            getAgents(currentVal, function (error, data) {
                if (error) {
                    errorHandler(error);
                    return;
                }
                
                // This agent variable is global to this script scope
                agents = data;
                
                try {
                    if (agents.length > 0) {
                        fillAgents(agents);
                        
                        $agentModulesRow.show();
                    }
                    else {
                        alert("<?php echo __('There are no modules using this plugin'); ?>");
                        
                        // Abort the another call
                        if (typeof pluginXHR !== 'undefined') {
                            pluginXHR.abort();
                            pluginXHR = undefined;
                        }
                    }
                    
                    // Hide spinner only if the another call has finished
                    if (typeof pluginXHR === 'undefined'
                            || pluginXHR.state() === 'resolved'
                            || pluginXHR.state() === 'rejected') {
                        hideSpinner();
                    }
                }
                catch (err) {
                    errorHandler(err);
                    return;
                }
            });
        }
        catch (err) {
            errorHandler(err);
            return;
        }
        
    }).change(); // Trigger the change
    
    $agentsSelect.change(function (e) {
        allowSubmit(false);
        
        var ids = $(this).val();
        var modulesSelected = $modulesSelect.val();
        
        try {
            var agentsFiltered = agentsFilteredWithAgents(agents, ids);
            var modules = moduleNamesFromAgents(agentsFiltered);
                        
        for (var i = 0; i < modules.length; i++) {
            modules[i] = htmlDecode(modules[i]);
        }
            
            fillModules(modules, modulesSelected);
        }
        catch (err) {
            errorHandler(err);
            return;
        }
    });
    
    $modulesSelect.change(function (e) {
        allowSubmit(false);
        
        var pluginID = $pluginsSelect.val();
        var moduleNames = $(this).val();
        var agentIDs = $agentsSelect.val();
        
        if (_.isNull(moduleNames) || _.isUndefined(moduleNames)) {
            e.preventDefault();
            return false;
        }
        
        try {
            showSpinner();
            
            clearModulePluginMacrosValues();
            
            getModulePluginMacros(pluginID, agentIDs, moduleNames, function (error, data) {
                if (error) {
                    errorHandler(error);
                    return;
                }
                
                try {
                    var modulePluginMacros = data;
                    
                    if (_.isArray(modulePluginMacros) && modulePluginMacros.length > 0) {
                        fillPluginMacros(modulePluginMacros);
                        
                        allowSubmit(true);
                    }
                    else {
                        throw new Error('<?php echo __('There was a problem loading the module plugin macros data'); ?>');
                    }
                    
                    hideSpinner();
                }
                catch (err) {
                    errorHandler(err);
                    return;
                }
            });
        }
        catch (err) {
            errorHandler(err);
            return;
        }
    });
    
    $form.submit(function(e) {
        if (!canSubmit) {
            e.stopImmediatePropagation();
            e.preventDefault();
        }
        else {
            $form.find('input.plugin-macro')
                .filter(function() {
                    var val = $(this).val();
                    
                    if ($(this).data("multiple_values") == true
                            && (typeof val === 'undefined'
                                || val.length == 0))
                        return true;
                    else
                        return false;
                    
                }).prop('disabled', true);
        }
    });
    
    $(document).ready (function () {
        
    });
    
</script>