define(["require", "exports", "tslib", "react", "d3-hierarchy", "@fluentui/react/lib/Utilities", "d3-selection", "@fluentui/react-focus", "d3-array"], function (require, exports, tslib_1, React, d3_hierarchy_1, Utilities_1, d3_selection_1, react_focus_1, d3_array_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.TreeChartBase = void 0;
    var getClassNames = (0, Utilities_1.classNamesFunction)();
    // Create a parent class for common tree components
    var StandardTree = /** @class */ (function () {
        function StandardTree(treeData, styleClassNames, _nodeElements, _linkElements) {
            if (_nodeElements === void 0) { _nodeElements = []; }
            if (_linkElements === void 0) { _linkElements = []; }
            this._nodeElements = [];
            this._linkElements = [];
            this.treeData = treeData;
            this.styleClassNames = styleClassNames;
            this._nodeElements = _nodeElements;
            this._linkElements = _linkElements;
        }
        StandardTree.prototype.truncateText = function (text, rectangleWidth, padding, styleClass) {
            var truncatedText = '';
            var words = text.split(/\s+/).reverse();
            var word = '';
            var tspan = (0, d3_selection_1.select)('.svgTree').append('text').attr('class', 'tempText').append('tspan').text(null);
            if (styleClass) {
                tspan.attr('class', styleClass);
            }
            var line = [];
            while ((word = words.pop())) {
                line.push(word);
                tspan.text(line.join(' ') + ' ');
                if (tspan.node() !== null) {
                    var w = tspan.node().getComputedTextLength();
                    if (w > rectangleWidth - padding) {
                        line.pop();
                        line.push('...');
                        break;
                    }
                }
            }
            truncatedText = line.join(' ') + ' ';
            tspan.text(null);
            (0, d3_selection_1.selectAll)('.tempText').remove();
            return truncatedText;
        };
        // Append node elements
        // nodeId to create unique key
        StandardTree.prototype.addNodeShapetoSVG = function (name, subname, bodytext, metricName, xCenterCoordinate, yCoordinate, fillColor, rectangleWidth, rectangleHeight, nodeId, parentInfo) {
            var ariaLabel = "nodeId: ".concat(nodeId, " \nnodeMainText: ").concat(name, "\nsubText ").concat(subname, " ").concat(parentInfo);
            var xCoordinate = xCenterCoordinate - rectangleWidth / 2;
            if (metricName || nodeId !== 0 || !bodytext) {
                this._nodeElements.push(React.createElement("rect", { width: rectangleWidth, height: rectangleHeight, x: xCoordinate, y: yCoordinate, tabIndex: 0, role: 'text', "data-is-focusable": true, "aria-label": ariaLabel, className: this.styleClassNames.rectNode, stroke: fillColor, key: "".concat(nodeId).concat(this.styleClassNames.rectNode) }));
            }
            if (subname) {
                subname = this.truncateText(subname, rectangleWidth, rectangleWidth / 4, this.styleClassNames.rectSubText);
            }
            if (bodytext) {
                bodytext = this.truncateText(bodytext, rectangleWidth, rectangleWidth / 4, this.styleClassNames.rectBodyText);
            }
            if (metricName) {
                metricName = this.truncateText(metricName, rectangleWidth, rectangleWidth / 4, this.styleClassNames.rectMetricText);
            }
            name = this.truncateText(name, rectangleWidth, rectangleWidth / 4, this.styleClassNames.rectText);
            // Text position y = y + rectHeight/2, 2 is ratio for depth
            // Text position x = x + rectWidth/2, 2 is ratio for length
            // Sub-text position x = x + rectWidth/2, 2 is ratio for length
            var subValue = metricName ? (React.createElement("tspan", { className: this.styleClassNames.rectMetricText, dy: "1.4em", x: xCoordinate + rectangleWidth / 2 }, metricName)) : bodytext ? (React.createElement(React.Fragment, null,
                React.createElement("tspan", { className: this.styleClassNames.rectSubText, dy: "1.4em", x: xCoordinate + rectangleWidth / 2 }, subname),
                React.createElement("tspan", { className: this.styleClassNames.rectBodyText, dy: "1.4em", x: xCoordinate + rectangleWidth / 2 }, bodytext))) : (React.createElement("tspan", { className: this.styleClassNames.rectSubText, dy: "1.4em", x: xCoordinate + rectangleWidth / 2 }, subname));
            if (!subname && !metricName && !bodytext) {
                this._nodeElements.push(React.createElement("text", { textAnchor: "middle", className: this.styleClassNames.rectMetricText, dy: yCoordinate + rectangleHeight / 1.6, x: xCoordinate + rectangleWidth / 2, key: "".concat(nodeId).concat(this.styleClassNames.rectText), "data-is-focusable": nodeId === 0 }, name));
            }
            else {
                this._nodeElements.push(React.createElement("text", { textAnchor: "middle", className: metricName ? this.styleClassNames.rectSubText : this.styleClassNames.rectText, dy: metricName ? yCoordinate + rectangleHeight / 2.5 : yCoordinate + rectangleHeight / 2, x: xCoordinate + rectangleWidth / 2, key: "".concat(nodeId).concat(this.styleClassNames.rectText), "data-is-focusable": nodeId === 0 },
                    name,
                    subValue));
            }
        };
        // Create a rectangular path from parent to the child nodes
        StandardTree.prototype.createPathLink = function (parentX, parentY, childX, childY, leaf, rectWidth, rectHeight, gap, childXMax) {
            // gap adds ratio for parent.y to child.y
            /*Below code is used to draw lines(___|) to show the parent child relation i.e a vertical line
              emerging from the parent and
              then a horzontal line encompassing all the its children which are
              shown below it .so it gives a visual representation of tree branches.
        
              So for making this path firstly we are moving to the childX which is the mid point of the node and then
              we are subtracting the half of rectwidth to move the complete width of the rectangle and
              we are subtracting gap from y cordinate as we are making this line at a little gap from node.
              Then we are building that line horizonatlly till childXmax, again adding half rectwidth to complete
              the line till end as childXmax will be midpoint.
              Then last part is for making line vertical for that we move to the parentx position and
              then draw the vertical till parenty + rectHeight + gap/2
              We have seperate path for leaf node as we are using different composition like compact, long etc.*/
            var path = "M".concat(childX - rectWidth / 2, ",").concat(childY - gap, " H").concat(childXMax + rectWidth / 2, " M").concat(parentX, ",").concat(childY - gap, "\n    V").concat(parentY + rectHeight + gap / 2);
            var leafpath = "M".concat(parentX, ",").concat(parentY + rectHeight + gap / 2, " V").concat(parentY + gap * 5, "\n    H").concat(parentX - rectWidth / 2, " H").concat(parentX + rectWidth / 2);
            // based on the type of node return leafpath or path element
            return leaf ? leafpath : path;
        };
        // Append path link element
        StandardTree.prototype.addLinktoSVG = function (nodeId, parentX, parentY, childX, childY, leaf, rectWidth, rectHeight, gap, childXMax) {
            if (childXMax === void 0) { childXMax = 0; }
            this._linkElements.push(React.createElement("path", { className: this.styleClassNames.link, d: this.createPathLink(parentX, parentY, childX, childY, leaf, rectWidth, rectHeight, gap, childXMax), key: "".concat(nodeId).concat(this.styleClassNames.link) }));
        };
        return StandardTree;
    }());
    // Create child class to Add Tree component based on treeHeight
    var LayeredTree = /** @class */ (function (_super) {
        tslib_1.__extends(LayeredTree, _super);
        function LayeredTree(treeData, composition, styleClassNames, _nodeElements, _linkElements, _treeTraversal) {
            if (_nodeElements === void 0) { _nodeElements = []; }
            if (_linkElements === void 0) { _linkElements = []; }
            var _this = _super.call(this, treeData, styleClassNames, _nodeElements, _linkElements) || this;
            _this.composition = composition;
            _this._treeTraversal = _treeTraversal;
            return _this;
        }
        LayeredTree.prototype.createTree = function (givenLayoutWidth, screenWidth) {
            var _a, _b, _c, _d, _e, _f;
            givenLayoutWidth = givenLayoutWidth < 65 ? 65 : givenLayoutWidth > 90 ? 90 : givenLayoutWidth;
            var layoutWidth = givenLayoutWidth || 75;
            var root = (0, d3_hierarchy_1.hierarchy)(this.treeData, function (d) {
                return d.children;
            });
            // Find tree Height
            var treeHeight = (root === null || root === void 0 ? void 0 : root.height) + 1;
            // Create tree layout, width: layoutWidth, height: layoutWidth/1.5 and add node separation
            var treeChart = (0, d3_hierarchy_1.tree)()
                .nodeSize([layoutWidth, layoutWidth / 1.5])
                .separation(function (a, b) {
                return a.parent === root && b.parent === root ? 3.5 : 1;
            });
            // Assigns the x and y position for the nodes
            var treeData = treeChart(root);
            // Compute the new tree layout.
            var nodes = treeData.descendants();
            // Normalize for fixed-depth and width
            // Normalise y coordinate by depth of each node by a factor of 130
            // Normalise x coordinate by start coordinate 0 with screenSize/3
            nodes.forEach(function (d) {
                d.y = d.depth === 0 ? 10 : d.depth * 130;
                d.x += screenWidth / 2;
            });
            // <------------------ Traversal section ------------------>
            // Create tree data structure
            var treeDataStructure = [];
            var TreeID = 0;
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            var createTreeDataStructure = function (d) {
                var _a, _b;
                d.id = TreeID;
                treeDataStructure.push({
                    id: TreeID,
                    children: d.children,
                    dataName: d.data.name,
                    subName: d.data.subname,
                    bodyText: d.data.bodytext,
                    metricName: (_a = d.data) === null || _a === void 0 ? void 0 : _a.metric,
                    fill: d.data.fill,
                    x: d.x,
                    y: d.y,
                    parentID: (_b = d.parent) === null || _b === void 0 ? void 0 : _b.id,
                });
                TreeID++;
            };
            this._treeTraversal === 0
                ? root.each(function (d) {
                    createTreeDataStructure(d);
                })
                : root.eachBefore(function (d) {
                    createTreeDataStructure(d);
                });
            var rectWidth = layoutWidth * 3;
            var rectHeight = rectWidth / 3.45;
            var gap = 20;
            var parentSet = new Set();
            for (var _i = 0, treeDataStructure_1 = treeDataStructure; _i < treeDataStructure_1.length; _i++) {
                var d = treeDataStructure_1[_i];
                var parentInfo = d.id === 0
                    ? 'Root Node'
                    : "Parent info parentId: ".concat(d.parentID, "\n      ").concat(treeDataStructure[d.parentID].dataName, "\n      ").concat(treeDataStructure[d.parentID].subName);
                // check for leaf nodes
                if (!d.children && !parentSet.has(d.parentID) && treeHeight === 3) {
                    var compactNodeWidth = (rectWidth - gap) / 2;
                    var compactNodeHeight = rectHeight;
                    parentSet.add(d.parentID);
                    // <------------------ Links section ------------------>
                    this.addLinktoSVG(d.id, treeDataStructure[d.parentID].x, treeDataStructure[d.parentID].y, treeDataStructure[d.id].x, treeDataStructure[d.id].y, true, rectWidth, rectHeight, gap);
                    // <------------------ Nodes section ------------------>
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    var children = (_a = treeDataStructure[d.parentID]) === null || _a === void 0 ? void 0 : _a.children;
                    var compactNodeCenterX1 = ((_b = treeDataStructure[d.parentID]) === null || _b === void 0 ? void 0 : _b.x) - compactNodeWidth / 2 - gap / 2;
                    var compactNodeCenterX2 = ((_c = treeDataStructure[d.parentID]) === null || _c === void 0 ? void 0 : _c.x) + compactNodeWidth / 2 + gap / 2;
                    var longNodeCenterX = (_d = treeDataStructure[d.parentID]) === null || _d === void 0 ? void 0 : _d.x;
                    var dy = (_e = children[0]) === null || _e === void 0 ? void 0 : _e.y;
                    for (var itr = 0; itr < children.length; ++itr) {
                        var child = children[itr];
                        // Given Composition
                        if (this.composition !== undefined) {
                            // For compact compostion
                            if (this.composition === 0) {
                                this.addNodeShapetoSVG(child.data.name, child.data.subname, child.data.bodytext, child.data.metricName, 
                                // If the leaf node count is 1 ,
                                //irrespective of provided composition we should always use long composition
                                itr % 2 === 0 ? (children.length === 1 ? longNodeCenterX : compactNodeCenterX1) : compactNodeCenterX2, dy, child.data.fill, children.length === 1 ? rectWidth : compactNodeWidth, rectHeight, child.id, parentInfo);
                                if (itr % 2 === 1) {
                                    dy += compactNodeHeight + gap;
                                }
                            }
                            // For long compostion
                            else {
                                this.addNodeShapetoSVG(child.data.name, child.data.subname, child.data.bodytext, child.data.metricName, longNodeCenterX, dy, child.data.fill, rectWidth, rectHeight, child.id, parentInfo);
                                dy += compactNodeHeight + gap;
                            }
                        }
                        // Automatic Node Composition
                        else {
                            if (children.length > 2) {
                                this.addNodeShapetoSVG(child.data.name, child.data.subname, child.data.bodytext, child.data.metricName, itr % 2 === 0 ? compactNodeCenterX1 : compactNodeCenterX2, dy, child.data.fill, children.length === 1 ? rectWidth : compactNodeWidth, rectHeight, child.id, parentInfo);
                                if (itr % 2 === 1) {
                                    dy += compactNodeHeight + gap;
                                }
                            }
                            else {
                                this.addNodeShapetoSVG(child.data.name, child.data.subname, child.data.bodytext, child.data.metricName, longNodeCenterX, dy, child.data.fill, rectWidth, rectHeight, child.id, parentInfo);
                                dy += compactNodeHeight + gap;
                            }
                        }
                    }
                }
                if (d.children || treeHeight <= 2) {
                    // <------------------ Nodes section ------------------>
                    // Since the height <=2 we will be using long compositon.
                    this.addNodeShapetoSVG(d.dataName, d.subName, d.bodyText, d.metricName, d.x, d.y, d.fill, rectWidth, rectHeight, d.id, parentInfo);
                    // <------------------ Links section ------------------>
                    if (d.id === 0 && d.children) {
                        // eslint-disable-next-line @typescript-eslint/no-explicit-any
                        var children = (_f = treeDataStructure[d.id]) === null || _f === void 0 ? void 0 : _f.children;
                        var childXMin = (0, d3_array_1.min)(children, function (child) { return child.x; });
                        var childXMax = (0, d3_array_1.max)(children, function (child) { return child.x; });
                        this.addLinktoSVG(d.id, d.x, d.y, childXMin, d.children[0].y, false, rectWidth, rectHeight, gap, childXMax);
                    }
                }
            }
        };
        return LayeredTree;
    }(StandardTree));
    var TreeChartBase = /** @class */ (function (_super) {
        tslib_1.__extends(TreeChartBase, _super);
        function TreeChartBase(props) {
            var _a, _b, _c, _d, _e;
            var _this = _super.call(this, props) || this;
            _this._nodeElements = [];
            _this._linkElements = [];
            _this._margin = {
                top: ((_a = _this.props.margins) === null || _a === void 0 ? void 0 : _a.top) || 30,
                bottom: ((_b = _this.props.margins) === null || _b === void 0 ? void 0 : _b.bottom) || 30,
                left: ((_c = _this.props.margins) === null || _c === void 0 ? void 0 : _c.left) || 50,
                right: ((_d = _this.props.margins) === null || _d === void 0 ? void 0 : _d.right) || 20,
            };
            _this._width = _this.props.width || 1500;
            _this._height = _this.props.height || 700;
            _this._treeData = _this.props.treeData;
            _this._composition = (_e = _this.props) === null || _e === void 0 ? void 0 : _e.composition;
            _this._treeTraversal = _this.props.treeTraversal;
            _this.state = {
                _width: _this._width,
                _height: _this._height,
            };
            return _this;
        }
        TreeChartBase.prototype.componentDidMount = function () {
            var _a = this.props, theme = _a.theme, className = _a.className, styles = _a.styles;
            // Get classNames to create component styling
            this._classNames = getClassNames(styles, {
                theme: theme,
                className: className,
            });
            // Call createTreeChart function in componentDidMount
            this.createTreeChart();
            this.setState({
                _width: this.props.width || 1500,
                _height: this.props.height || 700,
            });
        };
        TreeChartBase.prototype.componentDidUpdate = function (prevProps) {
            if (prevProps.layoutWidth !== this.props.layoutWidth) {
                var svgText = (0, d3_selection_1.selectAll)('text');
                var svgRect = (0, d3_selection_1.selectAll)('rect');
                var svgLink = (0, d3_selection_1.selectAll)('path');
                if (this._nodeElements.length === 0 && this._linkElements.length === 0) {
                    svgText.remove();
                    svgRect.remove();
                    svgLink.remove();
                }
                this.createTreeChart();
            }
        };
        TreeChartBase.prototype.createTreeChart = function () {
            var nodeElements = [];
            var linkElements = [];
            // Instantiate inherited class and call createTree function for the object
            var treeObject = new LayeredTree(this._treeData, this._composition, this._classNames, nodeElements, linkElements, this._treeTraversal);
            var width = this.state._width - this._margin.left - this._margin.right;
            treeObject.createTree(this.props.layoutWidth, width);
            this._nodeElements = nodeElements;
            this._linkElements = linkElements;
        };
        TreeChartBase.prototype.render = function () {
            var _a;
            return (React.createElement(react_focus_1.FocusZone, null,
                React.createElement("div", { className: (_a = this._classNames) === null || _a === void 0 ? void 0 : _a.root },
                    React.createElement("svg", { className: "svgTree", width: this.state._width - this._margin.left - this._margin.right, height: this.state._height - this._margin.top - this._margin.bottom },
                        React.createElement("g", { className: "svgNode" }, this._nodeElements.map(function (element) { return element; })),
                        React.createElement("g", { className: "svgLink" }, this._linkElements.map(function (element) { return element; }))))));
        };
        return TreeChartBase;
    }(React.Component));
    exports.TreeChartBase = TreeChartBase;
});
//# sourceMappingURL=TreeChart.base.js.map