/**
 * Author: dkanus
 * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
 * License: GPL
 * Copyright 2021-2023 Anton Tarasenko
 *------------------------------------------------------------------------------
 * This file is part of Acedia.
 *
 * Acedia 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, version 3 of the License, or
 * (at your option) any later version.
 *
 * Acedia 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with Acedia.  If not, see <https://www.gnu.org/licenses/>.
 */
class Commands extends FeatureConfig
    perobjectconfig
    config(AcediaCommands);

/// Auxiliary struct for describing adding a particular command set to
/// a particular group of users.
struct CommandSetGroupPair {
    /// Name of the command set to add
    var public string name;
    /// Name of the group, for which to add this set
    var public string for;
};

/// Auxiliary struct for describing a rule to rename a particular command for
/// compatibility reasons.
struct RenamingRulePair {
    /// Command class to rename
    var public class<AcediaObject> rename;
    /// Name to use for that class
    var public string to;
};

/// Setting this to `true` enables players to input commands with "mutate"
/// console command.
/// Default is `true`.
var public config bool useMutateInput;
/// Setting this to `true` enables players to input commands right in the chat
/// by prepending them with [`chatCommandPrefix`].
/// Default is `true`.
var public config bool useChatInput;
/// Chat messages, prepended by this prefix will be treated as commands.
/// Default is "!". Empty values are also treated as "!".
var public config string chatCommandPrefix;
/// Allows to specify which user groups are used in determining command/votings
/// permission.
/// They must be specified in the order of importance: from the group with
/// highest level of permissions to the lowest. When determining player's
/// permission to use a certain command/voting, his group with the highest
/// available permissions will be used.
var public config array<string> commandGroup;
/// Add a specified `CommandList` to the specified user group
var public config array<CommandSetGroupPair> addCommandList;
/// Allows to specify a name for a certain command class
///
/// NOTE:By default command choses that name by itself and its not recommended
/// to override it. You should only use this setting in case there is naming
/// conflict between commands from different packages.
var public config array<RenamingRulePair> renamingRule;
/// Allows to specify a name for a certain voting class
///
/// NOTE:By default voting choses that name by itself and its not recommended
/// to override it. You should only use this setting in case there is naming
/// conflict between votings from different packages.
var public config array<RenamingRulePair> votingRenamingRule;

protected function HashTable ToData() {
    local int i;
    local HashTable data;
    local ArrayList innerList;
    local HashTable innerPair;

    data = __().collections.EmptyHashTable();
    data.SetBool(P("useChatInput"), useChatInput, true);
    data.SetBool(P("useMutateInput"), useMutateInput, true);
    data.SetString(P("chatCommandPrefix"), chatCommandPrefix);

    // Serialize `commandGroup`
    innerList = _.collections.EmptyArrayList();
    for (i = 0; i < commandGroup.length; i += 1) {
        innerList.AddString(commandGroup[i]);
    }
    data.SetItem(P("commandGroups"), innerList);
    _.memory.Free(innerList);

    // Serialize `addCommandSet`
    innerList = _.collections.EmptyArrayList();
    for (i = 0; i < addCommandList.length; i += 1) {
        innerPair = _.collections.EmptyHashTable();
        innerPair.SetString(P("name"), addCommandList[i].name);
        innerPair.SetString(P("for"), addCommandList[i].for);
        innerList.AddItem(innerPair);
        _.memory.Free(innerPair);
    }
    data.SetItem(P("commandSets"), innerList);
    _.memory.Free(innerList);

    // Serialize `renamingRule`
    innerList = _.collections.EmptyArrayList();
    for (i = 0; i < renamingRule.length; i += 1) {
        innerPair = _.collections.EmptyHashTable();
        innerPair.SetString(P("rename"), string(renamingRule[i].rename));
        innerPair.SetString(P("to"), renamingRule[i].to);
        innerList.AddItem(innerPair);
        _.memory.Free(innerPair);
    }
    data.SetItem(P("renamingRules"), innerList);
    _.memory.Free(innerList);

    // Serialize `votingRenamingRule`
    innerList = _.collections.EmptyArrayList();
    for (i = 0; i < votingRenamingRule.length; i += 1) {
        innerPair = _.collections.EmptyHashTable();
        innerPair.SetString(P("rename"), string(votingRenamingRule[i].rename));
        innerPair.SetString(P("to"), votingRenamingRule[i].to);
        innerList.AddItem(innerPair);
        _.memory.Free(innerPair);
    }
    data.SetItem(P("votingRenamingRules"), innerList);
    _.memory.Free(innerList);
    return data;
}

protected function FromData(HashTable source) {
    local int i;
    local ArrayList innerList;
    local HashTable innerPair;
    local CommandSetGroupPair nextCommandSetGroupPair;
    local RenamingRulePair nextRenamingRule;
    local class<AcediaObject> nextClass;

    if (source == none) {
        return;
    }
    useChatInput = source.GetBool(P("useChatInput"));
    useMutateInput = source.GetBool(P("useMutateInput"));
    chatCommandPrefix = source.GetString(P("chatCommandPrefix"), "!");

    // De-serialize `commandGroup`
    commandGroup.length = 0;
    innerList = source.GetArrayList(P("commandGroups"));
    if (innerList != none) {
        for (i = 0; i < commandGroup.length; i += 1) {
            commandGroup[i] = innerList.GetString(i);
        }
        _.memory.Free(innerList);
    }

    // De-serialize `addCommandSet`
    addCommandList.length = 0;
    innerList = source.GetArrayList(P("commandSets"));
    if (innerList != none) {
        for (i = 0; i < addCommandList.length; i += 1) {
            innerPair = innerList.GetHashTable(i);
            if (innerPair != none) {
                nextCommandSetGroupPair.name = innerPair.GetString(P("name"));
                nextCommandSetGroupPair.for = innerPair.GetString(P("for"));
                addCommandList[addCommandList.length] = nextCommandSetGroupPair;
                _.memory.Free(innerPair);
            }
        }
        _.memory.Free(innerList);
    }

    // De-serialize `renamingRule`
    renamingRule.length = 0;
    innerList = source.GetArrayList(P("renamingRules"));
    if (innerList != none) {
        for (i = 0; i < renamingRule.length; i += 1) {
            innerPair = innerList.GetHashTable(i);
            if (innerPair != none) {
                nextClass =
                    class<AcediaObject>(_.memory.LoadClass_S(innerPair.GetString(P("rename"))));
                nextRenamingRule.rename = nextClass;
                nextRenamingRule.to = innerPair.GetString(P("to"));
                renamingRule[renamingRule.length] = nextRenamingRule;
                _.memory.Free(innerPair);
            }
        }
        _.memory.Free(innerList);
    }

    // De-serialize `votingRenamingRule`
    votingRenamingRule.length = 0;
    innerList = source.GetArrayList(P("votingRenamingRules"));
    if (innerList != none) {
        for (i = 0; i < votingRenamingRule.length; i += 1) {
            innerPair = innerList.GetHashTable(i);
            if (innerPair != none) {
                nextClass =
                    class<AcediaObject>(_.memory.LoadClass_S(innerPair.GetString(P("rename"))));
                nextRenamingRule.rename = nextClass;
                nextRenamingRule.to = innerPair.GetString(P("to"));
                votingRenamingRule[votingRenamingRule.length] = nextRenamingRule;
                _.memory.Free(innerPair);
            }
        }
        _.memory.Free(innerList);
    }
}

protected function DefaultIt() {
    local CommandSetGroupPair defaultPair;

    useChatInput = true;
    useMutateInput = true;
    chatCommandPrefix = "!";
    commandGroup[0] = "admin";
    commandGroup[1] = "moderator";
    commandGroup[2] = "trusted";
    addCommandList.length = 0;
    defaultPair.name = "default";
    defaultPair.for = "all";
    addCommandList[0] = defaultPair;
    renamingRule.length = 0;
}

defaultproperties {
    configName = "AcediaCommands"
}