#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.GameObjects.Components.Body.Part;
using Content.Shared.GameObjects.Components.Body.Part.Property;
using Content.Shared.GameObjects.Components.Body.Preset;
using Content.Shared.GameObjects.Components.Body.Template;
using Robust.Shared.GameObjects;
namespace Content.Shared.GameObjects.Components.Body
{
///
/// Component representing a collection of s
/// attached to each other.
///
public interface IBody : IComponent, IBodyPartContainer
{
///
/// The name of the used by this
/// .
///
public string? TemplateName { get; }
///
/// The name of the used by this
/// .
///
public string? PresetName { get; }
// TODO BODY Part slots
// TODO BODY Sensible templates
///
/// Mapping of slots in this body to their
/// .
///
public Dictionary Slots { get; }
///
/// Mapping of slots to the filling each one.
///
public IReadOnlyDictionary Parts { get; }
///
/// Mapping of slots to which other slots they connect to.
/// For example, the torso could be mapped to a list containing
/// "right arm", "left arm", "left leg", and "right leg".
/// This is mapped both ways during runtime, but in the prototype
/// it only has to be defined one-way, "torso": "left arm" will automatically
/// map "left arm" to "torso" as well.
///
public Dictionary> Connections { get; }
///
/// Mapping of template slots to the ID of the
/// that should fill it. E.g. "right arm" : "BodyPart.arm.basic_human".
///
public IReadOnlyDictionary PartIds { get; }
///
/// Attempts to add a part to the given slot.
///
/// The slot to add this part to.
/// The part to add.
///
/// Whether or not to check for the validity of the given .
/// Passing true does not guarantee it to be added, for example if it
/// had already been added before.
///
///
/// true if the part was added, false otherwise even if it was already added.
///
bool TryAddPart(string slot, IBodyPart part, bool force = false);
///
/// Checks if there is a in the given slot.
///
/// The slot to look in.
///
/// true if there is a part in the given ,
/// false otherwise.
///
bool HasPart(string slot);
///
/// Checks if this contains the given .
///
/// The part to look for.
///
/// true if the given is attached to the body,
/// false otherwise.
///
bool HasPart(IBodyPart part);
///
/// Removes the given reference, potentially
/// dropping other BodyParts if they
/// were hanging off of it.
///
void RemovePart(IBodyPart part);
///
/// Removes the body part in slot from this body,
/// if one exists.
///
/// The slot to remove it from.
/// True if the part was removed, false otherwise.
bool RemovePart(string slot);
///
/// Removes the body part from this body, if one exists.
///
/// The part to remove from this body.
/// The slot that the part was in, if any.
/// True if was removed, false otherwise.
bool RemovePart(IBodyPart part, [NotNullWhen(true)] out string? slotName);
///
/// Disconnects the given reference, potentially
/// dropping other BodyParts if they
/// were hanging off of it.
///
/// The part to drop.
///
/// All of the parts that were dropped, including .
///
///
/// True if the part was dropped, false otherwise.
///
bool TryDropPart(IBodyPart part, [NotNullWhen(true)] out List? dropped);
///
/// Recursively searches for if is connected to
/// the center.
///
/// The body part to find the center for.
/// True if it is connected to the center, false otherwise.
bool ConnectedToCenter(IBodyPart part);
///
/// Finds the central , if any, of this body based on
/// the . For humans, this is the torso.
///
/// The if one exists, null otherwise.
IBodyPart? CenterPart();
///
/// Returns whether the given part slot name exists within the current
/// .
///
/// The slot to check for.
/// True if the slot exists in this body, false otherwise.
bool HasSlot(string slot);
///
/// Finds the in the given if
/// one exists.
///
/// The part slot to search in.
/// The body part in that slot, if any.
/// True if found, false otherwise.
bool TryGetPart(string slot, [NotNullWhen(true)] out IBodyPart? result);
///
/// Finds the slotName that the given resides in.
///
///
/// The to find the slot for.
///
/// The slot found, if any.
/// True if a slot was found, false otherwise
bool TryGetSlot(IBodyPart part, [NotNullWhen(true)] out string? slot);
///
/// Finds the in the given
/// if one exists.
///
/// The slot to search in.
///
/// The of that slot, if any.
///
/// True if found, false otherwise.
bool TryGetSlotType(string slot, out BodyPartType result);
///
/// Finds the names of all slots connected to the given
/// for the template.
///
/// The slot to search in.
/// The connections found, if any.
/// True if the connections are found, false otherwise.
bool TryGetSlotConnections(string slot, [NotNullWhen(true)] out List? connections);
///
/// Grabs all occupied slots connected to the given slot,
/// regardless of whether the given is occupied.
///
/// The slot name to find connections from.
/// The connected body parts, if any.
///
/// True if successful, false if the slot couldn't be found on this body.
///
bool TryGetPartConnections(string slot, [NotNullWhen(true)] out List? connections);
///
/// Grabs all parts connected to the given , regardless
/// of whether the given is occupied.
///
/// The part to find connections from.
/// The connected body parts, if any.
///
/// True if successful, false if the part couldn't be found on this body.
///
bool TryGetPartConnections(IBodyPart part, [NotNullWhen(true)] out List? connections);
///
/// Finds all s of the given type in this body.
///
/// A list of parts of that type.
List GetPartsOfType(BodyPartType type);
///
/// Finds all s with the given property in this body.
///
/// The property type to look for.
/// A list of parts with that property.
List<(IBodyPart part, IBodyPartProperty property)> GetPartsWithProperty(Type type);
///
/// Finds all s with the given property in this body.
///
/// The property type to look for.
/// A list of parts with that property.
List<(IBodyPart part, T property)> GetPartsWithProperty() where T : class, IBodyPartProperty;
// TODO BODY Make a slot object that makes sense to the human mind, and make it serializable. Imagine the possibilities!
///
/// Retrieves the slot at the given index.
///
/// The index to look in.
/// A pair of the slot name and part type occupying it.
KeyValuePair SlotAt(int index);
///
/// Retrieves the part at the given index.
///
/// The index to look in.
/// A pair of the part name and body part occupying it.
KeyValuePair PartAt(int index);
///
/// Gibs this body.
///
void Gib(bool gibParts = false);
}
}