package org.artisanlogiciel.games.stl;

/**
 * Wall3d to create walls in 3d for stl conversion South, West North East...
 *
 * wall3D will create a rectangular cuboid with 2 triangle vertex for each face
 **/
public class Wall3d {

    // 4 triangles in 2 dim space reused 3 times
    // in facts order matters...
    final static int BASE[][][] = {
            // lower left
            {{0, 0}, {1, 0}, {0, 1}},
            // higher right
            {{1, 0}, {1, 1}, {0, 1}},
            // lower right
            {{0, 0}, {1, 0}, {1, 1}},
            // higher left
            {{0, 0}, {1, 1}, {0, 1}}};

    final static short X = 1;
    final static short Y = 2;
    final static short Z = 4;

    // final static short AXIS[][]= {{X,Y},{-Z,Y},{X,Y},{Z,Y},{X,-Z},{X,-Z}};

    // [face][axis]
    final static short AXIS[][] = {
            // face 0 (x,y) back
            {X, Y, 0},
            // face 1 (z,y) left
            {Z, Y, 0},
            // face 2 (x,y,1)
            {X, Y, 1},
            // face 3
            {Z, Y, 1},
            // face 4
            {X, Z, 0},
            // face 5
            {X, Z, 1}};

    final static String normalx = "1.0 0.0 0.0";
    final static String normaly = "0.0 1.0 0.0";
    final static String normalz = "0.0 0.0 1.0";
    final static String normalmx = "-1.0 0.0 0.0";
    final static String normalmy = "0.0 -1.0 0.0";
    final static String normalmz = "0.0 0.0 -1.0";

    // final static short NORMAL[] = {Z,X,Z,X,Y,Y};

    final static String normalstr[] =
            {   normalmz, normalx,
                    normalz, normalmx,
                    normaly, normalmy
            };

    boolean reverse_vertex[] = {
            true,false,false,true,false,true
    };

    int triangle[][][] = null;

    public Wall3d(int t[][][]) {
        triangle = t;
    }

    public Wall3d(Wall3d origin, int dx, int dy, int dz) {
        triangle = origin.translate(dx, dy, dz);
    }

    Wall3d(int xl, int yl, int zl, int dx, int dy, int dz) {
        int f = 0;
        triangle = new int[12][3][3];
        int[] factor = {xl, yl, zl};
        int[] translate = {dx, dy, dz};
        for (int facet = 0; facet < 12; facet++) {
            // point in a triangle / facet
            for (int p = 0; p < 3; p++) {
                short uaxis = 0;
                // a square face is two facets.
                int face = facet / 2;
                // first two axis ( projected on x,y,z depending on AXIS[face][] )
                for (int axis = 0; axis < 2; axis++) {
                    short caxis = AXIS[face][axis];
                    if (caxis > 0) {
                        f = 1;
                    } else if (caxis < 0) {
                        // wait wait in AXIS there is no negative value ...
                        // so we never enter here, what was the purpose ? might be history.
                        f = -1;
                        caxis = (short) -caxis;
                    }
                    // what if caxis == 0 ? f is kept as its previous value ?
                    // which is 1 in facts due to AXIS[..][0] > 0

                    // uaxis keep track of used axes for this face to find last missing axis
                    uaxis |= caxis;
                    if (caxis == X) {
                        caxis = 0;
                    } else if (caxis == Y) {
                        caxis = 1;
                    } else {
                        caxis = 2;
                    }
                    triangle[facet][p][caxis] = translate[caxis] + BASE[facet % 4][p][axis] * f * factor[caxis];
                }
                // last remaining axis
                if ((uaxis & X) == 0) {
                    // no X was used => X
                    uaxis = 0;
                } else if ((uaxis & Y) == 0) {
                    // X was used byt not Y => Y
                    uaxis = 1;
                } else {
                    // default X, and Y were used => Z
                    uaxis = 2;
                }
                triangle[facet][p][uaxis] = translate[uaxis] + AXIS[facet / 2][2] * factor[uaxis];
            }
        }
    }

    public int[][][] translate(int dx, int dy, int dz) {
        int[] translate = {dx, dy, dz};
        int t[][][] = new int[12][3][3];

        for (int facet = 0; facet < 12; facet ++) {
            // point in a triangle
            for (int p = 0; p < 3; p++) {
                for (int axis = 0; axis < 3; axis++) {
                    t[facet][p][axis] = translate[axis] + triangle[facet][p][axis];
                }
            }
        }
        return t;

    }

    /**
     * write triangles as stl text
     **/
    public String toString() {
        String s = "";
        for (int facet = 0; facet < 12; facet++) {
            int face = facet / 2;
            // most software don't care normal but just rely on vertex order ( right hand ).
            String normal = normalstr[face];
            s += "facet normal " + normal + "\nouter loop\n";
            boolean reverse = reverse_vertex[face];
            for (int p = 0; p < 3; p++) {
                s += "vertex";
                // p that accept right hand
                int rhp = p;
                if ( reverse )
                {
                    // reverse 2 and 1 ; 0 => 0, 1 => 2 , 2 => 1
                    rhp = ( p * 5 ) % 3;
                }
                for (int a = 0; a < 3; a++) {
                    s += " " + triangle[facet][rhp][a];
                }
                s += "\n";
            }
            s = s + "endloop\nendfacet\n";
        }
        return s;
    }

}
