// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0
package org.terasology.engine.math;

import com.google.common.collect.Maps;
import org.joml.Math;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.joml.Vector3i;
import org.joml.Vector3ic;

import java.util.EnumMap;

/**
 * An enumeration of the axis of the world from the player perspective. There is also
 *
 */
public enum Direction {
    UP(new Vector3i(0, 1, 0), new Vector3f(0, 1, 0)),
    RIGHT(new Vector3i(-1, 0, 0), new Vector3f(-1, 0, 0)),
    LEFT(new Vector3i(1, 0, 0), new Vector3f(1, 0, 0)),
    BACKWARD(new Vector3i(0, 0, -1), new Vector3f(0, 0, -1)),
    FORWARD(new Vector3i(0, 0, 1), new Vector3f(0, 0, 1)),
    DOWN(new Vector3i(0, -1, 0), new Vector3f(0, -1, 0));

    private static final EnumMap<Direction, Direction> REVERSE_MAP;
    private static final EnumMap<Direction, Side> CONVERSION_MAP;

    private final Vector3i vector3iDir;
    private final Vector3f vector3fDir;

    static {
        REVERSE_MAP = new EnumMap<>(Direction.class);
        REVERSE_MAP.put(UP, DOWN);
        REVERSE_MAP.put(LEFT, RIGHT);
        REVERSE_MAP.put(RIGHT, LEFT);
        REVERSE_MAP.put(FORWARD, BACKWARD);
        REVERSE_MAP.put(BACKWARD, FORWARD);
        REVERSE_MAP.put(DOWN, UP);
        CONVERSION_MAP = Maps.newEnumMap(Direction.class);
        CONVERSION_MAP.put(UP, Side.TOP);
        CONVERSION_MAP.put(DOWN, Side.BOTTOM);
        CONVERSION_MAP.put(FORWARD, Side.BACK);
        CONVERSION_MAP.put(BACKWARD, Side.FRONT);
        CONVERSION_MAP.put(LEFT, Side.RIGHT);
        CONVERSION_MAP.put(RIGHT, Side.LEFT);
    }

    Direction(Vector3i vector3i, Vector3f vector3f) {
        this.vector3iDir = vector3i;
        this.vector3fDir = vector3f;
    }

    public static Direction inDirection(int x, int y, int z) {
        if (Math.abs(x) > Math.abs(y)) {
            if (Math.abs(x) > Math.abs(z)) {
                return (x > 0) ? LEFT : RIGHT;
            }
        } else if (Math.abs(y) > Math.abs(z)) {
            return (y > 0) ? UP : DOWN;
        }
        return (z > 0) ? FORWARD : BACKWARD;
    }

    public static Direction inDirection(Vector3fc dir) {
        return inDirection(dir.x(), dir.y(), dir.z());
    }

    public Side toSide() {
        return CONVERSION_MAP.get(this);
    }

    /**
     * Determines which direction the player is facing
     *
     * @param x right/left
     * @param y top/bottom
     * @param z back/front
     * @return Side enum with the appropriate direction
     */
    public static Direction inDirection(float x, float y, float z) {
        if (Math.abs(x) > Math.abs(y)) {
            if (Math.abs(x) > Math.abs(z)) {
                return (x > 0) ? LEFT : RIGHT;
            }
        } else if (Math.abs(y) > Math.abs(z)) {
            return (y > 0) ? UP : DOWN;
        }
        return (z > 0) ? FORWARD : BACKWARD;
    }

    /**
     * Determines which horizontal direction the player is facing
     *
     * @param x right/left
     * @param z back/front
     * @return Side enum with the appropriate direction
     */
    public static Direction inHorizontalDirection(float x, float z) {
        if (Math.abs(x) > Math.abs(z)) {
            return (x > 0) ? LEFT : RIGHT;
        }
        return (z > 0) ? FORWARD : BACKWARD;
    }


    /**
     * readonly normalized {@link Vector3ic} in the given {@link Direction}
     *
     * @return vector pointing in the direction
     */
    public Vector3ic asVector3i() {
        return vector3iDir;
    }

    /**
     * readonly normalized {@link Vector3fc} in the given {@link Direction}
     *
     * @return vector pointing in the direction
     */
    public Vector3fc asVector3f() {
        return vector3fDir;
    }

    /**
     * @return The opposite side to this side.
     */
    public Direction reverse() {
        return REVERSE_MAP.get(this);
    }

}

@@ -152,16 +152,96 @@
 t.Maps;%0A
+import net.logstash.logback.encoder.org.apache.commons.lang.UnhandledException;%0A
 import o
@@ -874,856 +874,75 @@
 ate 
-static final EnumMap%3CDirection, Direction%3E REVERSE_MAP;%0A    private static final EnumMap%3CDirection, Side%3E CONVERSION_MAP;%0A%0A    private final Vector3i vector3iDir;%0A    private final Vector3f vector3fDir;%0A%0A    static %7B%0A        REVERSE_MAP = new EnumMap%3C%3E(Direction.class);%0A        REVERSE_MAP.put(UP, DOWN);%0A        REVERSE_MAP.put(LEFT, RIGHT);%0A        REVERSE_MAP.put(RIGHT, LEFT);%0A        REVERSE_MAP.put(FORWARD, BACKWARD);%0A        REVERSE_MAP.put(BACKWARD, FORWARD);%0A        REVERSE_MAP.put(DOWN, UP);%0A        CONVERSION_MAP = Maps.newEnumMap(Direction.class);%0A        CONVERSION_MAP.put(UP, Side.TOP);%0A        CONVERSION_MAP.put(DOWN, Side.BOTTOM);%0A        CONVERSION_MAP.put(FORWARD, Side.BACK);%0A        CONVERSION_MAP.put(BACKWARD, Side.FRONT);%0A        CONVERSION_MAP.put(LEFT, Side.RIGHT);%0A        CONVERSION_MAP.put(RIGHT, Side.LEFT);%0A    %7D
+final Vector3i vector3iDir;%0A    private final Vector3f vector3fDir;
 %0A%0A  
@@ -1592,40 +1592,483 @@
     
-return CONVERSION_MAP.get(this);
+switch (this) %7B%0A            case UP:%0A                return Side.TOP;%0A            case DOWN:%0A                return Side.BOTTOM;%0A            case FORWARD:%0A                return Side.BACK;%0A            case BACKWARD:%0A                return Side.FRONT;%0A            case LEFT:%0A                return Side.RIGHT;%0A            case RIGHT:%0A                return Side.LEFT;%0A            default:%0A                throw new IllegalStateException(%22Unexpected value: %22 + this);%0A        %7D
 %0A   
@@ -3612,37 +3612,456 @@
     
-return REVERSE_MAP.get(this);
+switch (this) %7B%0A            case RIGHT:%0A                return LEFT;%0A            case LEFT:%0A                return RIGHT;%0A            case UP:%0A                return DOWN;%0A            case DOWN:%0A                return UP;%0A            case FORWARD:%0A                return BACKWARD;%0A            case BACKWARD:%0A                return FORWARD;%0A            default:%0A                throw new IllegalStateException(%22Unexpected value: %22 + this);%0A        %7D
 %0A   

replace map with switch for mapping direction (#4668)