/**
 * Author: dkanus
 * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
 * License: GPL
 * Copyright 2021-2024 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 ETrader extends EInterface
    abstract;

//! Class, objects of which are expected to represent traders located on
//! the map.
//!
//! In classic KF game mode it would represent areas behind closed doors that
//! open during trader time and allow to purchase weapons and ammo.

/// Retrieves the location of the trader.
///
/// This location is used for distance or path calculations to the trader.
/// In case trader is represented by an area rather than a specific point,
/// this method is still supposed to return a vector representing the location
/// that "makes sense" for the trader.
public function Vector GetLocation();

/// Fetches the current case-insesitive name of the trader, which should be
/// unique post-map initialization but can be altered later using
/// [`ETrader::SetName()`].
///
/// The name is intended for admin use rather than regular players, ensuring
/// it's human-readable for configuration purposes.
public function Text GetName();

/// Changes the name of the trader to the provided [`newName`].
///
/// The change only occurs if the new name is not `none`, empty or already in
/// used by some other trader (trader names are considered case-insensitive).
public function SetName(BaseText newName);

/// Determines if the trader is currently enabled, meaning it can be opened and
/// used for trading.
///
/// A disabled trader cannot be used for trading.
/// Being marked as selected is discouraged, but remains possible.
///
/// Returns `true` if the trader is enabled, `false` otherwise.
public function bool IsEnabled();

/// Sets the trader's enabled state according to the `doEnable` parameter.
///
/// Disabling a trader automatically initiates [`ETrader::BootPlayers()`] to
/// remove players from the trader area and/or close their trading windows.
public function SetEnabled(bool doEnable);

/// Checks if the trader is set to auto-open when trading is activated.
///
/// Returns `true` if the trader will auto-open upon trading activation unless disabled, `false` otherwise.
///
/// This setting is ignored if the trader is disabled, but disabling the trader
/// does not reset this setting.
public function bool IsAutoOpen();

/// Sets the auto-open state of the trader to the specified value.
///
/// This function does not alter the enabled state of the trader but determines
/// its behavior when trading is activated.
public function SetAutoOpen(bool doAutoOpen);

/// Checks if the trader is currently open, meaning players can enter and use
/// it for buying or selling equipment.
///
/// Returns `true` if the trader is open, `false` otherwise.
public function bool IsOpen();

/// Determines if the specified `player` is currently using the trader to
/// buy items.
///
/// Returns `true` if the trader is being used by the specified player,
/// `false` otherwise.
public function bool IsUsedBy(EPlayer player);

/// Sets the open state of the trader based on the [`doOpen`] parameter.
///
/// Closing a trader does not automatically trigger [`BootPlayers()`].
public function SetOpen(bool doOpen);

/// Checks if this trader is currently selected within the trading system.
///
/// Returns `true` if this trader is selected, `false` otherwise.
public function bool IsSelected();

/// Marks this trader as selected within the trading system.
///
/// This status can influence various gameplay mechanics, particularly in user
/// interfaces where the selected trader might be highlighted or given priority.
public function Select();

/// Removes players from the trader's area.
///
/// This method closes any trading menus/sessions for the players and ensures
/// they are not trapped in the trader's area after it closes.
///
/// In the classic KF game mode, this typically teleports them just outside
/// the trading area.
public function BootPlayers();

/// Opens the trader, setting its state to open, and is guaranteed to be
/// equivalent to [`ETrader::SetOpen(true)`].
public final function Open() {
    SetOpen(true);
}

/// Closes the trader, setting its state to closed, and is guaranteed to be
/// equivalent to [`ETrader::SetOpen(false)`].
public final function Close() {
    SetOpen(false);
}

/// Fetches the maximum number of [`EItem`] copies a player can buy at once
/// based on the given template.
///
/// If [`target`] is `none`, it returns the maximum for the baseline case.
/// Returns 0 if the [`tradable`] is `none`.
///
/// Parameter [`allowDebt`] makes the calculation without caring whether player
/// has enough money, assuming they can pay for everything.
public function int GetMaxBuyQuantity(
    BaseText tradableTemplate,
    EPlayer target,
    optional bool allowDebt);

/// Fetches the maximum number of [`EItem`] copies a player can sell at once
/// based on the given template.
///
/// If [`target`] is `none`, it returns the maximum for the baseline case.
/// Returns 0 if the [`tradable`] is `none`.
///
/// Parameter [`allowDebt`] makes the calculation without caring whether trader
/// has enough money, assuming they can pay for everything.
public function int GetMaxSellQuantity(
    BaseText tradableTemplate,
    EPlayer target,
    optional bool allowDebt);

/// Calculates the money a player would receive for selling
/// a given [`EItem`].
///
/// The price may vary per player.
/// If [`target`] is `none`, it returns the baseline price.
/// Returns 0 if the [`tradable`] is `none`.
public function int GetSellPrice(EItem tradable, optional EPlayer target);

/// Determines the cost for a player to buy a given [`EItem`].
///
/// The cost may vary per player.
/// If [`target`] is `none`, it returns the baseline price.
/// Returns 0 if the [`tradable`] is `none`.
public function int GetBuyPrice(EItem tradable, optional EPlayer target);

/// Calculates the cost for a player to buy an [`EItem`] based on
/// the given template.
///
/// The cost may vary per player.
/// If [`target`] is `none`, it returns the baseline price.
/// Returns 0 if the [`tradableTemplate`] is `none`.
public function int GetTemplateBuyPrice(BaseText tradableTemplate, optional EPlayer target);

/// Attempts to buy an item with a given [`EItem`] template for
/// a specified player.
///
/// The transaction may allow the player to go into debt if specified.
/// Returns `true` on success and `false` if the player lacks sufficient funds
/// or if other conditions are not met.
public function bool BuyTemplate(
    BaseText tradableTemplate,
    EPlayer target,
    optional bool allowDebt
);

/// Checks whether a player can buy a tradable based on a template.
///
/// This function checks various conditions like financial status and returns
/// `true` if the tradable cannot be bought, otherwise returns `false`.
public final function bool CanBuyTemplate(
    BaseText tradableTemplate,
    EPlayer target,
    optional bool allowDebt
) {
    local bool success;
    local AcediaError explanation;

    explanation = CanBuyTemplateExplain(tradableTemplate, target, allowDebt);
    success = (explanation == none);
    _.memory.Free(explanation);
    return success;
}

/// Provides a detailed explanation if a player cannot buy a tradable based on
/// a template.
///
/// This function checks various conditions like financial status and returns
/// an error object describing the issue if the tradable cannot be bought,
/// otherwise returns `none`.
public function AcediaError CanBuyTemplateExplain(
    BaseText tradable,
    EPlayer target,
    optional bool allowDebt
);

/// Attempts to buy a specified [`EItem`] for a player.
///
/// The transaction may allow the player to go into debt if [`allowDebt`] flag
/// is set to `true`.
///
/// Returns `true` on success and `false` if the player lacks sufficient funds
/// or if other conditions are not met.
public function bool CanBuy(EItem tradable, EPlayer target, optional bool allowDebt);

/// Tries to buy given [`EItem`] for a provided [`EPlayer`].
///
/// Fails when [`EPlayer`] doesn't have enough money available, unless
/// [`allowDebt`] is set to `true`.
/// What money can be used for the purchase is decided by implementation.
///
/// Returns `true` on success and `false` on failure.
public function bool Buy(EItem tradable, EPlayer target, optional bool allowDebt);

/// Provides a detailed explanation if a player cannot buy a specific
/// [`EItem`].
///
/// The transaction may allow the player to go into debt if [`allowDebt`] flag
/// is set to `true`.
///
/// This function checks various conditions like financial status and returns
/// an error object describing the issue if the tradable cannot be bought,
/// otherwise returns `none`.
public function bool CanBuyExplain(
    EItem tradable,
    EPlayer target,
    optional bool allowDebt
);

/// Checks if a player can sell a specific [`EItem`].
///
/// The transaction may allow the trader to go into debt if [`allowDebt`] flag
/// is set to `true`.
///
/// Returns `true` if the sale is possible, `false` otherwise.
public final function bool CanSell(EItem tradable, EPlayer target, optional bool allowDebt) {
    local bool success;
    local AcediaError explanation;

    explanation = CanSellExplain(tradable, target, allowDebt);
    success = (explanation == none);
    _.memory.Free(explanation);
    return success;
}

/// Provides a detailed explanation if a player cannot sell a specific
/// [`EItem`].
///
/// The transaction may allow the trader to go into debt if [`allowDebt`] flag
/// is set to `true`.
///
/// This function checks various conditions like financial status and returns
/// an error object describing the issue if the tradable cannot be sold,
/// otherwise returns `none`.
public function AcediaError CanSellExplain(
    EItem tradable,
    EPlayer target,
    optional bool allowDebt
);

/// Tries to sell given [`EItem`] as a provided [`EPlayer`].
///
/// Fails when trader doesn't have enough money available, unless
/// [`allowDebt`] is set to `true`.
/// What money can be used for the purchase is decided by implementation.
///
/// Returns `true` on success and `false` on failure.
public function bool Sell(EItem tradable, EPlayer target, optional bool allowDebt);

/// Opens a menu for buying/selling inside the caller [`ETrader`].
public function bool OpenTradeMenu();

defaultproperties {
}