/*
    This file is a part of the SteamWar software.

    Copyright (C) 2020  SteamWar.de-Serverteam

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.core;

import de.steamwar.Reflection;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import net.minecraft.server.v1_8_R3.ChatComponentText;
import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.PacketPlayOutChat;
import org.bukkit.Sound;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;

import java.util.HashMap;
import java.util.Map;

public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper {

    @Override
    public void playPling(Player player) {
        player.playSound(player.getLocation(), Sound.ORB_PICKUP, 1, 1);
    }

    @Override
    public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
        ((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(new ChatComponentText(BaseComponent.toLegacyText(msg)), (byte)type.ordinal()));
    }

    @Override
    public Object getDataWatcherObject(int index, Class<?> type) {
        return index;
    }

    private static final Class<?> watchableObject = Reflection.getClass("net.minecraft.DataWatcher$WatchableObject");
    private static final Reflection.Constructor watchableObjectConstructor = Reflection.getConstructor(watchableObject, int.class, int.class, Object.class);
    private static final Map<Class<?>, Integer> watchableDatatypes = new HashMap<>();
    static {
        watchableDatatypes.put(byte.class, 0);
        watchableDatatypes.put(short.class, 1);
        watchableDatatypes.put(int.class, 2);
        watchableDatatypes.put(float.class, 3);
        watchableDatatypes.put(String.class, 4);
    }

    @Override
    public Object getDataWatcherItem(Object dwo, Object value) {
        return watchableObjectConstructor.invoke(watchableDatatypes.get(value.getClass()), dwo, value);
    }

    @Override
    public BountifulWrapper.PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset) {
        Reflection.Field<Integer> posX = Reflection.getField(packetClass, int.class, fieldOffset);
        Reflection.Field<Integer> posY = Reflection.getField(packetClass, int.class, fieldOffset +1);
        Reflection.Field<Integer> posZ = Reflection.getField(packetClass, int.class, fieldOffset +2);
        Reflection.Field<Byte> lookYaw = Reflection.getField(packetClass, byte.class, 0);
        Reflection.Field<Byte> lookPitch = Reflection.getField(packetClass, byte.class, 1);

        return (packet, x, y, z, pitch, yaw) -> {
            posX.set(packet, MathHelper.floor(x * 32));
            posY.set(packet, MathHelper.floor(y * 32));
            posZ.set(packet, MathHelper.floor(z * 32));
            lookYaw.set(packet, (byte)(yaw * 256 / 360));
            lookPitch.set(packet, (byte)(pitch * 256 / 360));
        };
    }

    @Override
    public BountifulWrapper.PositionSetter getRelMoveSetter(Class<?> packetClass) {
        Reflection.Field<?> moveX = Reflection.getField(packetClass, "b", byte.class);
        Reflection.Field<?> moveY = Reflection.getField(packetClass, "c", byte.class);
        Reflection.Field<?> moveZ = Reflection.getField(packetClass, "d", byte.class);
        Reflection.Field<Byte> lookYaw = Reflection.getField(packetClass, "e", byte.class);
        Reflection.Field<Byte> lookPitch = Reflection.getField(packetClass, "f", byte.class);

        return (packet, x, y, z, pitch, yaw) -> {
            moveX.set(packet, (byte)(x*32));
            moveY.set(packet, (byte)(y*32));
            moveZ.set(packet, (byte)(z*32));
            lookYaw.set(packet, (byte)(yaw*256/360));
            lookPitch.set(packet, (byte)(pitch*256/360));
        };
    }

    @Override
    public BountifulWrapper.UUIDSetter getUUIDSetter(Class<?> packetClass) {
        return (packet, uuid) -> {};
    }
}
