/*
 * Copyright (C) 2012 Darth Affe <http://wyrez.org> and contributors
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.wyrez.shootingstars.mesh;

import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;

/**
 *
 * @author Darth Affe
 */
public class HexPrism extends Mesh {
    /*    The vertices are located as following
     * 
     *              10____________9
     *               /|          |\
     *              / |          | \
     *             / 3|__________|2 \
     *          11/  /            \  \ 8
     *           |\ /       7      \ /|
     *           | \                / |
     *           |/ \       0      / \|
     *         4 \   \____________/13 / 1
     *            \  |12          |  /
     *             \ |            | /
     *              \|____________|/
     *              5              6
     * 
     */
//TODO remove bottom for better performance
    private static final short[] GEOMETRY_INDICES_DATA = {
        0, 1, 2,/**/ 2, 3, 0,/**/ 0, 3, 4,/**/ 4, 5, 0,/**/ 0, 5, 6,/**/ 6, 1, 0, // bottom
        //0, 1, 6,/**/ 6, 5, 0,/**/ 0, 5, 4,/**/ 4, 3, 0,/**/ 0, 3, 2,/**/ 2, 1, 0, // reverse bottom
        7, 8, 13,/**/ 13, 12, 7,/**/ 7, 12, 11,/**/ 11, 10, 7,/**/ 7, 10, 9,/**/ 9, 8, 7, // top
        //7, 8, 9,/**/ 9, 10, 7,/**/ 7, 10, 11,/**/ 11, 12, 7,/**/ 7, 12, 13,/**/ 13, 8, 7, // reverse top
        1, 8, 9,/**/ 9, 2, 1,/**/ 2, 9, 10,/**/ 10, 3, 2,/**/ 3, 10, 11,/**/ 11, 4, 3, //side
        4, 11, 12,/**/ 12, 5, 4,/**/ 5, 12, 13,/**/ 13, 6, 5,/**/ 6, 13, 8,/**/ 8, 1, 6 //side
    };
    private static final float[] GEOMETRY_NORMALS_DATA = {
        0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0, //bottom
        0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0,/**/ 0, 1, 0 //top
    };
    //TODO to texture sides more vertices are needed
    private static final float[] GEOMETRY_TEXTURE_DATA = {
        0.5f, 0.5f, 0, 0.5f, 0.25f, 0, 0.75f, 0, 1, 0.5f, 0.75f, 1, 0.25f, 1,//bottom
        0.5f, 0.5f, 0, 0.5f, 0.25f, 0, 0.75f, 0, 1, 0.5f, 0.75f, 1, 0.25f, 1 //top
    };
    private Vector3f center;
    private float radius;
    private float height;

    public HexPrism(float radius, float height) {
        this(Vector3f.ZERO, radius, height);
    }

    public HexPrism(Vector3f center, float radius, float height) {
        super();
        updateGeometry(center, radius, height);
    }

    /**
     * Empty constructor for serialization only. Do not use!
     */
    public HexPrism() {
        super();
    }

    @Override
    public HexPrism clone() {
        return new HexPrism(center.clone(), radius, height);
    }

    protected final void updateGeometry(Vector3f center, float radius, float height) {
        this.center = center;
        this.radius = radius;
        this.height = height;
        updateGeometryIndices();
        updateGeometryNormals();
        updateGeometryTextures();
        updateGeometryVertices();
    }

    protected void updateGeometryIndices() {
        if (getBuffer(Type.Index) == null) {
            setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA));
        }
    }

    protected void updateGeometryNormals() {
        if (getBuffer(Type.Normal) == null) {
            setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(GEOMETRY_NORMALS_DATA));
        }
    }

    protected void updateGeometryTextures() {
        if (getBuffer(Type.TexCoord) == null) {
            setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(GEOMETRY_TEXTURE_DATA));
        }
    }

    protected void updateGeometryVertices() {
        Vector3f[] vertices = computeVertices();
        setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
        updateBound();
    }

    protected Vector3f[] computeVertices() {
        Vector3f[] vertices = new Vector3f[14];
        //bottom
        vertices[0] = center;
        for (int i = 0; i < 6; i++) {
            vertices[i + 1] = new Vector3f(vertices[0].x + radius * FastMath.cos(i * FastMath.PI / 3),
                    vertices[0].y, (vertices[0].z + radius * FastMath.sin(i * FastMath.PI / 3)));
        }
        //top
        vertices[7] = center.add(0f, height, 0f);
        for (int i = 0; i < 6; i++) {
            vertices[i + 8] = new Vector3f(vertices[7].x + radius * FastMath.cos(i * FastMath.PI / 3),
                    vertices[7].y, (vertices[7].z + radius * FastMath.sin(i * FastMath.PI / 3)));
        }
        return vertices;
    }
}
