package com.srbenoit.render;

import com.srbenoit.geom.Vector3;

/**
 * A triangular face that makes up a scene. This class extends <code>Tuple3</code>, where the
 * superclass fields represent the normal vector to the face.
 */
public class WorldFace extends Vector3 {

    /** the index of this face in the scene where it is contained */
    private int indexInScene;

    /** the first vertex in the face */
    private WorldVertex vertex0;

    /** the second vertex in the face */
    private WorldVertex vertex1;

    /** the third vertex in the face */
    private WorldVertex vertex2;

    /**
     * Constructs a new <code>WorldFace</code>.
     *
     * @param  vert0  the first vertex in the face
     * @param  vert1  the second vertex in the face
     * @param  vert2  the third vertex in the face
     */
    public WorldFace(final WorldVertex vert0, final WorldVertex vert1, final WorldVertex vert2) {

        super();

        this.vertex0 = vert0;
        this.vertex1 = vert1;
        this.vertex2 = vert2;

        computeNormal();

        this.indexInScene = -1;
    }

    /**
     * Sets the index of this face in the scene.
     *
     * @param  index  the index
     */
    public void setIndexInScene(final int index) {

        this.indexInScene = index;
    }

    /**
     * Gets the index of this face in the scene.
     *
     * @return  the index
     */
    public int getIndexInScene() {

        return this.indexInScene;
    }

    /**
     * Gets the first vertex in the face.
     *
     * @return  the vertex
     */
    public WorldVertex getVertex0() {

        return this.vertex0;
    }

    /**
     * Gets the second vertex in the face.
     *
     * @return  the vertex
     */
    public WorldVertex getVertex1() {

        return this.vertex1;
    }

    /**
     * Gets the third vertex in the face.
     *
     * @return  the vertex
     */
    public WorldVertex getVertex2() {

        return this.vertex2;
    }

    /**
     * Gets a specified vertex in the face.
     *
     * @param   index  the index of the vertex may be outside the legal range - this value will be
     *                 taken modulo the number of vertices before use)
     * @return  the vertex
     */
    public WorldVertex getVertex(final int index) {

        int actual;
        WorldVertex vert;

        actual = index % 3;

        if (actual < 0) {
            actual += 3;
        }

        switch (actual) {

        case 0:
            vert = this.vertex0;
            break;

        case 1:
            vert = this.vertex1;
            break;

        default:
            vert = this.vertex2;
            break;
        }

        return vert;
    }

    /**
     * Computes the normal vector.
     */
    public final void computeNormal() {

        double dx1;
        double dy1;
        double dz1;
        double dx2;
        double dy2;
        double dz2;
        double crossX;
        double crossY;
        double crossZ;

        dx1 = this.vertex1.getPosX() - this.vertex0.getPosX();
        dy1 = this.vertex1.getPosY() - this.vertex0.getPosY();
        dz1 = this.vertex1.getPosZ() - this.vertex0.getPosZ();

        dx2 = this.vertex2.getPosX() - this.vertex0.getPosX();
        dy2 = this.vertex2.getPosY() - this.vertex0.getPosY();
        dz2 = this.vertex2.getPosZ() - this.vertex0.getPosZ();

        crossX = (dy1 * dz2) - (dz1 * dy2);
        crossY = (dz1 * dx2) - (dx1 * dz2);
        crossZ = (dx1 * dy2) - (dy1 * dx2);

        setVec(crossX, crossY, crossZ);
        normalize();
    }
}
