// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.protocol.packets.player;

import java.util.Objects;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull;
import com.hypixel.hytale.protocol.WorldInteraction;
import com.hypixel.hytale.protocol.MouseMotionEvent;
import com.hypixel.hytale.protocol.MouseButtonEvent;
import com.hypixel.hytale.protocol.Vector2f;
import javax.annotation.Nullable;
import com.hypixel.hytale.protocol.Packet;

public class MouseInteraction implements Packet
{
    public static final int PACKET_ID = 111;
    public static final boolean IS_COMPRESSED = false;
    public static final int NULLABLE_BIT_FIELD_SIZE = 1;
    public static final int FIXED_BLOCK_SIZE = 44;
    public static final int VARIABLE_FIELD_COUNT = 2;
    public static final int VARIABLE_BLOCK_START = 52;
    public static final int MAX_SIZE = 20480071;
    public long clientTimestamp;
    public int activeSlot;
    @Nullable
    public String itemInHandId;
    @Nullable
    public Vector2f screenPoint;
    @Nullable
    public MouseButtonEvent mouseButton;
    @Nullable
    public MouseMotionEvent mouseMotion;
    @Nullable
    public WorldInteraction worldInteraction;
    
    @Override
    public int getId() {
        return 111;
    }
    
    public MouseInteraction() {
    }
    
    public MouseInteraction(final long clientTimestamp, final int activeSlot, @Nullable final String itemInHandId, @Nullable final Vector2f screenPoint, @Nullable final MouseButtonEvent mouseButton, @Nullable final MouseMotionEvent mouseMotion, @Nullable final WorldInteraction worldInteraction) {
        this.clientTimestamp = clientTimestamp;
        this.activeSlot = activeSlot;
        this.itemInHandId = itemInHandId;
        this.screenPoint = screenPoint;
        this.mouseButton = mouseButton;
        this.mouseMotion = mouseMotion;
        this.worldInteraction = worldInteraction;
    }
    
    public MouseInteraction(@Nonnull final MouseInteraction other) {
        this.clientTimestamp = other.clientTimestamp;
        this.activeSlot = other.activeSlot;
        this.itemInHandId = other.itemInHandId;
        this.screenPoint = other.screenPoint;
        this.mouseButton = other.mouseButton;
        this.mouseMotion = other.mouseMotion;
        this.worldInteraction = other.worldInteraction;
    }
    
    @Nonnull
    public static MouseInteraction deserialize(@Nonnull final ByteBuf buf, final int offset) {
        final MouseInteraction obj = new MouseInteraction();
        final byte nullBits = buf.getByte(offset);
        obj.clientTimestamp = buf.getLongLE(offset + 1);
        obj.activeSlot = buf.getIntLE(offset + 9);
        if ((nullBits & 0x1) != 0x0) {
            obj.screenPoint = Vector2f.deserialize(buf, offset + 13);
        }
        if ((nullBits & 0x2) != 0x0) {
            obj.mouseButton = MouseButtonEvent.deserialize(buf, offset + 21);
        }
        if ((nullBits & 0x4) != 0x0) {
            obj.worldInteraction = WorldInteraction.deserialize(buf, offset + 24);
        }
        if ((nullBits & 0x8) != 0x0) {
            final int varPos0 = offset + 52 + buf.getIntLE(offset + 44);
            final int itemInHandIdLen = VarInt.peek(buf, varPos0);
            if (itemInHandIdLen < 0) {
                throw ProtocolException.negativeLength("ItemInHandId", itemInHandIdLen);
            }
            if (itemInHandIdLen > 4096000) {
                throw ProtocolException.stringTooLong("ItemInHandId", itemInHandIdLen, 4096000);
            }
            obj.itemInHandId = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8);
        }
        if ((nullBits & 0x10) != 0x0) {
            final int varPos2 = offset + 52 + buf.getIntLE(offset + 48);
            obj.mouseMotion = MouseMotionEvent.deserialize(buf, varPos2);
        }
        return obj;
    }
    
    public static int computeBytesConsumed(@Nonnull final ByteBuf buf, final int offset) {
        final byte nullBits = buf.getByte(offset);
        int maxEnd = 52;
        if ((nullBits & 0x8) != 0x0) {
            final int fieldOffset0 = buf.getIntLE(offset + 44);
            int pos0 = offset + 52 + fieldOffset0;
            final int sl = VarInt.peek(buf, pos0);
            pos0 += VarInt.length(buf, pos0) + sl;
            if (pos0 - offset > maxEnd) {
                maxEnd = pos0 - offset;
            }
        }
        if ((nullBits & 0x10) != 0x0) {
            final int fieldOffset2 = buf.getIntLE(offset + 48);
            int pos2 = offset + 52 + fieldOffset2;
            pos2 += MouseMotionEvent.computeBytesConsumed(buf, pos2);
            if (pos2 - offset > maxEnd) {
                maxEnd = pos2 - offset;
            }
        }
        return maxEnd;
    }
    
    @Override
    public void serialize(@Nonnull final ByteBuf buf) {
        final int startPos = buf.writerIndex();
        byte nullBits = 0;
        if (this.screenPoint != null) {
            nullBits |= 0x1;
        }
        if (this.mouseButton != null) {
            nullBits |= 0x2;
        }
        if (this.worldInteraction != null) {
            nullBits |= 0x4;
        }
        if (this.itemInHandId != null) {
            nullBits |= 0x8;
        }
        if (this.mouseMotion != null) {
            nullBits |= 0x10;
        }
        buf.writeByte(nullBits);
        buf.writeLongLE(this.clientTimestamp);
        buf.writeIntLE(this.activeSlot);
        if (this.screenPoint != null) {
            this.screenPoint.serialize(buf);
        }
        else {
            buf.writeZero(8);
        }
        if (this.mouseButton != null) {
            this.mouseButton.serialize(buf);
        }
        else {
            buf.writeZero(3);
        }
        if (this.worldInteraction != null) {
            this.worldInteraction.serialize(buf);
        }
        else {
            buf.writeZero(20);
        }
        final int itemInHandIdOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int mouseMotionOffsetSlot = buf.writerIndex();
        buf.writeIntLE(0);
        final int varBlockStart = buf.writerIndex();
        if (this.itemInHandId != null) {
            buf.setIntLE(itemInHandIdOffsetSlot, buf.writerIndex() - varBlockStart);
            PacketIO.writeVarString(buf, this.itemInHandId, 4096000);
        }
        else {
            buf.setIntLE(itemInHandIdOffsetSlot, -1);
        }
        if (this.mouseMotion != null) {
            buf.setIntLE(mouseMotionOffsetSlot, buf.writerIndex() - varBlockStart);
            this.mouseMotion.serialize(buf);
        }
        else {
            buf.setIntLE(mouseMotionOffsetSlot, -1);
        }
    }
    
    @Override
    public int computeSize() {
        int size = 52;
        if (this.itemInHandId != null) {
            size += PacketIO.stringSize(this.itemInHandId);
        }
        if (this.mouseMotion != null) {
            size += this.mouseMotion.computeSize();
        }
        return size;
    }
    
    public static ValidationResult validateStructure(@Nonnull final ByteBuf buffer, final int offset) {
        if (buffer.readableBytes() - offset < 52) {
            return ValidationResult.error("Buffer too small: expected at least 52 bytes");
        }
        final byte nullBits = buffer.getByte(offset);
        if ((nullBits & 0x8) != 0x0) {
            final int itemInHandIdOffset = buffer.getIntLE(offset + 44);
            if (itemInHandIdOffset < 0) {
                return ValidationResult.error("Invalid offset for ItemInHandId");
            }
            int pos = offset + 52 + itemInHandIdOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for ItemInHandId");
            }
            final int itemInHandIdLen = VarInt.peek(buffer, pos);
            if (itemInHandIdLen < 0) {
                return ValidationResult.error("Invalid string length for ItemInHandId");
            }
            if (itemInHandIdLen > 4096000) {
                return ValidationResult.error("ItemInHandId exceeds max length 4096000");
            }
            pos += VarInt.length(buffer, pos);
            pos += itemInHandIdLen;
            if (pos > buffer.writerIndex()) {
                return ValidationResult.error("Buffer overflow reading ItemInHandId");
            }
        }
        if ((nullBits & 0x10) != 0x0) {
            final int mouseMotionOffset = buffer.getIntLE(offset + 48);
            if (mouseMotionOffset < 0) {
                return ValidationResult.error("Invalid offset for MouseMotion");
            }
            int pos = offset + 52 + mouseMotionOffset;
            if (pos >= buffer.writerIndex()) {
                return ValidationResult.error("Offset out of bounds for MouseMotion");
            }
            final ValidationResult mouseMotionResult = MouseMotionEvent.validateStructure(buffer, pos);
            if (!mouseMotionResult.isValid()) {
                return ValidationResult.error("Invalid MouseMotion: " + mouseMotionResult.error());
            }
            pos += MouseMotionEvent.computeBytesConsumed(buffer, pos);
        }
        return ValidationResult.OK;
    }
    
    public MouseInteraction clone() {
        final MouseInteraction copy = new MouseInteraction();
        copy.clientTimestamp = this.clientTimestamp;
        copy.activeSlot = this.activeSlot;
        copy.itemInHandId = this.itemInHandId;
        copy.screenPoint = ((this.screenPoint != null) ? this.screenPoint.clone() : null);
        copy.mouseButton = ((this.mouseButton != null) ? this.mouseButton.clone() : null);
        copy.mouseMotion = ((this.mouseMotion != null) ? this.mouseMotion.clone() : null);
        copy.worldInteraction = ((this.worldInteraction != null) ? this.worldInteraction.clone() : null);
        return copy;
    }
    
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof final MouseInteraction other) {
            return this.clientTimestamp == other.clientTimestamp && this.activeSlot == other.activeSlot && Objects.equals(this.itemInHandId, other.itemInHandId) && Objects.equals(this.screenPoint, other.screenPoint) && Objects.equals(this.mouseButton, other.mouseButton) && Objects.equals(this.mouseMotion, other.mouseMotion) && Objects.equals(this.worldInteraction, other.worldInteraction);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(this.clientTimestamp, this.activeSlot, this.itemInHandId, this.screenPoint, this.mouseButton, this.mouseMotion, this.worldInteraction);
    }
}
