package com.mojang.math;

import net.minecraft.Util;
import java.util.stream.Collectors;
import com.mojang.datafixers.util.Pair;
import java.util.Arrays;
import net.minecraft.core.FrontAndTop;
import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
import it.unimi.dsi.fastutil.booleans.BooleanList;
import javax.annotation.Nullable;
import net.minecraft.core.Direction;
import java.util.Map;
import net.minecraft.util.StringRepresentable;

public enum OctahedralGroup implements StringRepresentable {
    IDENTITY("identity", SymmetricGroup3.P123, false, false, false), 
    ROT_180_FACE_XY("rot_180_face_xy", SymmetricGroup3.P123, true, true, false), 
    ROT_180_FACE_XZ("rot_180_face_xz", SymmetricGroup3.P123, true, false, true), 
    ROT_180_FACE_YZ("rot_180_face_yz", SymmetricGroup3.P123, false, true, true), 
    ROT_120_NNN("rot_120_nnn", SymmetricGroup3.P231, false, false, false), 
    ROT_120_NNP("rot_120_nnp", SymmetricGroup3.P312, true, false, true), 
    ROT_120_NPN("rot_120_npn", SymmetricGroup3.P312, false, true, true), 
    ROT_120_NPP("rot_120_npp", SymmetricGroup3.P231, true, false, true), 
    ROT_120_PNN("rot_120_pnn", SymmetricGroup3.P312, true, true, false), 
    ROT_120_PNP("rot_120_pnp", SymmetricGroup3.P231, true, true, false), 
    ROT_120_PPN("rot_120_ppn", SymmetricGroup3.P231, false, true, true), 
    ROT_120_PPP("rot_120_ppp", SymmetricGroup3.P312, false, false, false), 
    ROT_180_EDGE_XY_NEG("rot_180_edge_xy_neg", SymmetricGroup3.P213, true, true, true), 
    ROT_180_EDGE_XY_POS("rot_180_edge_xy_pos", SymmetricGroup3.P213, false, false, true), 
    ROT_180_EDGE_XZ_NEG("rot_180_edge_xz_neg", SymmetricGroup3.P321, true, true, true), 
    ROT_180_EDGE_XZ_POS("rot_180_edge_xz_pos", SymmetricGroup3.P321, false, true, false), 
    ROT_180_EDGE_YZ_NEG("rot_180_edge_yz_neg", SymmetricGroup3.P132, true, true, true), 
    ROT_180_EDGE_YZ_POS("rot_180_edge_yz_pos", SymmetricGroup3.P132, true, false, false), 
    ROT_90_X_NEG("rot_90_x_neg", SymmetricGroup3.P132, false, false, true), 
    ROT_90_X_POS("rot_90_x_pos", SymmetricGroup3.P132, false, true, false), 
    ROT_90_Y_NEG("rot_90_y_neg", SymmetricGroup3.P321, true, false, false), 
    ROT_90_Y_POS("rot_90_y_pos", SymmetricGroup3.P321, false, false, true), 
    ROT_90_Z_NEG("rot_90_z_neg", SymmetricGroup3.P213, false, true, false), 
    ROT_90_Z_POS("rot_90_z_pos", SymmetricGroup3.P213, true, false, false), 
    INVERSION("inversion", SymmetricGroup3.P123, true, true, true), 
    INVERT_X("invert_x", SymmetricGroup3.P123, true, false, false), 
    INVERT_Y("invert_y", SymmetricGroup3.P123, false, true, false), 
    INVERT_Z("invert_z", SymmetricGroup3.P123, false, false, true), 
    ROT_60_REF_NNN("rot_60_ref_nnn", SymmetricGroup3.P312, true, true, true), 
    ROT_60_REF_NNP("rot_60_ref_nnp", SymmetricGroup3.P231, true, false, false), 
    ROT_60_REF_NPN("rot_60_ref_npn", SymmetricGroup3.P231, false, false, true), 
    ROT_60_REF_NPP("rot_60_ref_npp", SymmetricGroup3.P312, false, false, true), 
    ROT_60_REF_PNN("rot_60_ref_pnn", SymmetricGroup3.P231, false, true, false), 
    ROT_60_REF_PNP("rot_60_ref_pnp", SymmetricGroup3.P312, true, false, false), 
    ROT_60_REF_PPN("rot_60_ref_ppn", SymmetricGroup3.P312, false, true, false), 
    ROT_60_REF_PPP("rot_60_ref_ppp", SymmetricGroup3.P231, true, true, true), 
    SWAP_XY("swap_xy", SymmetricGroup3.P213, false, false, false), 
    SWAP_YZ("swap_yz", SymmetricGroup3.P132, false, false, false), 
    SWAP_XZ("swap_xz", SymmetricGroup3.P321, false, false, false), 
    SWAP_NEG_XY("swap_neg_xy", SymmetricGroup3.P213, true, true, false), 
    SWAP_NEG_YZ("swap_neg_yz", SymmetricGroup3.P132, false, true, true), 
    SWAP_NEG_XZ("swap_neg_xz", SymmetricGroup3.P321, true, false, true), 
    ROT_90_REF_X_NEG("rot_90_ref_x_neg", SymmetricGroup3.P132, true, false, true), 
    ROT_90_REF_X_POS("rot_90_ref_x_pos", SymmetricGroup3.P132, true, true, false), 
    ROT_90_REF_Y_NEG("rot_90_ref_y_neg", SymmetricGroup3.P321, true, true, false), 
    ROT_90_REF_Y_POS("rot_90_ref_y_pos", SymmetricGroup3.P321, false, true, true), 
    ROT_90_REF_Z_NEG("rot_90_ref_z_neg", SymmetricGroup3.P213, false, true, true), 
    ROT_90_REF_Z_POS("rot_90_ref_z_pos", SymmetricGroup3.P213, true, false, true);
    
    private final Matrix3f transformation;
    private final String name;
    @Nullable
    private Map<Direction, Direction> rotatedDirections;
    private final boolean invertX;
    private final boolean invertY;
    private final boolean invertZ;
    private final SymmetricGroup3 permutation;
    private static final OctahedralGroup[][] cayleyTable;
    private static final OctahedralGroup[] inverseTable;
    
    private OctahedralGroup(final String string3, final SymmetricGroup3 e, final boolean boolean5, final boolean boolean6, final boolean boolean7) {
        this.name = string3;
        this.invertX = boolean5;
        this.invertY = boolean6;
        this.invertZ = boolean7;
        this.permutation = e;
        this.transformation = new Matrix3f();
        this.transformation.m00 = (boolean5 ? -1.0f : 1.0f);
        this.transformation.m11 = (boolean6 ? -1.0f : 1.0f);
        this.transformation.m22 = (boolean7 ? -1.0f : 1.0f);
        this.transformation.mul(e.transformation());
    }
    
    private BooleanList packInversions() {
        return (BooleanList)new BooleanArrayList(new boolean[] { this.invertX, this.invertY, this.invertZ });
    }
    
    public OctahedralGroup compose(final OctahedralGroup c) {
        return OctahedralGroup.cayleyTable[this.ordinal()][c.ordinal()];
    }
    
    @Override
    public String toString() {
        return this.name;
    }
    
    @Override
    public String getSerializedName() {
        return this.name;
    }
    
    public Direction rotate(final Direction fz) {
        if (this.rotatedDirections == null) {
            this.rotatedDirections = Maps.newEnumMap(Direction.class);
            for (final Direction fz2 : Direction.values()) {
                final Direction.Axis a7 = fz2.getAxis();
                final Direction.AxisDirection b8 = fz2.getAxisDirection();
                final Direction.Axis a8 = Direction.Axis.values()[this.permutation.permutation(a7.ordinal())];
                final Direction.AxisDirection b9 = this.inverts(a8) ? b8.opposite() : b8;
                final Direction fz3 = Direction.fromAxisAndDirection(a8, b9);
                this.rotatedDirections.put(fz2, fz3);
            }
        }
        return this.rotatedDirections.get(fz);
    }
    
    public boolean inverts(final Direction.Axis a) {
        switch (a) {
            case X: {
                return this.invertX;
            }
            case Y: {
                return this.invertY;
            }
            default: {
                return this.invertZ;
            }
        }
    }
    
    public FrontAndTop rotate(final FrontAndTop gb) {
        return FrontAndTop.fromFrontAndTop(this.rotate(gb.front()), this.rotate(gb.top()));
    }
    
    static {
        final Map<Pair<SymmetricGroup3, BooleanList>, OctahedralGroup> map2;
        final OctahedralGroup[] array;
        int length;
        int i = 0;
        OctahedralGroup c3;
        final OctahedralGroup[] array2;
        int length2;
        int j = 0;
        OctahedralGroup c4;
        BooleanList booleanList11;
        BooleanList booleanList12;
        SymmetricGroup3 e13;
        BooleanArrayList booleanArrayList14;
        int integer2;
        cayleyTable = Util.<OctahedralGroup[][]>make(new OctahedralGroup[values().length][values().length], arr -> {
            map2 = Arrays.<OctahedralGroup>stream(values()).collect(Collectors.toMap(c -> Pair.of(c.permutation, c.packInversions()), c -> c));
            values();
            for (length = array.length; i < length; ++i) {
                c3 = array[i];
                values();
                for (length2 = array2.length; j < length2; ++j) {
                    c4 = array2[j];
                    booleanList11 = c3.packInversions();
                    booleanList12 = c4.packInversions();
                    e13 = c4.permutation.compose(c3.permutation);
                    booleanArrayList14 = new BooleanArrayList(3);
                    for (integer2 = 0; integer2 < 3; ++integer2) {
                        booleanArrayList14.add(booleanList11.getBoolean(integer2) ^ booleanList12.getBoolean(c3.permutation.permutation(integer2)));
                    }
                    arr[c3.ordinal()][c4.ordinal()] = map2.get(Pair.of(e13, booleanArrayList14));
                }
            }
            return;
        });
        inverseTable = Arrays.<OctahedralGroup>stream(values()).map(c -> Arrays.<OctahedralGroup>stream(values()).filter(c2 -> c.compose(c2) == OctahedralGroup.IDENTITY).findAny().get()).<OctahedralGroup>toArray(OctahedralGroup[]::new);
    }
}
