/**
 *  Config class for storing map lists.
 *      Copyright 2022-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 FutilityNicknames extends FeatureConfig
    perobjectconfig
    config(FutilityNicknames);

enum NicknameSpacesAction {
    NSA_DoNothing,
    NSA_Trim,
    NSA_Simplify
};

enum NicknameColorPermissions {
    NCP_ForbidColor,
    NCP_ForceTeamColor,
    NCP_ForceSingleColor,
    NCP_AllowAnyColor
};

/// How to treat whitespace characters inside players' nicknames:
///
/// * `NSA_DoNothing` - does nothing, leaving whitespaces as they are;
/// * `NSA_Trim` - removes leading and trailing whitespaces for nicknames;
/// * `NSA_Simplify` - removes leading and trailing whitespaces
///     for nicknames, also reducing a sequence of whitespaces inside
///     nickname to a single space, e.g. "my   nick" becomes "my nick".
///
/// Default is `NSA_DoNothing`, same as on vanilla.
var public config NicknameSpacesAction spacesAction;
/// How to treat colored nicknames:
///
/// * `NCP_ForbidColor` - completely strips down any color from nicknames;
/// * `NCP_ForceTeamColor` - forces all nicknames to have player's current
///     team's color;
/// * `NCP_ForceSingleColor` - allows nickname to be painted with a single
///     color (sets nickname's color to that of the first character);
/// * `NCP_AllowAnyColor` - allows nickname to be colored in any way player
///     wants.
/// Default is `NCP_ForbidColor`, same as on vanilla.
var public config NicknameColorPermissions colorPermissions;
/// Set this to `true` if you wish to replace all whitespace characters with
/// underscores and `false` to leave them as is.
/// Default is `true`, same as on vanilla. However there is one difference:
/// Futility replaces all whitespace characters (including tabulations,
/// non-breaking spaces, etc.) instead of only ' '.
var public config bool replaceSpacesWithUnderscores;
/// Set this to `true` to remove single 'quotation marks' and `false` to
/// leave them. Default is `false`, same as on vanilla.
var public config bool removeSingleQuotationMarks;
/// Set this to `true` to remove dobule 'quotation marks' and `false` to
/// leave them. Default is `true`, same as on vanilla.
var public config bool removeDoubleQuotationMarks;
/// Should we replace empty player nicknames with a random fallback nickname
/// (defined in `fallbackNickname` array)?
var public config bool correctEmptyNicknames;
/// Max allowed nickname length. Negative values disable any length limits.
///
/// NOTE #1: `0` resets all nicknames to be empty and,
/// if `correctEmptyNicknames` is set to `true`, they will be replaced with
/// one of the fallback nicknames (see `correctEmptyNicknames` and
/// `fallbackNickname`).
///
/// NOTE #2: Because of how color swapping in vanilla Killing Floor works,
/// every color swap makes text count as being about 4 characters longer.
/// So if one uses too many colors in the nickname, for drawing functions
/// it will appear to be longer than it actually is and it *will* mess up
/// UI. Unless you are using custom HUD it is recommended to keep this value
/// at default `20` and forbid colored nicknames (by setting
/// `colorPermissions=NCP_ForbidColor`). Or to allow only one color (by setting
/// `colorPermissions=NCP_ForceSingleColor` or
/// `colorPermissions=NCP_ForceTeamColor`) and reducing `maxNicknameLength` to
/// `16` (20 characters - 4 for color swap).
/// If you want to increase the limit above that, you can also do your own
/// research by testing nicknames of various length on screen resolutions you
/// care about.
var public config int maxNicknameLength;
/// Array of fallback nicknames that will be used to replace any empty nicknames
/// if `correctEmptyNicknames` is set to `true`.
var public config array<string> fallbackNickname;

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

    data = __().collections.EmptyHashTable();
    data.SetString(P("spacesAction"), string(spacesAction));
    data.SetString(P("colorPermissions"), string(colorPermissions));
    data.SetBool(P("replaceSpacesWithUnderscores"), replaceSpacesWithUnderscores);
    data.SetBool(P("removeSingleQuotationMarks"), removeSingleQuotationMarks);
    data.SetBool(P("removeDoubleQuotationMarks"), removeDoubleQuotationMarks);
    data.SetBool(P("correctEmptyNicknames"), correctEmptyNicknames);
    data.SetInt(P("maxNicknameLength"), maxNicknameLength);
    fallbackNicknamesData = __().collections.EmptyArrayList();

    for (i = 0; i < fallbackNickname.length; i += 1) {
        fallbackNicknamesData.AddItem(__().text.FromFormattedString(fallbackNickname[i]));
    }
    data.SetItem(P("fallbackNickname"), fallbackNicknamesData);
    _.memory.Free(fallbackNicknamesData);
    return data;
}

protected function FromData(HashTable source) {
    local int i;
    local Text nextNickName, storedText;
    local ArrayList fallbackNicknamesData;

    if (source == none) {
        return;
    }
    storedText = source.GetText(P("spacesAction"));
    spacesAction = SpaceActionFromText(storedText);
    _.memory.Free(storedText);
    storedText = source.GetText(P("colorPermissions"));
    colorPermissions = ColorPermissionsFromText(storedText);
    _.memory.Free(storedText);
    replaceSpacesWithUnderscores = source.GetBool(P("replaceSpacesWithUnderscores"), true);
    removeSingleQuotationMarks = source.GetBool(P("removeSingleQuotationMarks"), true);
    removeDoubleQuotationMarks = source.GetBool(P("removeDoubleQuotationMarks"), true);
    correctEmptyNicknames = source.GetBool(P("correctEmptyNicknames"), true);
    maxNicknameLength = source.GetInt(P("correctEmptyNicknames"), 20);
    fallbackNicknamesData = source.GetArrayList(P("fallbackNickname"));
    if (fallbackNickname.length > 0) {
        fallbackNickname.length = 0;
    }
    for (i = 0; i < fallbackNicknamesData.GetLength(); i += 1) {
        nextNickName = fallbackNicknamesData.GetText(i);
        if (nextNickName != none) {
            fallbackNickname[i] = nextNickName.ToFormattedString();
        } else {
            fallbackNickname[i] = "";
        }
        _.memory.Free(nextNickName);
    }
    _.memory.Free(fallbackNicknamesData);
}

private function NicknameSpacesAction SpaceActionFromText(BaseText action) {
    if (action == none) {
        return NSA_DoNothing;
    }
    if (action.EndsWith(P("DoNothing"), SCASE_INSENSITIVE)) {
        return NSA_DoNothing;
    }
    if (action.EndsWith(P("Trim"), SCASE_INSENSITIVE)) {
        return NSA_Trim;
    }
    if (action.EndsWith(P("Simplify"), SCASE_INSENSITIVE)) {
        return NSA_Simplify;
    }
    return NSA_DoNothing;
}

private function NicknameColorPermissions ColorPermissionsFromText(BaseText permissions) {
    if (permissions == none) {
        return NCP_ForbidColor;
    }
    if (permissions.EndsWith(P("ForbidColor"), SCASE_INSENSITIVE)) {
        return NCP_ForbidColor;
    }
    if (permissions.EndsWith(P("TeamColor"), SCASE_INSENSITIVE)) {
        return NCP_ForceTeamColor;
    }
    if (permissions.EndsWith(P("SingleColor"), SCASE_INSENSITIVE)) {
        return NCP_ForceSingleColor;
    }
    if (permissions.EndsWith(P("AllowAnyColor"), SCASE_INSENSITIVE)) {
        return NCP_AllowAnyColor;
    }
    return NCP_ForbidColor;
}

protected function DefaultIt() {
    spacesAction = NSA_DoNothing;
    colorPermissions = NCP_ForbidColor;
    replaceSpacesWithUnderscores = true;
    removeSingleQuotationMarks = false;
    removeDoubleQuotationMarks = true;
    correctEmptyNicknames = true;
    maxNicknameLength = 20;
    if (fallbackNickname.length > 0) {
        fallbackNickname.length = 0;
    }
    fallbackNickname[0] = "Fresh Meat";
    fallbackNickname[1] = "Rotten Meat";
    fallbackNickname[2] = "Troll Meat";
    fallbackNickname[3] = "Rat Meat";
    fallbackNickname[4] = "Dog Meat";
    fallbackNickname[5] = "Elk Meat";
    fallbackNickname[6] = "Crab Meat";
    fallbackNickname[7] = "Boar Meat";
    fallbackNickname[8] = "Horker Meat";
    fallbackNickname[9] = "Bug Meat";
}

defaultproperties {
    configName = "FutilityNicknames"
    spacesAction = NSA_DoNothing
    colorPermissions = NCP_ForbidColor
    replaceSpacesWithUnderscores = true
    removeSingleQuotationMarks = false
    removeDoubleQuotationMarks = true
    correctEmptyNicknames = true
    maxNicknameLength = 20
    fallbackNickname(0) = "Fresh Meat"
    fallbackNickname(1) = "Rotten Meat"
    fallbackNickname(2) = "Troll Meat"
    fallbackNickname(3) = "Rat Meat"
    fallbackNickname(4) = "Dog Meat"
    fallbackNickname(5) = "Elk Meat"
    fallbackNickname(6) = "Crab Meat"
    fallbackNickname(7) = "Boar Meat"
    fallbackNickname(8) = "Horker Meat"
    fallbackNickname(9) = "Bug Meat"
}