package li.cil.oc.api.driver;

import li.cil.oc.api.network.ManagedEnvironment;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;

/**
 * Interface for item component drivers.
 * <p/>
 * This driver type is used for components that are items, i.e. that can be
 * inserted into computers and robots. An example for this are internal drives,
 * memory and graphic cards.
 * <p/>
 * When trying to add an item to a computer the list of registered drivers is
 * queried using the drivers' <tt>worksWith</tt> functions. The first driver
 * that replies positively and whose check against the slot type is successful,
 * i.e. for which the <tt>slot</tt> matches the slot it should be inserted into,
 * will be used as the component's driver and the component will be added. If no
 * driver is found the item will be rejected and cannot be installed.
 * <p/>
 * Note that it is possible to write one driver that supports as many different
 * items as you wish. I'd recommend writing one per device (type), though, to
 * keep things modular.
 */
public interface Item {
    /**
     * Used to determine the item types this driver handles.
     * <p/>
     * This is used to determine which driver to use for an item when it should
     * be installed in a computer. Note that the return value should not change
     * over time; if it does, though, an already installed component will not
     * be ejected, since this value is only checked when adding components.
     *
     * @param item the item to check.
     * @return <tt>true</tt> if the item is supported; <tt>false</tt> otherwise.
     */
    boolean worksWith(ItemStack item);

    /**
     * Create a new managed environment interfacing the specified item.
     * <p/>
     * This is used to connect the component to the component network when it is
     * added to a computer, for example. The only kind of component that does
     * not need to be connected to the component network is probably memory, and
     * there's a built-in driver for that. You may still opt to not implement
     * this - i.e. it is safe to return <tt>null</tt> here.
     * <p/>
     * Keep in mind that the tile entity's location may change if the owner is
     * a robot. This is important if you cache the location somewhere. For
     * example, the wireless network card checks in it's update whether its
     * owner's position has changed to update the index structure used for
     * receiver look-up.
     * <p/>
     * This is expected to return a <em>new instance</em> each time it is
     * called. The created instance's life cycle is managed by the computer or
     * other container that caused its creation.
     *
     * @param stack     the item stack for which to get the environment.
     * @param container the tile entity the environment will be managed by.
     * @return the environment for that item.
     */
    ManagedEnvironment createEnvironment(ItemStack stack, TileEntity container);

    /**
     * The slot type of the specified item this driver supports.
     * <p/>
     * This is used to determine into which slot of a computer the components
     * this driver supports may go. This will only be called if a previous call
     * to {@link #worksWith} with the same stack returned true.
     *
     * @param stack the item stack to get the slot type for.
     * @return the slot type of the specified item.
     */
    Slot slot(ItemStack stack);

    /**
     * The tier of the specified item this driver supports.
     * <p/>
     * This is used to determine into which slot of a computer the components
     * this driver supports may go. This will only be called if a previous call
     * to {@link #worksWith} with the same stack returned true.
     * <p/>
     * <em>Important</em>: tiers are zero-indexed.
     *
     * @param stack the item stack to get the tier for.
     * @return the tier of the specified item.
     */
    int tier(ItemStack stack);

    /**
     * Get the tag compound based on the item stack to use for persisting the
     * environment associated with the specified item stack.
     * <p/>
     * This is only used if the item has an environment. This must always be a
     * child tag of the item stack's own tag compound, it will not be saved
     * otherwise. Use this in the unlikely case that the default name collides
     * with something. The built-in components use a child tag-compound with
     * the name <tt>oc:data</tt>, which will also be used if this returns
     * <tt>null</tt>.
     * <p/>
     * This tag will be passed to the environment's <tt>save</tt> and
     * <tt>load</tt> methods when appropriate (world save / load and when
     * removed from their hosting inventory).
     *
     * @param stack the item to get the child tag from.
     * @return the tag to use for saving and loading, or <tt>null</tt> to use
     * the default tag <tt>oc:data</tt>.
     */
    NBTTagCompound dataTag(ItemStack stack);
}