package de.take_weiland.mods.commons.net;
import com.google.common.io.ByteArrayDataOutput;
import de.take_weiland.mods.commons.Unsafe;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidStack;
import javax.annotation.ParametersAreNullableByDefault;
import java.io.DataOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.util.BitSet;
import java.util.EnumSet;
import java.util.UUID;
/**
* <p>An extension to the DataOutput interface which adds methods useful in the Minecraft environment.</p>
* <p>This interface is intended to write to a memory-based buffer and thus does not throw IOExceptions.</p>
* <p>This interface is mostly intended for network communication purposes and <i>not</i> for saving data to disk.
* Additionally this interface specifies <b>Little Endian</b> byte order, violating the contract of the DataOutput interface,
* to offer better performance on most systems.</p>
* <p>Instances of this interfaces can be obtained using {@link Network#newDataOutput()}.</p>
*
* @author diesieben07
*/
@ParametersAreNullableByDefault
public interface MCDataOutput extends ByteArrayDataOutput {
/**
* <p>Write the given String to this stream.</p>
* <p>If the String is null, this method writes a VarInt -1, otherwise it first writes the length of the String
* as a VarInt and then every character in the String, as if by the {@link #writeChar(int)} method.</p>
* @param s the String to write, may be null
*/
void writeString(String s);
/**
* <p>Write the given ItemStack to this stream.</p>
* <p>If the ItemStack is null, this method writes a short -1, otherwise it writes the data of the ItemStack in
* the following manner:</p>
* <ol>
* <li>The ItemID of the ItemStack as a short</li>
* <li>The damage value of the ItemStack as a short</li>
* <li>The stack size of the ItemStack as a byte</li>
* <li>The NBT tag of the ItemStack, as if by the {@link #writeNBT(net.minecraft.nbt.NBTTagCompound)} method</li>
* </ol>
* @param stack the ItemStack to write, may be null
*/
void writeItemStack(ItemStack stack);
/**
* <p>Write the given FluidStack to this stream.</p>
* <p>If the FluidStack is null, this method writes a VarInt -1, otherwise it writes the data of the FluidStack in
* the following manner:</p>
* <ol>
* <li>The FluidID of the FluidStack as a VarInt</li>
* <li>The amount of the FluidStack as a VarInt</li>
* <li>The NBT tag of the FluidStack, as if by the {@link #writeNBT(net.minecraft.nbt.NBTTagCompound)} method</li>
* </ol>
* @param stack the FluidStack to write, may be null
*/
void writeFluidStack(FluidStack stack);
/**
* <p>Write the given NBTTagCompound to this stream.</p>
* <p>If the NBTTagCompound is null, this method writes a byte -1. Otherwise it writes the following for every tag
* in the compound and terminates with a byte 0:</p>
* <ol>
* <li>The {@link net.minecraft.nbt.NBTBase#getId() Type ID} of the tag as a byte</li>
* <li>The name of the tag, as if by the {@link #writeString(String)} method</li>
* <li>The data of the tag, via the {@link net.minecraft.nbt.NBTBase#write(java.io.DataOutput)} method</li>
* </ol>
*
* @param nbt the NBTTagCompound to write, may be null
*/
void writeNBT(NBTTagCompound nbt);
/**
* <p>Writes an Item reference to the buffer.</p>
* <p>If the Item is null, a VarInt {@code 32000} is written, otherwise the ID of the Item is written as a VarInt.</p>
* @param item the Item
*/
void writeItem(Item item);
/**
* <p>Writes a Block reference to the buffer.</p>
* <p>If the Block is null, a VarInt {@code 4096} is written, otherwise the ID of the Block is written as a VarInt.</p>
* @param block the Block
*/
void writeBlock(Block block);
/**
* <p>Writes the coordinates to this stream.</p>
* <p>This method writes the coordinates in the order x, y, z. The x and z coordinates are written as if by the
* {@link #writeInt(int)} method. The y coordinate is written as if by the {@link #writeByte(int)} method.</p>
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
*/
void writeCoords(int x, int y, int z);
/**
* <p>Write the given UUID to this stream.</p>
* <p>If the given UUID is null, a long 0xF000 is written (a fake UUID version which does not exist). Otherwise two
* long values are written, first the most significant bits of the UUID and then the least significant bits.</p>
* @param uuid the UUID to write, may be null
*/
void writeUUID(UUID uuid);
/**
* <p>Write the given Enum to this stream.</p>
* <p>If the given Enum is null, a VarInt -1 is written, otherwise the {@link Enum#ordinal() ordinal} value of the Enum
* is written as a VarInt.</p>
* @param e the Enum to write, may be null
*/
<E extends Enum<E>> void writeEnum(E e);
/**
* <p>Write the given BitSet to this stream.</p>
* <p>If the BitSet is null, a null long array is written as if by the {@link #writeLongs(long[])} method. Otherwise a
* long array equivalent to the result of {@link java.util.BitSet#toLongArray()} is written in the same manner.</p>
* @param bitSet the BitSet to write, may be null
*/
void writeBitSet(BitSet bitSet);
/**
* <p>Write the given EnumSet to this stream.</p>
* <p>If the EnumSet is null, the long value {@code 1L << 63L} is written. Otherwise a long value is written where the
* ith bit represents if the enum constant with ordinal value i is present in the Set.</p>
* <p>This method only supports Enum types with at most 63 constants. If an Enum type with 64 or more constants is used,
* the behavior of this method is unspecified.</p>
* @param enumSet the EnumSet to write, may be null
*/
<E extends Enum<E>> void writeEnumSet(EnumSet<E> enumSet);
/**
* <p>Write a VarInt to the stream.</p>
* <p>The method writes the given int as a series of 7-bit chunks in little endian order.
* Every chunk is written as the least significant bits of a byte, with the most significant bit set if another chunk
* follows.</p>
* @param i the int to write
*/
void writeVarInt(int i);
/**
* <p>Write the given boolean array to the stream.</p>
* <p>Ìf the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then the booleans as a series of {@code booleans.length %8 + 1} bytes. 8 elements are written as
* one byte, each bit in the byte representing one element, least significant bits first.
* True is represented by a set bit, false by an unset bit.</p>
* @param booleans the array to write
*/
void writeBooleans(boolean[] booleans);
/**
* <p>Write the specified portion of the given boolean array to the stream.</p>
* <p>This method writes the booleans in the same manner as the {@link #writeBooleans(boolean[])} method.</p>
* @param booleans the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeBooleans(boolean[] booleans, int off, int len);
/**
* <p>Write the given byte array to the stream.</p>
* <p>If the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then each byte as if by the {@link #writeByte(int)} method.</p>
* @param bytes the array to write
*/
void writeBytes(byte[] bytes);
/**
* <p>Write the specified portion of the given byte array to the stream.</p>
* <p>This method writes the bytes in the same manner as the {@link #writeBytes(byte[])} method.</p>
* @param bytes the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeBytes(byte[] bytes, int off, int len);
/**
* <p>Write the given short array to the stream.</p>
* <p>If the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then each short as if by the {@link #writeShort(int)} method.</p>
* @param shorts the array to write
*/
void writeShorts(short[] shorts);
/**
* <p>Write the specified portion of the given short array to the stream.</p>
* <p>This method writes the shorts in the same manner as the {@link #writeShorts(short[])} method.</p>
* @param shorts the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeShorts(short[] shorts, int off, int len);
/**
* <p>Write the given int array to the stream.</p>
* <p>If the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then each int as if by the {@link #writeInt(int)} method.</p>
* @param ints the array to write
*/
void writeInts(int[] ints);
/**
* <p>Write the specified portion of the given int array to the stream.</p>
* <p>This method writes the ints in the same manner as the {@link #writeInts(int[])} method.</p>
* @param ints the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeInts(int[] ints, int off, int len);
/**
* <p>Write the given long array to the stream.</p>
* <p>If the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then each long as if by the {@link #writeLong(long)} method.</p>
* @param longs the array to write
*/
void writeLongs(long[] longs);
/**
* <p>Write the specified portion of the given long array to the stream.</p>
* <p>This method writes the longs in the same manner as the {@link #writeLongs(long[])} method.</p>
* @param longs the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeLongs(long[] longs, int off, int len);
/**
* <p>Write the given char array to the stream.</p>
* <p>If the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then each char as if by the {@link #writeChar(int)} method.</p>
* @param chars the array to write
*/
void writeChars(char[] chars);
/**
* <p>Write the specified portion of the given char array to the stream.</p>
* <p>This method writes the chars in the same manner as the {@link #writeChars(char[])} method.</p>
* @param chars the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeChars(char[] chars, int off, int len);
/**
* <p>Write the given float array to the stream.</p>
* <p>If the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then each float as if by the {@link #writeFloat(float)} method.</p>
* @param floats the array to write
*/
void writeFloats(float[] floats);
/**
* <p>Write the specified portion of the given float array to the stream.</p>
* <p>This method writes the floats in the same manner as the {@link #writeFloats(float[])} method.</p>
* @param floats the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeFloats(float[] floats, int off, int len);
/**
* <p>Write the given double array to the stream.</p>
* <p>If the array is null, this method writes a VarInt -1. Otherwise this method first writes the length of the array
* as a VarInt and then each double as if by the {@link #writeDouble(double)} method.</p>
* @param doubles the array to write
*/
void writeDoubles(double[] doubles);
/**
* <p>Write the specified portion of the given double array to the stream.</p>
* <p>This method writes the doubles in the same manner as the {@link #writeDoubles(double[])} method.</p>
* @param doubles the array to write
* @param off the offset of the first element to write
* @param len the number of elements to write
*/
void writeDoubles(double[] doubles, int off, int len);
/**
* <p>Write the given Boolean to the stream. The Boolean is encoded as a single byte. The value {@code false} is
* encoded as {@code 0}, {@code true} as {@code 1} and {@code null} as {@code -1}.</p>
* @param b the Boolean
*/
void writeBooleanBox(Boolean b);
/**
* <p>Write the given Byte to the stream. If the value is {@code null}, a single byte {@code 0} is written.
* Otherwise a byte {@code 1} is written followed by the given Byte.</p>
* @param b the the Byte
*/
void writeByteBox(Byte b);
/**
* <p>Write the given Short to the stream. If the value is {@code null}, a single byte {@code 0} is written.
* Otherwise a byte {@code 1} is written followed by the given Short.</p>
* @param s the Short
*/
void writeShortBox(Short s);
/**
* <p>Write the given Character to the stream. If the value is {@code null}, a single byte {@code 0} is written.
* Otherwise a byte {@code 1} is written followed by the given Character.</p>
* @param c the Character
*/
void writeCharBox(Character c);
/**
* <p>Write the given Integer to the stream. If the value is {@code null}, a single byte {@code 0} is written.
* Otherwise a byte {@code 1} is written followed by the given Integer.</p>
* @param i the Integer
*/
void writeIntBox(Integer i);
/**
* <p>Write the given Long to the stream. If the value is {@code null}, a single byte {@code 0} is written.
* Otherwise a byte {@code 1} is written followed by the given Long.</p>
* @param l the Long
*/
void writeLongBox(Long l);
/**
* <p>Write the given Float to the stream. If the value is {@code null}, a single byte {@code 0} is written.
* Otherwise a byte {@code 1} is written followed by the given Float.</p>
* @param f the Float
*/
void writeFloatBox(Float f);
/**
* <p>Write the given Double to the stream. If the value is {@code null}, a single byte {@code 0} is written.
* Otherwise a byte {@code 1} is written followed by the given Double.</p>
* @param d the Double
*/
void writeDoubleBox(Double d);
/**
* <p>Write the contents of this stream to the given OutputStream as a series of bytes.</p>
* @param stream the OutputStream to write to
*/
void writeTo(OutputStream stream) throws IOException;
/**
* <p>Write the contents of this stream to the given DataOutput as a series of bytes.</p>
* @param out the DataOutput to write to
*/
void writeTo(DataOutput out) throws IOException;
/**
* <p>Write the contents of this stream to the given ByteBuffer.</p>
* @param buf the buffer to write to
*/
void writeTo(ByteBuffer buf);
/**
* <p>Write the contents of this stream to the given ByteChannel.</p>
* @param channel the channel to write to
*/
void writeTo(WritableByteChannel channel) throws IOException;
/**
* <p>The number of bytes written to this stream to far.</p>
* @return the number of bytes
*/
int length();
/**
* <p>Return the array backing this stream. Any modification in the returned array will be reflected in the contents
* of this stream, as long as the buffer does not grow.</p>
* @return the array backing this buffer
*/
@Unsafe
byte[] backingArray();
/**
* <p>Write {@code n} 0 bytes to the buffer.</p>
* @param n the number of bytes to write
*/
void writeNulls(int n);
/**
* <p>Lock this stream so that no further write operations can occur. Attempts to write to a locked stream will
* result in an {@link java.lang.IllegalStateException}.</p>
*/
void lock();
/**
* <p>Check if this buffer is currently locked.</p>
* @return if this buffer is locked
* @see #lock()
*/
boolean isLocked();
/**
* <p>Get an {@code OutputStream} view of this stream. The created stream writes through to this stream.</p>
* @return an OutputStream
*/
OutputStream asOutputStream();
}