/**
 * Author: dkanus
 * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
 * License: GPL
 * 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 SideEffect extends AcediaObject;

//! Defines the concept of "side effects" in the context of the Acedia and its derivative mods.
//!
//! Side effects are changes that are not part of the mod's main functionality, but rather something
//! necessary to enable that functionality, while also possibly affecting how other mods work.
//! Documenting these side effects helps developers and server admins understand changes performed
//! by Acedia or mods based on it, and anticipate any potential conflicts or issues that may arise.
//!
//! It should be noted that what constitutes a side effect is loosely defined, and it is simply
//! a tool to inform others that something unexpected has happened, possibly breaking other mods.
//! AcediaCore aims to leave a minimal footprint, but still needs to make some changes
//! (e.g., adding GameRules, patching code of some functions), and [`SideEffects`] can be used to
//! document them.
//! Similarly, [`SideEffect`]s can be used to document changes made by AcediaFixes, a package meant
//! only for fixing bugs that inevitably needs to make many under-the-hood changes to achieve
//! that goal.
//!
//! On the other hand gameplay mods like Futility or Ire can make a lot of changes, but they can all
//! be just expected part of its direct functionality: we expect feature that shares dosh of leavers
//! to alter players' dosh values, so this is not a side effect.
//! Such mods are likely not going to have to specify any side effects whatsoever.

var private Text name;
var private Text description;
var private Text package;
var private Text source;
var private Text status;
var private bool initialized;

protected function Finalizer() {
    _.memory.Free(name);
    _.memory.Free(description);
    _.memory.Free(package);
    _.memory.Free(source);
    _.memory.Free(status);
    name = none;
    description = none;
    package = none;
    source = none;
    status = none;
    initialized = false;
}

/// Checks whether caller [`SideEffect`] was initialized.
///
/// Initialization must happen directly after creation and only initialized instances should
/// ever be used.
public final function bool IsInitialized() {
    return initialized;
}

/// This function is used to set the initial values of the [`SideEffect`] object properties when it
/// is first created.
///
/// All arguments must be not `none`.
///
/// Returns `true` if the initialization was successful, `false` otherwise (including the case where
/// the [`SideEffect`] object has already been initialized).
public final function bool Initialize(
    BaseText sideEffectName,
    BaseText sideEffectDescription,
    BaseText sideEffectPackage,
    BaseText sideEffectSource,
    BaseText sideEffectStatus
) {
    if (initialized)                    return false;
    if (sideEffectName == none)         return false;
    if (sideEffectDescription == none)  return false;
    if (sideEffectPackage == none)      return false;
    if (sideEffectSource == none)       return false;
    if (sideEffectStatus == none)       return false;

    name = sideEffectName.Copy();
    description = sideEffectDescription.Copy();
    package = sideEffectPackage.Copy();
    source = sideEffectSource.Copy();
    status = sideEffectStatus.Copy();
    initialized = true;
    return true;
}

/// This function is used to set the initial values of the [`SideEffect`] object properties when it
/// is first created.
///
/// Returns `true` if the initialization was successful, `false` otherwise (including the case where
/// the [`SideEffect`] object has already been initialized).
public final function bool Initialize_S(
    string sideEffectName,
    string sideEffectDescription,
    string sideEffectPackage,
    string sideEffectSource,
    string sideEffectStatus
) {
    name = _.text.FromString(sideEffectName);
    description = _.text.FromString(sideEffectDescription);
    package = _.text.FromString(sideEffectPackage);
    source = _.text.FromString(sideEffectSource);
    status = _.text.FromString(sideEffectStatus);
    initialized = true;
    return true;
}

/// Returns a brief summary that conveys the purpose of the caller [SideEffect] to the user in
/// a clear and concise manner.
///
/// While there is no hard limit on the length of this value, it is recommended to keep it under 80
/// characters for readability.
///
/// Returned value for initialized [`SideEffect`] is guaranteed to not be `none`, as it is
/// a required property of the [`SideEffect`] object.
public final function Text GetName() {
    if (initialized) {
        return name.Copy();
    }
    return none;
}

/// Returns a brief summary that conveys the purpose of the caller [SideEffect] to the user in
/// a clear and concise manner.
///
/// While there is no hard limit on the length of this value, it is recommended to keep it under 80
/// characters for readability.
public final function string GetName_S() {
    if (initialized && name != none) {
        return name.ToString();
    }
    return "";
}

/// Returns the detailed description of the caller [`SideEffect`], which describes what was done
/// and why the relevant change was necessary.
///
/// Returned value for initialized [`SideEffect`] is guaranteed to not be `none`, as it is
/// a required property of the [`SideEffect`] object.
public final function Text GetDescription() {
    if (initialized) {
        return description.Copy();
    }
    return none;
}

/// Returns the detailed description of the caller [`SideEffect`], which describes what was done
/// and why the relevant change was necessary.
public final function string GetDescription_S() {
    if (initialized && description != none) {
        return description.ToString();
    }
    return "";
}

/// Returns the name of the package ("*.u" file) that introduced the changes
/// represented by the caller `SideEffect`.
///
/// It should be noted that even if a different package requested the functionality that led to
/// the changes being made, the package responsible for the side effect is the one that performed
/// the changes.
///
/// Returned value for initialized [`SideEffect`] is guaranteed to not be `none`, as it is
/// a required property of the [`SideEffect`] object.
public final function Text GetPackage() {
    if (initialized) {
        return package.Copy();
    }
    return none;
}

/// Returns the name of the package ("*.u" file) that introduced the changes
/// represented by the caller `SideEffect`.
///
/// It should be noted that even if a different package requested the functionality that led to
/// the changes being made, the package responsible for the side effect is the one that performed
/// the changes.
public final function string GetPackage_S() {
    if (initialized && package != none) {
        return package.ToString();
    }
    return "";
}

/// The origin of this change within the package is specified, and for larger packages, additional
/// details can be provided to clarify the cause of the change.
///
/// Returned value for initialized [`SideEffect`] is guaranteed to not be `none`, as it is
/// a required property of the [`SideEffect`] object.
public final function Text GetSource() {
    if (initialized) {
        return source.Copy();
    }
    return none;
}

/// The origin of this change within the package is specified, and for larger packages, additional
/// details can be provided to clarify the cause of the change.
public final function string GetSource_S() {
    if (initialized && source != none) {
        return source.ToString();
    }
    return "";
}

/// The status of the caller [`SideEffect`], that is used to differentiate between different ways
/// that a side effect may have been introduced, allowing for better tracking and management of
/// the effect.
///
/// Returned value for initialized [`SideEffect`] is guaranteed to not be `none`, as it is
/// a required property of the [`SideEffect`] object.
public final function Text GetStatus() {
    if (initialized) {
        return status.Copy();
    }
    return none;
}

/// The status of the caller [`SideEffect`], that is used to differentiate between different ways
/// that a side effect may have been introduced, allowing for better tracking and management of
/// the effect.
public final function string GetStatus_S() {
    if (initialized && status != none) {
        return status.ToString();
    }
    return "";
}

public function bool IsEqual(Object other) {
    local SideEffect otherSideEffect;

    if (self == other)                                                          return true;
    otherSideEffect = SideEffect(other);
    if (otherSideEffect == none)                                                return false;
    if (!otherSideEffect.initialized)                                           return false;
    if (GetHashCode() != otherSideEffect.GetHashCode())                         return false;
    if (!name.Compare(otherSideEffect.name,, SFORM_SENSITIVE))                  return false;
    if (!package.Compare(otherSideEffect.package,, SFORM_SENSITIVE))            return false;
    if (!source.Compare(otherSideEffect.source,, SFORM_SENSITIVE))              return false;
    if (!status.Compare(otherSideEffect.status,, SFORM_SENSITIVE))              return false;
    if (!description.Compare(otherSideEffect.description,, SFORM_SENSITIVE))    return false;

    return true;
}

protected function int CalculateHashCode() {
    local int result;

    if (initialized) {
        result = name.GetHashCode();
        result = CombineHash(result, description.GetHashCode());
        result = CombineHash(result, package.GetHashCode());
        result = CombineHash(result, source.GetHashCode());
        result = CombineHash(result, status.GetHashCode());
        return result;
    }
}

defaultproperties {
}