/**
 *  Config class for storing map lists.
 *      Copyright 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 CommandList extends AcediaConfig
    perObjectConfig
    config(AcediaCommands);

//! `CommandList` describes a set of commands and votings that can be made
//! available to users inside Commands feature
//!
//! Optionally, permission configs can be specified for commands and votings,
//! allowing server admins to create command lists for different groups player
//! with the same commands, but different permissions.

// For storing `class<Command>` - `string` pairs in the config
struct CommandConfigStoragePair {
    var public class<Command> cmd;
    var public string config;
};

// For storing `class` - `string` pairs in the config
struct VotingConfigStoragePair {
    var public class<Voting> vtn;
    var public string config;
};

// For returning `class` - `Text` pairs into other Acedia classes
struct EntityConfigPair {
    var public class<AcediaObject> class;
    var public Text config;
};

/// Allows to specify if this list should only be added when server is running
/// in debug mode.
/// `true` means yes, `false` means that list will always be available.
var public config bool debugOnly;
/// Adds a command of specified class with a "default" permissions config.
var public config array< class<Command> > command;
/// Adds a command of specified class with specified permissions config
var public config array<CommandConfigStoragePair> commandWith;
/// Adds a voting of specified class with a "default" permissions config
var public config array< class<Voting> > voting;
/// Adds a voting of specified class with specified permissions config
var public config array<VotingConfigStoragePair> votingWith;

public final function array<EntityConfigPair> GetCommandData() {
    local int i;
    local EntityConfigPair nextPair;
    local array<EntityConfigPair> result;

    for (i = 0; i < command.length; i += 1) {
        if (command[i] != none) {
            nextPair.class = command[i];
            result[result.length] = nextPair;
        }
    }
    for (i = 0; i < commandWith.length; i += 1) {
        if (commandWith[i].cmd != none) {
            nextPair.class = commandWith[i].cmd;
            if (commandWith[i].config != "") {
                nextPair.config = _.text.FromString(commandWith[i].config);
            }
            result[result.length] = nextPair;
            // Moved into the `result`
            nextPair.config = none;
        }
    }
    return result;
}

public final function array<EntityConfigPair> GetVotingData() {
    local int i;
    local EntityConfigPair nextPair;
    local array<EntityConfigPair> result;

    for (i = 0; i < voting.length; i += 1) {
        if (voting[i] != none) {
            nextPair.class = voting[i];
            result[result.length] = nextPair;
        }
    }
    for (i = 0; i < votingWith.length; i += 1) {
        if (votingWith[i].vtn != none) {
            nextPair.class = votingWith[i].vtn;
            if (votingWith[i].config != "") {
                nextPair.config = _.text.FromString(votingWith[i].config);
            }
            result[result.length] = nextPair;
            // Moved into the `result`
            nextPair.config = none;
        }
    }
    return result;
}

protected function HashTable ToData() {
    local int i;
    local ArrayList entityArray;
    local HashTable result, innerPair;

    result = _.collections.EmptyHashTable();
    result.SetBool(P("debugOnly"), debugOnly);
    entityArray = _.collections.EmptyArrayList();
    for (i = 0; i < command.length; i += 1) {
        entityArray.AddString(string(command[i]));
    }
    result.SetItem(P("commands"), entityArray);
    _.memory.Free(entityArray);

    entityArray = _.collections.EmptyArrayList();
    for (i = 0; i < voting.length; i += 1) {
        entityArray.AddString(string(voting[i]));
    }
    result.SetItem(P("votings"), entityArray);
    _.memory.Free(entityArray);

    entityArray = _.collections.EmptyArrayList();
    for (i = 0; i < commandWith.length; i += 1) {
        innerPair = _.collections.EmptyHashTable();
        innerPair.SetString(P("command"), string(commandWith[i].cmd));
        innerPair.SetString(P("config"), commandWith[i].config);
        entityArray.AddItem(innerPair);
        _.memory.Free(innerPair);
    }
    result.SetItem(P("commandsWithConfig"), entityArray);
    _.memory.Free(entityArray);

    entityArray = _.collections.EmptyArrayList();
    for (i = 0; i < votingWith.length; i += 1) {
        innerPair = _.collections.EmptyHashTable();
        innerPair.SetString(P("voting"), string(votingWith[i].vtn));
        innerPair.SetString(P("config"), votingWith[i].config);
        entityArray.AddItem(innerPair);
        _.memory.Free(innerPair);
    }
    result.SetItem(P("votingsWithConfig"), entityArray);
    _.memory.Free(entityArray);
    return result;
}

protected function FromData(HashTable source) {
    local int i;
    local ArrayList entityArray;
    local HashTable innerPair;
    local class<Command> nextCommandClass;
    local class<Voting> nextVotingClass;
    local CommandConfigStoragePair nextCommandPair;
    local VotingConfigStoragePair nextVotingPair;

    if (source == none) {
        return;
    }
    debugOnly = source.GetBool(P("debugOnly"));
    command.length = 0;
    entityArray = source.GetArrayList(P("commands"));
    if (entityArray != none) {
        for (i = 0; i < entityArray.GetLength(); i += 1) {
            nextCommandClass = class<Command>(_.memory.LoadClass_S(entityArray.GetString(i)));
            if (nextCommandClass != none) {
                command[command.length] = nextCommandClass;
            }
        }
    }
    _.memory.Free(entityArray);

    voting.length = 0;
    entityArray = source.GetArrayList(P("votings"));
    if (entityArray != none) {
        for (i = 0; i < entityArray.GetLength(); i += 1) {
            nextVotingClass = class<Voting>(_.memory.LoadClass_S(entityArray.GetString(i)));
            if (nextVotingClass != none) {
                voting[voting.length] = nextVotingClass;
            }
        }
    }
    _.memory.Free(entityArray);

    commandWith.length = 0;
    entityArray = source.GetArrayList(P("commandsWithConfig"));
    if (entityArray != none) {
        for (i = 0; i < entityArray.GetLength(); i += 1) {
            innerPair = entityArray.GetHashTable(i);
            if (innerPair == none) {
                continue;
            }
            nextCommandPair.cmd =
                class<Command>(_.memory.LoadClass_S(innerPair.GetString(P("command"))));
            nextCommandPair.config = innerPair.GetString(P("config"));
            _.memory.Free(innerPair);
            if (nextCommandPair.cmd != none) {
                commandWith[commandWith.length] = nextCommandPair;
            }
        }
    }
    _.memory.Free(entityArray);

    votingWith.length = 0;
    entityArray = source.GetArrayList(P("votingsWithConfig"));
    if (entityArray != none) {
        for (i = 0; i < entityArray.GetLength(); i += 1) {
            innerPair = entityArray.GetHashTable(i);
            if (innerPair == none) {
                continue;
            }
            nextVotingPair.vtn =
                class<Voting>(_.memory.LoadClass_S(innerPair.GetString(P("voting"))));
            nextVotingPair.config = innerPair.GetString(P("config"));
            _.memory.Free(innerPair);
            if (nextVotingPair.vtn != none) {
                votingWith[votingWith.length] = nextVotingPair;
            }
        }
    }
    _.memory.Free(entityArray);
}

protected function DefaultIt() {
    debugOnly = false;
    command.length = 0;
    commandWith.length = 0;
    voting.length = 0;
    votingWith.length = 0;
    command[0] = class'ACommandHelp';
    command[1] = class'ACommandVote';
}

defaultproperties {
    configName = "AcediaCommands"
    supportsDataConversion = true
    debugOnly = false
    command(0) = class'ACommandHelp'
    command(1) = class'ACommandVote'
}