"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var THREE = require("@intelligentgraphics/three");
var igd_productdata_1 = require("@intelligentgraphics/igd.productdata");
var ig_gfx_threejs_1 = require("@intelligentgraphics/ig.gfx.threejs");
var Core = require("@intelligentgraphics/ig.gfx.core");
var three_1 = require("@intelligentgraphics/three");
var ZERO_VECTOR = {
    x: 0,
    y: 0,
    z: 0,
};
var DEFAULT_OPTIONS = {
    lineColor: "black",
    textColor: "black",
    textBoxBackground: "rgb(239, 239, 239)",
    textBoxBorder: "rgb(225, 225, 225)",
    unit: igd_productdata_1.IGXE.EPropertyValueUnit.LENGTH_MM,
    createLabelText: function (value, unit) {
        var unitString = igd_productdata_1.IGXE.Units.getDefaultUnitString(unit);
        return value + " " + unitString;
    },
};
/**
 * Draws are wireframe around each target and
 * renders all provided dimensions as labels on each axis.
 *
 * @export
 * @class LabeledAxis
 * @implements {IMeasurementRenderer}
 */
var LabeledAxis = /** @class */ (function () {
    function LabeledAxis(options, api, dimensionsProvider, camera, letterGeometryCache) {
        this.api = api;
        this.dimensionsProvider = dimensionsProvider;
        this.camera = camera;
        this.objectLabels = new Map();
        this.options = tslib_1.__assign(tslib_1.__assign({}, DEFAULT_OPTIONS), options);
        this.renderScene = ig_gfx_threejs_1.SceneRenderer.createSceneRenderer(letterGeometryCache);
        this.textObjectDefaults = {
            type: "text",
            align: "center",
            color: this.options.textColor,
            size: 0.0295,
            font: "",
            background: {
                color: this.options.textBoxBackground,
                padding: 0.015,
                border: {
                    width: 0.003,
                    color: this.options.textBoxBorder,
                },
            },
        };
    }
    /**
     * Updates the internal camera and the orientation of the labels towards the new camera's position
     *
     * @param {THREE.Camera} camera
     */
    LabeledAxis.prototype.setCamera = function (camera) {
        if (camera === this.camera) {
            return;
        }
        this.camera = camera;
        this.updateLabelLookat();
    };
    /**
     * Updates the orientation of the labels towards the camera's position
     *
     */
    LabeledAxis.prototype.updateLabelLookat = function () {
        var e_1, _a;
        try {
            for (var _b = tslib_1.__values(this
                .objectLabels), _c = _b.next(); !_c.done; _c = _b.next()) {
                var _d = tslib_1.__read(_c.value, 2), _e = _d[1], labels = _e.labels, articles = _e.articles, labelContainer = _e.labelContainer, size = _e.size;
                var _f = this.calculateLabelPositions(size, labelContainer), x = _f.x, y = _f.y, z = _f.z;
                for (var index = 0; index < 3; index++) {
                    var labelContainer_1 = labels[index];
                    if (!labelContainer_1.children[0]) {
                        continue;
                    }
                    var position = void 0;
                    switch (index) {
                        case 0:
                            position = x;
                            break;
                        case 1:
                            position = y;
                            break;
                        case 2:
                            position = z;
                            break;
                    }
                    labelContainer_1.position.set(position.x, position.y, position.z);
                    if (this.camera instanceof three_1.OrthographicCamera) {
                        var lookAt = ig_gfx_threejs_1.ThreeVector3FromVec3(position);
                        lookAt.setY(this.camera.position.y);
                        labelContainer_1.children[0].lookAt(lookAt);
                    }
                    else {
                        labelContainer_1.children[0].lookAt(this.camera.position);
                    }
                }
            }
        }
        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; }
        }
    };
    LabeledAxis.prototype.renderMeasurement = function (targets) {
        var e_2, _a;
        this.objectLabels.clear();
        try {
            for (var targets_1 = tslib_1.__values(targets), targets_1_1 = targets_1.next(); !targets_1_1.done; targets_1_1 = targets_1.next()) {
                var target = targets_1_1.value;
                if ("articles" in target) {
                    this.renderGroupMeasurement(target.parent, target.articles, target.bounds);
                }
                else {
                    this.renderArticleMeasurement(target.parent, target.article, target.bounds);
                }
            }
        }
        catch (e_2_1) { e_2 = { error: e_2_1 }; }
        finally {
            try {
                if (targets_1_1 && !targets_1_1.done && (_a = targets_1.return)) _a.call(targets_1);
            }
            finally { if (e_2) throw e_2.error; }
        }
        this.updateLabelLookat();
    };
    LabeledAxis.prototype.renderGroupMeasurement = function (parent, articles, bounds) {
        var size = Core.Vector.Sub3(bounds.max, bounds.min);
        var positions = this.calculateLabelPositions(size, parent);
        var objects = [];
        objects.push({
            type: "wirebox",
            bounds: {
                min: ZERO_VECTOR,
                max: size,
            },
            color: this.options.lineColor,
        });
        var _a = this.dimensionsProvider.getGroupDimensions(articles), width = _a.width, height = _a.height, depth = _a.depth;
        var labelContainer = {
            type: "group",
            children: [],
        };
        objects.push(labelContainer);
        var x = {
            type: "group",
            children: [],
            position: positions.x,
        };
        var y = {
            type: "group",
            children: [],
            position: positions.y,
        };
        var z = {
            type: "group",
            children: [],
            position: positions.z,
        };
        labelContainer.children.push(x, y, z);
        if (width !== undefined) {
            x.children.push({
                type: "group",
                children: [
                    tslib_1.__assign(tslib_1.__assign({}, this.textObjectDefaults), { text: this.createLabelText(width), position: ZERO_VECTOR }),
                ],
            });
        }
        if (height !== undefined) {
            y.children.push({
                type: "group",
                children: [
                    tslib_1.__assign(tslib_1.__assign({}, this.textObjectDefaults), { text: this.createLabelText(height), position: ZERO_VECTOR }),
                ],
            });
        }
        if (depth !== undefined) {
            z.children.push({
                type: "group",
                children: [
                    tslib_1.__assign(tslib_1.__assign({}, this.textObjectDefaults), { text: this.createLabelText(depth), position: ZERO_VECTOR }),
                ],
            });
        }
        var _b = tslib_1.__read(this.renderScene(parent, objects), 2), labelContainerObject = _b[1];
        this.objectLabels.set(parent, {
            articles: articles,
            labels: labelContainerObject.children,
            labelContainer: labelContainerObject,
            size: size,
        });
    };
    LabeledAxis.prototype.renderArticleMeasurement = function (parent, article, bounds) {
        var localBounds = this.api.GetBounds(article.gfxId, "Local");
        var size = Core.Vector.Sub3(localBounds.max, localBounds.min);
        var positions = this.calculateLabelPositions(size, parent);
        var objects = [];
        objects.push({
            type: "wirebox",
            bounds: {
                min: ZERO_VECTOR,
                max: size,
            },
            color: this.options.lineColor,
        });
        var _a = this.dimensionsProvider.getArticleDimensions(article), width = _a.width, height = _a.height, depth = _a.depth;
        var labelContainer = {
            type: "group",
            children: [],
        };
        objects.push(labelContainer);
        var x = {
            type: "group",
            children: [],
            position: positions.x,
        };
        var y = {
            type: "group",
            children: [],
            position: positions.y,
        };
        var z = {
            type: "group",
            children: [],
            position: positions.z,
        };
        labelContainer.children.push(x, y, z);
        if (width !== undefined) {
            x.children.push({
                type: "group",
                children: [
                    tslib_1.__assign(tslib_1.__assign({}, this.textObjectDefaults), { text: this.createLabelText(width), position: ZERO_VECTOR }),
                ],
            });
        }
        if (height !== undefined) {
            y.children.push({
                type: "group",
                children: [
                    tslib_1.__assign(tslib_1.__assign({}, this.textObjectDefaults), { text: this.createLabelText(height), position: ZERO_VECTOR }),
                ],
            });
        }
        if (depth !== undefined) {
            z.children.push({
                type: "group",
                children: [
                    tslib_1.__assign(tslib_1.__assign({}, this.textObjectDefaults), { text: this.createLabelText(depth), position: ZERO_VECTOR }),
                ],
            });
        }
        var _b = tslib_1.__read(this.renderScene(parent, objects), 2), labelContainerObject = _b[1];
        this.objectLabels.set(parent, {
            articles: [article],
            labels: labelContainerObject.children,
            labelContainer: labelContainerObject,
            size: size,
        });
    };
    LabeledAxis.prototype.calculateLabelPositions = function (size, parent) {
        var e_3, _a;
        var rotationYRad = Core.MathUtils.degToRad(0);
        var points = [
            [tslib_1.__assign({}, ZERO_VECTOR), 0, 0],
            [
                Core.LinearAlgebra.AdaptToRotation(rotationYRad, tslib_1.__assign(tslib_1.__assign({}, ZERO_VECTOR), { x: size.x }), ZERO_VECTOR),
                180,
                0,
            ],
            [
                Core.LinearAlgebra.AdaptToRotation(rotationYRad, tslib_1.__assign(tslib_1.__assign({}, ZERO_VECTOR), { x: size.x, z: size.z }), ZERO_VECTOR),
                180,
                180,
            ],
            [
                Core.LinearAlgebra.AdaptToRotation(rotationYRad, tslib_1.__assign(tslib_1.__assign({}, ZERO_VECTOR), { z: size.z }), ZERO_VECTOR),
                0,
                180,
            ],
        ];
        var smallestDistance;
        var closestPoint;
        try {
            for (var points_1 = tslib_1.__values(points), points_1_1 = points_1.next(); !points_1_1.done; points_1_1 = points_1.next()) {
                var entry = points_1_1.value;
                var relativePosition = new THREE.Vector3(entry[0].x, entry[0].y, entry[0].z);
                var distance = parent
                    .localToWorld(relativePosition)
                    .distanceTo(this.camera.position);
                if (smallestDistance === undefined || distance < smallestDistance) {
                    closestPoint = entry;
                    smallestDistance = distance;
                }
            }
        }
        catch (e_3_1) { e_3 = { error: e_3_1 }; }
        finally {
            try {
                if (points_1_1 && !points_1_1.done && (_a = points_1.return)) _a.call(points_1);
            }
            finally { if (e_3) throw e_3.error; }
        }
        var _b = tslib_1.__read(closestPoint, 3), displayRoot = _b[0], displayRootXRotation = _b[1], displayRootZRotation = _b[2];
        displayRoot.y = size.y;
        var posX = {
            x: size.x / 2,
            y: 0,
            z: 0,
        };
        posX = Core.LinearAlgebra.AdaptToRotation(Core.MathUtils.degToRad(0 + displayRootXRotation), posX, ZERO_VECTOR);
        posX = Core.Vector.Add3(posX, displayRoot);
        posX.y += 0.1;
        var posY = {
            x: displayRoot.x,
            y: size.y / 2,
            z: displayRoot.z,
        };
        var posZ = {
            x: 0,
            y: 0,
            z: size.z / 2,
        };
        posZ = Core.LinearAlgebra.AdaptToRotation(Core.MathUtils.degToRad(0 + displayRootZRotation), posZ, ZERO_VECTOR);
        posZ = Core.Vector.Add3(posZ, displayRoot);
        posZ.y += 0.1;
        return {
            x: posX,
            y: posY,
            z: posZ,
        };
    };
    LabeledAxis.prototype.createLabelText = function (value) {
        var convertedValue = igd_productdata_1.IGXE.Units.convert(value, igd_productdata_1.IGXE.EPropertyValueUnit.LENGTH_M, this.options.unit);
        return this.options.createLabelText(convertedValue, this.options.unit);
    };
    return LabeledAxis;
}());
exports.LabeledAxis = LabeledAxis;
