/**
 * Author: dkanus
 * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
 * License: GPL
 * 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 ACommandFakers extends Command
    dependsOn(VotingModel);

var private array<UserID> fakers;

protected static function StaticFinalizer() {
    __().memory.FreeMany(default.fakers);
    default.fakers.length = 0;
}

protected function BuildData(CommandDataBuilder builder) {
    builder.Group(P("debug"));
    builder.Summary(P("Adds fake voters for testing \"vote\" command."));
    builder.Describe(P("Displays current fake voters."));

    builder.SubCommand(P("amount"));
    builder.Describe(P("Specify amount of faker that are allowed to vote."));
    builder.ParamInteger(P("fakers_amount"));

    builder.SubCommand(P("vote"));
    builder.Describe(P("Make a vote as a faker."));
    builder.ParamInteger(P("faker_number"));
    builder.ParamBoolean(P("vote_for"));
}

protected function Executed(
    CallData arguments,
    EPlayer instigator,
    CommandPermissions permissions
) {
    if (arguments.subCommandName.IsEmpty()) {
        DisplayCurrentFakers();
    } else if (arguments.subCommandName.Compare(P("amount"), SCASE_INSENSITIVE)) {
        ChangeAmount(arguments.parameters.GetInt(P("fakers_amount")));
    } else if (arguments.subCommandName.Compare(P("vote"), SCASE_INSENSITIVE)) {
        CastVote(
            arguments.parameters.GetInt(P("faker_number")),
            arguments.parameters.GetBool(P("vote_for")));
    }
}

public final static function /*borrow*/ array<UserID> BorrowDebugVoters() {
    return default.fakers;
}

private final function CastVote(int fakerID, bool voteFor) {
    local Voting currentVoting;

    if (fakerID < 0 || fakerID >= fakers.length) {
        callerConsole
            .UseColor(_.color.TextFailure)
            .WriteLine(P("Faker number is out of bounds."));
        return;
    }
    currentVoting = _.commands.GetCurrentVoting();
    if (currentVoting == none) {
        callerConsole
            .UseColor(_.color.TextFailure)
            .WriteLine(P("There is no voting active right now."));
        return;
    }
    currentVoting.CastVoteByID(fakers[fakerID], voteFor);
    _.memory.Free(currentVoting);
}

private final function ChangeAmount(int newAmount) {
    local int i;
    local Text nextIDName;
    local UserID nextID;
    local Voting currentVoting;

    if (newAmount < 0) {
        callerConsole
            .UseColor(_.color.TextFailure)
            .WriteLine(P("Cannot specify negative amount."));
    }
    if (newAmount == fakers.length) {
        callerConsole
            .UseColor(_.color.TextNeutral)
            .WriteLine(P("Specified same amount of fakers."));
    } else if (newAmount > fakers.length) {
        for (i = fakers.length; i < newAmount; i += 1) {
            nextIDName = _.text.FromString("DEBUG:FAKER:" $ i);
            nextID = UserID(__().memory.Allocate(class'UserID'));
            nextID.Initialize(nextIDName);
            _.memory.Free(nextIDName);
            fakers[fakers.length] = nextID;
        }
    } else {
        for (i = fakers.length - 1; i >= newAmount; i -= 1) {
            _.memory.Free(fakers[i]);
        }
        fakers.length = newAmount;
    }
    default.fakers = fakers;
    currentVoting = _.commands.GetCurrentVoting();
    if (currentVoting != none) {
        currentVoting.SetDebugVoters(default.fakers);
        _.memory.Free(currentVoting);
    }
}

private function DisplayCurrentFakers() {
    local int i;
    local VotingModel.PlayerVoteStatus nextVoteStatus;
    local MutableText nextNumber;
    local Voting currentVoting;

    if (fakers.length <= 0) {
        callerConsole.WriteLine(P("No fakers!"));
        return;
    }
    currentVoting =_.commands.GetCurrentVoting();
    for (i = 0; i < fakers.length; i += 1) {
        nextNumber = _.text.FromIntM(i);
        callerConsole
            .Write(P("Faker #"))
            .Write(nextNumber)
            .Write(P(": "));
        if (currentVoting != none) {
            nextVoteStatus = currentVoting.GetVote(fakers[i]);
        }
        switch (nextVoteStatus) {
            case PVS_NoVote:
                callerConsole.WriteLine(P("no vote"));
                break;
            case PVS_VoteFor:
                callerConsole.UseColorOnce(_.color.TextPositive).WriteLine(P("vote for"));
                break;
            case PVS_VoteAgainst:
                callerConsole.UseColorOnce(_.color.TextNegative).WriteLine(P("vote against"));
                break;
            default:
                callerConsole.UseColorOnce(_.color.TextFailure).WriteLine(P("vote !ERROR!"));
        }
        _.memory.Free(nextNumber);
    }
}

defaultproperties {
    preferredName = "fakers"
}