commands/help.js

const Command = require('../core/command');
const Communication = require('../core/communication');
const definitions = require('./definitions.json');


/**
 * A command to help a user get more information about the  bot usage
 * 
 * @author Maksim Sandybekov
 * @date 11.05.2020
 * @version 1.0
 * 
 * @extends Command
 */
class Help extends Command {

    /**
     * @constructor
     * @param {string} fileName 
     */
    constructor(fileName) {
        super(fileName);
        
    }


    execute(message, args) {

         // Communication on channel is not allowed
         let com = new Communication(message);
         if (!com.isAllowed()) {
            return message.channel.send(com.getReason());
        }

        let userId = com.getUserId();
        let responseMessage = "";

        if (args.length > 0) {
            responseMessage =  this.getCommandHelp(args,  userId);
            return com.isDirect() ? message.author.send(responseMessage) : message.channel.send(responseMessage);
        }
        
        // Return the general 
        responseMessage = this.getHelpOverview(userId);
        return com.isDirect() ? message.author.send(responseMessage) : message.channel.send(responseMessage);
    }


    /**
     * Get the help response for a specific argument. 
     * 
     * @param {*} args The arguments passed with the message.
     * @param {*} userId The id of the calling user.
     * @return {string} The response text.
     */
    getCommandHelp(args, userId) {

        let mapping = this.__aggregateCommandMap();
        let responseMessage = this.getResponse("noSuchCommand", userId);

        // To many arguments
        if (args.length > 1) {
            responseMessage = this.getResponse("tooMany", userId);
        }

        // Get help for a specific command
        if (args.length == 1 && mapping.names.includes(args[0])) {
            let commandFile = mapping.map[args[0]];

            try {
                responseMessage = this.getResponse(commandFile, userId, args[0])            

            } catch (err) {
                responseMessage = this.getResponse("noHelp", userId);

            }
        }

        return responseMessage;
    }


    /**
     * Get the general help.
     * 
     * @param userId The id of the calling user.
     * @return {string} The repsonse text.
     */
    getHelpOverview(userId) {

        let mapping = this.__aggregateCommandMap();

        // General help info
        let filteredCommandNames = mapping.names.filter(name => name != 'help' && name != undefined);
        return this.getResponse('general', userId, filteredCommandNames.join(", "));
    }


    /**
     * Aggregate command names in an array and a map between filename and command name.
     * 
     * @private
     * @return {Object}
     */
    __aggregateCommandMap() {

        let commandNames = [];
        let commandNameMapping = {};
        for (let key of Object.keys(definitions)) {
            let command = definitions[key];

            if (command.name !== 'help' && command.name !== '_defaults_') {
                commandNames.push(command.name);
                commandNameMapping[command.name] = key;
            }
        }

        return {"map": commandNameMapping, "names": commandNames};
    }

}



module.exports = Help;