package net.minecraft.world.level.saveddata.maps;

import java.util.AbstractList;
import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket;
import net.minecraft.world.item.MapItem;
import net.minecraft.network.protocol.Packet;
import net.minecraft.world.level.BlockGetter;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.item.ItemStack;
import java.util.Iterator;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Mth;
import com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import net.minecraft.world.entity.player.Player;
import java.util.Map;
import java.util.List;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.saveddata.SavedData;

public class MapItemSavedData extends SavedData {
    public int x;
    public int z;
    public DimensionType dimension;
    public boolean trackingPosition;
    public boolean unlimitedTracking;
    public byte scale;
    public byte[] colors;
    public boolean locked;
    public final List<HoldingPlayer> carriedBy;
    private final Map<Player, HoldingPlayer> carriedByPlayers;
    private final Map<String, MapBanner> bannerMarkers;
    public final Map<String, MapDecoration> decorations;
    private final Map<String, MapFrame> frameMarkers;
    
    public MapItemSavedData(final String string) {
        super(string);
        this.colors = new byte[16384];
        this.carriedBy = Lists.newArrayList();
        this.carriedByPlayers = Maps.newHashMap();
        this.bannerMarkers = Maps.newHashMap();
        this.decorations = Maps.newLinkedHashMap();
        this.frameMarkers = Maps.newHashMap();
    }
    
    public void setProperties(final int integer1, final int integer2, final int integer3, final boolean boolean4, final boolean boolean5, final DimensionType cbi) {
        this.scale = (byte)integer3;
        this.setOrigin(integer1, integer2, this.scale);
        this.dimension = cbi;
        this.trackingPosition = boolean4;
        this.unlimitedTracking = boolean5;
        this.setDirty();
    }
    
    public void setOrigin(final double double1, final double double2, final int integer) {
        final int integer2 = 128 * (1 << integer);
        final int integer3 = Mth.floor((double1 + 64.0) / integer2);
        final int integer4 = Mth.floor((double2 + 64.0) / integer2);
        this.x = integer3 * integer2 + integer2 / 2 - 64;
        this.z = integer4 * integer2 + integer2 / 2 - 64;
    }
    
    @Override
    public void load(final CompoundTag jt) {
        final int integer3 = jt.getInt("dimension");
        final DimensionType cbi4 = DimensionType.getById(integer3);
        if (cbi4 == null) {
            throw new IllegalArgumentException("Invalid map dimension: " + integer3);
        }
        this.dimension = cbi4;
        this.x = jt.getInt("xCenter");
        this.z = jt.getInt("zCenter");
        this.scale = (byte)Mth.clamp(jt.getByte("scale"), 0, 4);
        this.trackingPosition = (!jt.contains("trackingPosition", 1) || jt.getBoolean("trackingPosition"));
        this.unlimitedTracking = jt.getBoolean("unlimitedTracking");
        this.locked = jt.getBoolean("locked");
        this.colors = jt.getByteArray("colors");
        if (this.colors.length != 16384) {
            this.colors = new byte[16384];
        }
        final ListTag jz5 = jt.getList("banners", 10);
        for (int integer4 = 0; integer4 < jz5.size(); ++integer4) {
            final MapBanner crc7 = MapBanner.load(jz5.getCompound(integer4));
            this.bannerMarkers.put(crc7.getId(), crc7);
            this.addDecoration(crc7.getDecoration(), null, crc7.getId(), crc7.getPos().getX(), crc7.getPos().getZ(), 180.0, crc7.getName());
        }
        final ListTag jz6 = jt.getList("frames", 10);
        for (int integer5 = 0; integer5 < jz6.size(); ++integer5) {
            final MapFrame cre8 = MapFrame.load(jz6.getCompound(integer5));
            this.frameMarkers.put(cre8.getId(), cre8);
            this.addDecoration(MapDecoration.Type.FRAME, null, "frame-" + cre8.getEntityId(), cre8.getPos().getX(), cre8.getPos().getZ(), cre8.getRotation(), null);
        }
    }
    
    @Override
    public CompoundTag save(final CompoundTag jt) {
        jt.putInt("dimension", this.dimension.getId());
        jt.putInt("xCenter", this.x);
        jt.putInt("zCenter", this.z);
        jt.putByte("scale", this.scale);
        jt.putByteArray("colors", this.colors);
        jt.putBoolean("trackingPosition", this.trackingPosition);
        jt.putBoolean("unlimitedTracking", this.unlimitedTracking);
        jt.putBoolean("locked", this.locked);
        final ListTag jz3 = new ListTag();
        for (final MapBanner crc5 : this.bannerMarkers.values()) {
            ((AbstractList<CompoundTag>)jz3).add(crc5.save());
        }
        jt.put("banners", jz3);
        final ListTag jz4 = new ListTag();
        for (final MapFrame cre6 : this.frameMarkers.values()) {
            ((AbstractList<CompoundTag>)jz4).add(cre6.save());
        }
        jt.put("frames", jz4);
        return jt;
    }
    
    public void lockData(final MapItemSavedData crg) {
        this.locked = true;
        this.x = crg.x;
        this.z = crg.z;
        this.bannerMarkers.putAll(crg.bannerMarkers);
        this.decorations.putAll(crg.decorations);
        System.arraycopy(crg.colors, 0, this.colors, 0, crg.colors.length);
        this.setDirty();
    }
    
    public void tickCarriedBy(final Player ayj, final ItemStack ben) {
        if (!this.carriedByPlayers.containsKey(ayj)) {
            final HoldingPlayer a4 = new HoldingPlayer(ayj);
            this.carriedByPlayers.put(ayj, a4);
            this.carriedBy.add(a4);
        }
        if (!ayj.inventory.contains(ben)) {
            this.decorations.remove(ayj.getName().getString());
        }
        for (int integer4 = 0; integer4 < this.carriedBy.size(); ++integer4) {
            final HoldingPlayer a5 = this.carriedBy.get(integer4);
            final String string6 = a5.player.getName().getString();
            if (a5.player.removed || (!a5.player.inventory.contains(ben) && !ben.isFramed())) {
                this.carriedByPlayers.remove(a5.player);
                this.carriedBy.remove(a5);
                this.decorations.remove(string6);
            }
            else if (!ben.isFramed() && a5.player.dimension == this.dimension && this.trackingPosition) {
                this.addDecoration(MapDecoration.Type.PLAYER, a5.player.level, string6, a5.player.getX(), a5.player.getZ(), a5.player.yRot, null);
            }
        }
        if (ben.isFramed() && this.trackingPosition) {
            final ItemFrame avr4 = ben.getFrame();
            final BlockPos fk5 = avr4.getPos();
            final MapFrame cre6 = this.frameMarkers.get(MapFrame.frameId(fk5));
            if (cre6 != null && avr4.getId() != cre6.getEntityId() && this.frameMarkers.containsKey(cre6.getId())) {
                this.decorations.remove("frame-" + cre6.getEntityId());
            }
            final MapFrame cre7 = new MapFrame(fk5, avr4.getDirection().get2DDataValue() * 90, avr4.getId());
            this.addDecoration(MapDecoration.Type.FRAME, ayj.level, "frame-" + avr4.getId(), fk5.getX(), fk5.getZ(), avr4.getDirection().get2DDataValue() * 90, null);
            this.frameMarkers.put(cre7.getId(), cre7);
        }
        final CompoundTag jt4 = ben.getTag();
        if (jt4 != null && jt4.contains("Decorations", 9)) {
            final ListTag jz5 = jt4.getList("Decorations", 10);
            for (int integer5 = 0; integer5 < jz5.size(); ++integer5) {
                final CompoundTag jt5 = jz5.getCompound(integer5);
                if (!this.decorations.containsKey(jt5.getString("id"))) {
                    this.addDecoration(MapDecoration.Type.byIcon(jt5.getByte("type")), ayj.level, jt5.getString("id"), jt5.getDouble("x"), jt5.getDouble("z"), jt5.getDouble("rot"), null);
                }
            }
        }
    }
    
    public static void addTargetDecoration(final ItemStack ben, final BlockPos fk, final String string, final MapDecoration.Type a) {
        ListTag jz5;
        if (ben.hasTag() && ben.getTag().contains("Decorations", 9)) {
            jz5 = ben.getTag().getList("Decorations", 10);
        }
        else {
            jz5 = new ListTag();
            ben.addTagElement("Decorations", jz5);
        }
        final CompoundTag jt6 = new CompoundTag();
        jt6.putByte("type", a.getIcon());
        jt6.putString("id", string);
        jt6.putDouble("x", fk.getX());
        jt6.putDouble("z", fk.getZ());
        jt6.putDouble("rot", 180.0);
        ((AbstractList<CompoundTag>)jz5).add(jt6);
        if (a.hasMapColor()) {
            final CompoundTag jt7 = ben.getOrCreateTagElement("display");
            jt7.putInt("MapColor", a.getMapColor());
        }
    }
    
    private void addDecoration(MapDecoration.Type a, @Nullable final LevelAccessor bjx, final String string, final double double4, final double double5, double double6, @Nullable final Component lf) {
        final int integer12 = 1 << this.scale;
        final float float13 = (float)(double4 - this.x) / integer12;
        final float float14 = (float)(double5 - this.z) / integer12;
        byte byte15 = (byte)(float13 * 2.0f + 0.5);
        byte byte16 = (byte)(float14 * 2.0f + 0.5);
        final int integer13 = 63;
        byte byte17;
        if (float13 >= -63.0f && float14 >= -63.0f && float13 <= 63.0f && float14 <= 63.0f) {
            double6 += ((double6 < 0.0) ? -8.0 : 8.0);
            byte17 = (byte)(double6 * 16.0 / 360.0);
            if (this.dimension == DimensionType.NETHER && bjx != null) {
                final int integer14 = (int)(bjx.getLevelData().getDayTime() / 10L);
                byte17 = (byte)(integer14 * integer14 * 34187121 + integer14 * 121 >> 15 & 0xF);
            }
        }
        else {
            if (a != MapDecoration.Type.PLAYER) {
                this.decorations.remove(string);
                return;
            }
            final int integer14 = 320;
            if (Math.abs(float13) < 320.0f && Math.abs(float14) < 320.0f) {
                a = MapDecoration.Type.PLAYER_OFF_MAP;
            }
            else {
                if (!this.unlimitedTracking) {
                    this.decorations.remove(string);
                    return;
                }
                a = MapDecoration.Type.PLAYER_OFF_LIMITS;
            }
            byte17 = 0;
            if (float13 <= -63.0f) {
                byte15 = -128;
            }
            if (float14 <= -63.0f) {
                byte16 = -128;
            }
            if (float13 >= 63.0f) {
                byte15 = 127;
            }
            if (float14 >= 63.0f) {
                byte16 = 127;
            }
        }
        this.decorations.put(string, new MapDecoration(a, byte15, byte16, byte17, lf));
    }
    
    @Nullable
    public Packet<?> getUpdatePacket(final ItemStack ben, final BlockGetter bjg, final Player ayj) {
        final HoldingPlayer a5 = this.carriedByPlayers.get(ayj);
        if (a5 == null) {
            return null;
        }
        return a5.nextUpdatePacket(ben);
    }
    
    public void setDirty(final int integer1, final int integer2) {
        this.setDirty();
        for (final HoldingPlayer a5 : this.carriedBy) {
            a5.markDirty(integer1, integer2);
        }
    }
    
    public HoldingPlayer getHoldingPlayer(final Player ayj) {
        HoldingPlayer a3 = this.carriedByPlayers.get(ayj);
        if (a3 == null) {
            a3 = new HoldingPlayer(ayj);
            this.carriedByPlayers.put(ayj, a3);
            this.carriedBy.add(a3);
        }
        return a3;
    }
    
    public void toggleBanner(final LevelAccessor bjx, final BlockPos fk) {
        final float float4 = fk.getX() + 0.5f;
        final float float5 = fk.getZ() + 0.5f;
        final int integer6 = 1 << this.scale;
        final float float6 = (float4 - this.x) / integer6;
        final float float7 = (float5 - this.z) / integer6;
        final int integer7 = 63;
        boolean boolean10 = false;
        if (float6 >= -63.0f && float7 >= -63.0f && float6 <= 63.0f && float7 <= 63.0f) {
            final MapBanner crc11 = MapBanner.fromWorld(bjx, fk);
            if (crc11 == null) {
                return;
            }
            boolean boolean11 = true;
            if (this.bannerMarkers.containsKey(crc11.getId()) && this.bannerMarkers.get(crc11.getId()).equals(crc11)) {
                this.bannerMarkers.remove(crc11.getId());
                this.decorations.remove(crc11.getId());
                boolean11 = false;
                boolean10 = true;
            }
            if (boolean11) {
                this.bannerMarkers.put(crc11.getId(), crc11);
                this.addDecoration(crc11.getDecoration(), bjx, crc11.getId(), float4, float5, 180.0, crc11.getName());
                boolean10 = true;
            }
            if (boolean10) {
                this.setDirty();
            }
        }
    }
    
    public void checkBanners(final BlockGetter bjg, final int integer2, final int integer3) {
        final Iterator<MapBanner> iterator5 = this.bannerMarkers.values().iterator();
        while (iterator5.hasNext()) {
            final MapBanner crc6 = iterator5.next();
            if (crc6.getPos().getX() == integer2 && crc6.getPos().getZ() == integer3) {
                final MapBanner crc7 = MapBanner.fromWorld(bjg, crc6.getPos());
                if (crc6.equals(crc7)) {
                    continue;
                }
                iterator5.remove();
                this.decorations.remove(crc6.getId());
            }
        }
    }
    
    public void removedFromFrame(final BlockPos fk, final int integer) {
        this.decorations.remove("frame-" + integer);
        this.frameMarkers.remove(MapFrame.frameId(fk));
    }
    
    public class HoldingPlayer {
        public final Player player;
        private boolean dirtyData;
        private int minDirtyX;
        private int minDirtyY;
        private int maxDirtyX;
        private int maxDirtyY;
        private int tick;
        public int step;
        
        public HoldingPlayer(final Player ayj) {
            this.dirtyData = true;
            this.maxDirtyX = 127;
            this.maxDirtyY = 127;
            this.player = ayj;
        }
        
        @Nullable
        public Packet<?> nextUpdatePacket(final ItemStack ben) {
            if (this.dirtyData) {
                this.dirtyData = false;
                return new ClientboundMapItemDataPacket(MapItem.getMapId(ben), MapItemSavedData.this.scale, MapItemSavedData.this.trackingPosition, MapItemSavedData.this.locked, MapItemSavedData.this.decorations.values(), MapItemSavedData.this.colors, this.minDirtyX, this.minDirtyY, this.maxDirtyX + 1 - this.minDirtyX, this.maxDirtyY + 1 - this.minDirtyY);
            }
            if (this.tick++ % 5 == 0) {
                return new ClientboundMapItemDataPacket(MapItem.getMapId(ben), MapItemSavedData.this.scale, MapItemSavedData.this.trackingPosition, MapItemSavedData.this.locked, MapItemSavedData.this.decorations.values(), MapItemSavedData.this.colors, 0, 0, 0, 0);
            }
            return null;
        }
        
        public void markDirty(final int integer1, final int integer2) {
            if (this.dirtyData) {
                this.minDirtyX = Math.min(this.minDirtyX, integer1);
                this.minDirtyY = Math.min(this.minDirtyY, integer2);
                this.maxDirtyX = Math.max(this.maxDirtyX, integer1);
                this.maxDirtyY = Math.max(this.maxDirtyY, integer2);
            }
            else {
                this.dirtyData = true;
                this.minDirtyX = integer1;
                this.minDirtyY = integer2;
                this.maxDirtyX = integer1;
                this.maxDirtyY = integer2;
            }
        }
    }
}
