/**
 * 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 VotingsTool extends CmdItemsTool
    dependson(CommandAPI);

//! This is a base class for auxiliary objects that will be used for storing
//! named [`Voting`] classes.
//!
//! This storage class allows for efficient manipulation and retrieval of
//! [`Voting`] classes, along with information about what use groups were
//! authorized to use them.
//!
//! Additionally this tool is used to keep track of the currently ongoing
//! voting, preventing [`CommandsAPI`] from starting several votings at once.

/// Currently running voting process.
/// This tool doesn't actively track when voting ends, so reference can be
/// non-`none` even if voting has already ended. Instead `DropFinishedVoting()`
/// method is used as needed to figure out whether that voting has ended and
/// should be deallocated.
var private Voting currentVoting;

protected function Finalizer() {
    super.Finalizer();
    _.memory.Free(currentVoting);
    currentVoting = none;
}

/// Starts a voting process with a given name, returning its result.
public final function CommandAPI.StartVotingResult StartVoting(
    CommandAPI.VotingConfigInfo votingData,
    HashTable arguments
) {
    local CommandAPI.StartVotingResult result;
    DropFinishedVoting();
    if (currentVoting != none) {
        return SVR_AlreadyInProgress;
    }
    if (votingData.votingClass == none) {
        return SVR_UnknownVoting;
    }
    currentVoting = Voting(_.memory.Allocate(votingData.votingClass));
    result = currentVoting.Start(votingData.config, arguments);
    if (result != SVR_Success) {
        _.memory.Free(currentVoting);
        currentVoting = none;
    }
    return result;
}

/// Returns `true` iff some voting is currently active.
public final function bool IsVotingRunning() {
    DropFinishedVoting();
    return (currentVoting != none);
}

/// Returns instance of the active voting.
///
/// `none` iff no voting is currently active.
public final function Voting GetCurrentVoting() {
    DropFinishedVoting();
    if (currentVoting != none) {
        currentVoting.NewRef();
    }
    return currentVoting;
}

protected function ItemCard MakeCard(class<AcediaObject> votingClass, BaseText itemName) {
    local ItemCard newCard;

    if (class<Voting>(votingClass) != none) {
        newCard = ItemCard(_.memory.Allocate(class'ItemCard'));
        newCard.InitializeWithClass(votingClass);
    }
    return newCard;
}

private final function class<Voting> GetVoting(BaseText itemName) {
    local ItemCard relevantCard;
    local class<Voting> result;

    relevantCard = GetCard(itemName);
    if (relevantCard != none) {
        result = class<Voting>(relevantCard.GetItemClass());
    }
    _.memory.Free(relevantCard);
    return result;
}

// Clears `currentVoting` if it has already finished
private final function DropFinishedVoting() {
    if (currentVoting != none && currentVoting.HasEnded()) {
        _.memory.Free(currentVoting);
        currentVoting = none;
    }
}

defaultproperties {
    ruleBaseClass = class'Voting'
}