package net.minecraft.network.protocol.game;

import net.minecraft.network.PacketListener;
import java.io.IOException;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.level.border.WorldBorder;
import net.minecraft.network.protocol.Packet;

public class ClientboundSetBorderPacket implements Packet<ClientGamePacketListener> {
    private Type type;
    private int newAbsoluteMaxSize;
    private double newCenterX;
    private double newCenterZ;
    private double newSize;
    private double oldSize;
    private long lerpTime;
    private int warningTime;
    private int warningBlocks;
    
    public ClientboundSetBorderPacket() {
    }
    
    public ClientboundSetBorderPacket(final WorldBorder bzw, final Type a) {
        this.type = a;
        this.newCenterX = bzw.getCenterX();
        this.newCenterZ = bzw.getCenterZ();
        this.oldSize = bzw.getSize();
        this.newSize = bzw.getLerpTarget();
        this.lerpTime = bzw.getLerpRemainingTime();
        this.newAbsoluteMaxSize = bzw.getAbsoluteMaxSize();
        this.warningBlocks = bzw.getWarningBlocks();
        this.warningTime = bzw.getWarningTime();
    }
    
    @Override
    public void read(final FriendlyByteBuf kv) throws IOException {
        this.type = kv.<Type>readEnum(Type.class);
        switch (this.type) {
            case SET_SIZE: {
                this.newSize = kv.readDouble();
                break;
            }
            case LERP_SIZE: {
                this.oldSize = kv.readDouble();
                this.newSize = kv.readDouble();
                this.lerpTime = kv.readVarLong();
                break;
            }
            case SET_CENTER: {
                this.newCenterX = kv.readDouble();
                this.newCenterZ = kv.readDouble();
                break;
            }
            case SET_WARNING_BLOCKS: {
                this.warningBlocks = kv.readVarInt();
                break;
            }
            case SET_WARNING_TIME: {
                this.warningTime = kv.readVarInt();
                break;
            }
            case INITIALIZE: {
                this.newCenterX = kv.readDouble();
                this.newCenterZ = kv.readDouble();
                this.oldSize = kv.readDouble();
                this.newSize = kv.readDouble();
                this.lerpTime = kv.readVarLong();
                this.newAbsoluteMaxSize = kv.readVarInt();
                this.warningBlocks = kv.readVarInt();
                this.warningTime = kv.readVarInt();
                break;
            }
        }
    }
    
    @Override
    public void write(final FriendlyByteBuf kv) throws IOException {
        kv.writeEnum(this.type);
        switch (this.type) {
            case SET_SIZE: {
                kv.writeDouble(this.newSize);
                break;
            }
            case LERP_SIZE: {
                kv.writeDouble(this.oldSize);
                kv.writeDouble(this.newSize);
                kv.writeVarLong(this.lerpTime);
                break;
            }
            case SET_CENTER: {
                kv.writeDouble(this.newCenterX);
                kv.writeDouble(this.newCenterZ);
                break;
            }
            case SET_WARNING_TIME: {
                kv.writeVarInt(this.warningTime);
                break;
            }
            case SET_WARNING_BLOCKS: {
                kv.writeVarInt(this.warningBlocks);
                break;
            }
            case INITIALIZE: {
                kv.writeDouble(this.newCenterX);
                kv.writeDouble(this.newCenterZ);
                kv.writeDouble(this.oldSize);
                kv.writeDouble(this.newSize);
                kv.writeVarLong(this.lerpTime);
                kv.writeVarInt(this.newAbsoluteMaxSize);
                kv.writeVarInt(this.warningBlocks);
                kv.writeVarInt(this.warningTime);
                break;
            }
        }
    }
    
    @Override
    public void handle(final ClientGamePacketListener lw) {
        lw.handleSetBorder(this);
    }
    
    public void applyChanges(final WorldBorder bzw) {
        switch (this.type) {
            case SET_SIZE: {
                bzw.setSize(this.newSize);
                break;
            }
            case LERP_SIZE: {
                bzw.lerpSizeBetween(this.oldSize, this.newSize, this.lerpTime);
                break;
            }
            case SET_CENTER: {
                bzw.setCenter(this.newCenterX, this.newCenterZ);
                break;
            }
            case INITIALIZE: {
                bzw.setCenter(this.newCenterX, this.newCenterZ);
                if (this.lerpTime > 0L) {
                    bzw.lerpSizeBetween(this.oldSize, this.newSize, this.lerpTime);
                }
                else {
                    bzw.setSize(this.newSize);
                }
                bzw.setAbsoluteMaxSize(this.newAbsoluteMaxSize);
                bzw.setWarningBlocks(this.warningBlocks);
                bzw.setWarningTime(this.warningTime);
                break;
            }
            case SET_WARNING_TIME: {
                bzw.setWarningTime(this.warningTime);
                break;
            }
            case SET_WARNING_BLOCKS: {
                bzw.setWarningBlocks(this.warningBlocks);
                break;
            }
        }
    }
    
    public enum Type {
        SET_SIZE, 
        LERP_SIZE, 
        SET_CENTER, 
        INITIALIZE, 
        SET_WARNING_TIME, 
        SET_WARNING_BLOCKS;
    }
}
