#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.Slot;
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 used to create this
/// .
///
public BodyTemplatePrototype? Template { get; }
///
/// The used to create this
/// .
///
public BodyPresetPrototype? Preset { get; }
///
/// An enumeration of the slots that make up this body, regardless
/// of if they contain a part or not.
///
IEnumerable Slots { get; }
///
/// An enumeration of the parts on this body paired with the slots
/// that they are in.
///
IEnumerable> Parts { get; }
///
/// An enumeration of the slots on this body without a part in them.
///
IEnumerable EmptySlots { get; }
///
/// Finds the central , if any,
/// of this body.
///
///
/// The central if one exists,
/// null otherwise.
///
BodyPartSlot? CenterSlot { get; }
///
/// Finds the central , if any,
/// of this body.
///
///
/// The central if one exists,
/// null otherwise.
///
IBodyPart? CenterPart { get; }
// TODO BODY Sensible templates
///
/// Attempts to add a part to the given slot.
///
/// The slot to add this part to.
/// The part to add.
///
/// Whether to check if the slot exists, or create one otherwise.
///
///
/// true if the part was added, false otherwise even if it was
/// already added.
///
bool TryAddPart(string slotId, IBodyPart part);
void SetPart(string slotId, IBodyPart part);
///
/// 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 slotId);
///
/// 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 from this body,
/// dropping other if they were hanging
/// off of it.
/// The part to remove.
///
/// true if the part was removed, false otherwise
/// even if the part was already removed previously.
///
///
bool 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 slotId);
///
/// 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 BodyPartSlot? slotId);
///
/// 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 the one in
/// .
///
///
/// true if the part was dropped, false otherwise.
///
bool TryDropPart(BodyPartSlot slot, [NotNullWhen(true)] out Dictionary? 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);
///
/// Returns whether the given part slot exists in this body.
///
/// The slot to check for.
/// true if the slot exists in this body, false otherwise.
bool HasSlot(string slot);
BodyPartSlot? GetSlot(IBodyPart part);
///
/// Finds the slot 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 BodyPartSlot? 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 slotId, [NotNullWhen(true)] out IBodyPart? result);
///
/// Checks if a slot of the specified type exists on this body.
///
/// The type to check for.
/// true if present, false otherwise.
bool HasSlotOfType(BodyPartType type);
///
/// Gets all slots of the specified type on this body.
///
/// The type to check for.
/// An enumerable of the found slots.
IEnumerable GetSlotsOfType(BodyPartType type);
///
/// Checks if a part of the specified type exists on this body.
///
/// The type to check for.
/// true if present, false otherwise.
bool HasPartOfType(BodyPartType type);
///
/// Gets all slots of the specified type on this body.
///
/// The type to check for.
/// An enumerable of the found slots.
IEnumerable 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.
IEnumerable<(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.
IEnumerable<(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.
BodyPartSlot 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.
///
///
/// Whether or not to also gib this body's parts.
///
void Gib(bool gibParts = false);
}
}