"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var Math_1 = require("../Math/");
var Deformation = tslib_1.__importStar(require("./Deformation"));
var Face = tslib_1.__importStar(require("./Face"));
exports.createLatticeFromMinAndMax = function (deformation, min, max) {
    var lattice = exports.createFromDeformation(deformation);
    lattice.vertices = new Array(8);
    var index = 0;
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(max, max, max);
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(max, max, min);
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(max, min, max);
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(max, min, min);
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(min, max, min);
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(min, max, max);
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(min, min, min);
    lattice.vertices[index++] = Math_1.Vector.CreateVec3(min, min, max);
    lattice.faces = new Array(12);
    index = 0;
    lattice.faces[index++] = Face.create(0, 2, 1);
    lattice.faces[index++] = Face.create(2, 3, 1);
    lattice.faces[index++] = Face.create(4, 6, 5);
    lattice.faces[index++] = Face.create(6, 7, 5);
    lattice.faces[index++] = Face.create(4, 5, 1);
    lattice.faces[index++] = Face.create(5, 0, 1);
    lattice.faces[index++] = Face.create(7, 6, 2);
    lattice.faces[index++] = Face.create(6, 3, 2);
    lattice.faces[index++] = Face.create(5, 7, 0);
    lattice.faces[index++] = Face.create(7, 2, 0);
    lattice.faces[index++] = Face.create(1, 3, 4);
    lattice.faces[index++] = Face.create(3, 6, 4);
    return lattice;
};
exports.createFromDeformation = function (deformation) {
    var e_1, _a;
    var lattice = {
        deformation: deformation,
        dimensionX: deformation.dimensionX,
        dimensionY: deformation.dimensionY,
        dimensionZ: deformation.dimensionZ,
        vertices: undefined,
        faces: undefined,
    };
    switch (deformation.type) {
        case Deformation.LatticeType.XY:
            lattice.dimensionZ = 2;
            break;
        case Deformation.LatticeType.YZ:
            lattice.dimensionX = 2;
            break;
        case Deformation.LatticeType.XZ:
            lattice.dimensionY = 2;
            break;
    }
    // #region Vertices
    var tNV = 2 *
        (lattice.dimensionX * lattice.dimensionZ +
            lattice.dimensionX * lattice.dimensionY +
            lattice.dimensionY * lattice.dimensionZ);
    var tVertices = new Array();
    var tX, tY, tZ;
    // Top/Bottom:
    for (tY = 0; tY < lattice.dimensionY; tY += lattice.dimensionY - 1) {
        for (tX = 0; tX < lattice.dimensionX; tX++) {
            for (tZ = 0; tZ < lattice.dimensionZ; tZ++) {
                tVertices.push(getVertexFromDeformation(deformation, tX, tY, tZ));
            }
        }
    }
    // Front/Back:
    for (tZ = 0; tZ < lattice.dimensionZ; tZ += lattice.dimensionZ - 1) {
        for (tX = 0; tX < lattice.dimensionX; tX++) {
            for (tY = 0; tY < lattice.dimensionY; tY++) {
                tVertices.push(getVertexFromDeformation(lattice.deformation, tX, tY, tZ));
            }
        }
    }
    // Left/Right:
    for (tX = 0; tX < lattice.dimensionX; tX += lattice.dimensionX - 1) {
        for (tY = 0; tY < lattice.dimensionY; tY++) {
            for (tZ = 0; tZ < lattice.dimensionZ; tZ++) {
                tVertices.push(getVertexFromDeformation(lattice.deformation, tX, tY, tZ));
            }
        }
    }
    // to speed-up index access:
    var tVertexArray = tVertices;
    // #endregion
    // #region Faces
    var tNF = 4 *
        ((lattice.dimensionX - 1) * (lattice.dimensionY - 1) +
            (lattice.dimensionX - 1) * (lattice.dimensionZ - 1) +
            (lattice.dimensionY - 1) * (lattice.dimensionZ - 1));
    var tFaces = new Array();
    var tFace;
    var tFaceA;
    var tFaceB;
    var tOffset = 0;
    // Top/Bottom:
    for (var tL = 0; tL < 2; tL++) {
        for (tX = 0; tX < lattice.dimensionX - 1; tX++) {
            for (tZ = 0; tZ < lattice.dimensionZ - 1; tZ++) {
                tFaceA = Face.create();
                tFaceA.a = tOffset + tX * lattice.dimensionZ + tZ;
                tFaceA.b = tOffset + tX * lattice.dimensionZ + tZ + 1;
                tFaceA.c = tOffset + (tX + 1) * lattice.dimensionZ + tZ;
                if (tL === 1) {
                    Face.flip(tFaceA);
                }
                tFaces.push(tFaceA);
                tFaceB = Face.create();
                tFaceB.a = tOffset + tX * lattice.dimensionZ + tZ + 1;
                tFaceB.b = tOffset + (tX + 1) * lattice.dimensionZ + tZ + 1;
                tFaceB.c = tOffset + (tX + 1) * lattice.dimensionZ + tZ;
                if (tL === 1) {
                    Face.flip(tFaceB);
                }
                tFaces.push(tFaceB);
            }
        }
        tOffset += lattice.dimensionX * lattice.dimensionZ;
    }
    // Front/Back:
    for (var tL = 0; tL < 2; tL++) {
        for (tX = 0; tX < lattice.dimensionX - 1; tX++) {
            for (tY = 0; tY < lattice.dimensionY - 1; tY++) {
                tFaceA = Face.create();
                tFaceA.a = tOffset + tX * lattice.dimensionY + tY;
                tFaceA.b = tOffset + tX * lattice.dimensionY + tY + 1;
                tFaceA.c = tOffset + (tX + 1) * lattice.dimensionY + tY;
                if (tL === 0) {
                    Face.flip(tFaceA);
                }
                tFaces.push(tFaceA);
                tFaceB = Face.create();
                tFaceB.a = tOffset + tX * lattice.dimensionY + tY + 1;
                tFaceB.b = tOffset + (tX + 1) * lattice.dimensionY + tY + 1;
                tFaceB.c = tOffset + (tX + 1) * lattice.dimensionY + tY;
                if (tL === 0) {
                    Face.flip(tFaceB);
                }
                tFaces.push(tFaceB);
            }
        }
        tOffset += lattice.dimensionX * lattice.dimensionY;
    }
    // Left/Right:
    for (var tL = 0; tL < 2; tL++) {
        for (tY = 0; tY < lattice.dimensionY - 1; tY++) {
            for (tZ = 0; tZ < lattice.dimensionZ - 1; tZ++) {
                tFaceA = Face.create();
                tFaceA.a = tOffset + tY * lattice.dimensionZ + tZ;
                tFaceA.b = tOffset + tY * lattice.dimensionZ + tZ + 1;
                tFaceA.c = tOffset + (tY + 1) * lattice.dimensionZ + tZ;
                if (tL === 0) {
                    Face.flip(tFaceA);
                }
                tFaces.push(tFaceA);
                tFaceB = Face.create();
                tFaceB.a = tOffset + tY * lattice.dimensionZ + tZ + 1;
                tFaceB.b = tOffset + (tY + 1) * lattice.dimensionZ + tZ + 1;
                tFaceB.c = tOffset + (tY + 1) * lattice.dimensionZ + tZ;
                if (tL === 0) {
                    Face.flip(tFaceB);
                }
                tFaces.push(tFaceB);
            }
        }
        tOffset += lattice.dimensionY * lattice.dimensionZ;
    }
    // #endregion
    // #region Optimization
    lattice.vertices = new Array(lattice.dimensionX * lattice.dimensionY * lattice.dimensionZ);
    exports.updateVertices(lattice, lattice.deformation);
    var tVertexMapping = new Map();
    for (var tI = 0; tI < tVertexArray.length; tI++) {
        var tVertex = tVertexArray[tI];
        var tJ = 0;
        try {
            for (var _b = (e_1 = void 0, tslib_1.__values(lattice.vertices)), _c = _b.next(); !_c.done; _c = _b.next()) {
                var tUVertex = _c.value;
                if (Math_1.Vector.IsEqual3(tVertex, tUVertex)) {
                    tVertexMapping.set(tI, tJ);
                    break;
                }
                tJ++;
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
            }
            finally { if (e_1) throw e_1.error; }
        }
    }
    lattice.faces = tFaces;
    for (var tF = 0; tF < lattice.faces.length; tF++) {
        tFace = lattice.faces[tF];
        if (tVertexMapping.has(tFace.a)) {
            tFace.a = tVertexMapping.get(tFace.a);
        }
        if (tVertexMapping.has(tFace.b)) {
            tFace.b = tVertexMapping.get(tFace.b);
        }
        if (tVertexMapping.has(tFace.c)) {
            tFace.c = tVertexMapping.get(tFace.c);
        }
        lattice.faces[tF] = tFace;
    }
    return lattice;
};
exports.getVerticeCount = function (lattice) {
    return lattice.vertices.length;
};
exports.getFaceCount = function (lattice) { return lattice.faces.length; };
var getVertexFromDeformation = function (deformation, x, y, z) {
    var vertex;
    // The deformation object has valid maximum and minimum numbers, except for lattice type xyz
    switch (deformation.type) {
        case Deformation.LatticeType.XY:
            vertex = Deformation.getVertexAtTime0(deformation, x, y, 0);
            vertex.z = z === 0 ? deformation.maximum : deformation.minimum;
            return vertex;
        case Deformation.LatticeType.YZ:
            vertex = Deformation.getVertexAtTime0(deformation, 0, y, z);
            vertex.x = x === 0 ? deformation.minimum : deformation.maximum;
            return vertex;
        case Deformation.LatticeType.XZ:
            vertex = Deformation.getVertexAtTime0(deformation, x, 0, z);
            vertex.y = y === 0 ? deformation.maximum : deformation.minimum;
            return vertex;
    }
    return Deformation.getVertexAtTime0(deformation, x, y, z);
};
exports.setDeformationTime = function (lattice, pTime) {
    if (pTime < 0 || pTime > 1) {
        console.log("Controller.setDeformationTime: time must be in [0...1]");
        return;
    }
    if (lattice.deformation.times != null) {
        var defo = Deformation.createAtTime(lattice.deformation, pTime);
        exports.updateVertices(lattice, defo);
    }
};
exports.updateVertices = function (lattice, deformation) {
    var tI = 0;
    for (var tZ = 0; tZ < lattice.dimensionZ; tZ++) {
        for (var tY = 0; tY < lattice.dimensionY; tY++) {
            for (var tX = 0; tX < lattice.dimensionX; tX++) {
                lattice.vertices[tI++] = getVertexFromDeformation(deformation, tX, tY, tZ);
            }
        }
    }
};
exports.translateDeformation = function (lattice, x, y, z) {
    Deformation.translate(lattice.deformation, x, y, z);
    exports.updateVertices(lattice, lattice.deformation);
};
exports.getBoundingBox = function (lattice) {
    var e_2, _a;
    var tMinimum = Math_1.Vector.CreateVec3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
    var tMaximum = Math_1.Vector.CreateVec3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
    try {
        for (var _b = tslib_1.__values(lattice.vertices), _c = _b.next(); !_c.done; _c = _b.next()) {
            var vertex = _c.value;
            if (vertex.x < tMinimum.x)
                tMinimum.x = vertex.x;
            if (vertex.y < tMinimum.y)
                tMinimum.y = vertex.y;
            if (vertex.z < tMinimum.z)
                tMinimum.z = vertex.z;
            if (vertex.x > tMaximum.x)
                tMaximum.x = vertex.x;
            if (vertex.y > tMaximum.y)
                tMaximum.y = vertex.y;
            if (vertex.z > tMaximum.z)
                tMaximum.z = vertex.z;
        }
    }
    catch (e_2_1) { e_2 = { error: e_2_1 }; }
    finally {
        try {
            if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
        }
        finally { if (e_2) throw e_2.error; }
    }
    var result = Math_1.createBounds(tMinimum, tMaximum);
    return result;
};
exports.getVertex = function (lattice, index) {
    return lattice.vertices[index];
};
exports.setVertex = function (lattice, index, x, y, z) {
    var vert = lattice.vertices[index];
    vert.x = x;
    vert.y = y;
    vert.z = z;
};
exports.getFace = function (lattice, index) {
    return lattice.faces[index];
};
