import { error } from "../util/debug";

import { layoutBottomInlineItems, layoutLeftInlineItems, layoutRightInlineItems, layoutTopInlineItems } from "./util";

export class Layout {
    constructor(_spec, ctx) {
        this.leftCurrent = 0, this.topCurrent = 0, this.rightCurrent = 0, this.bottomCurrent = 0, 
        this._onError = null == ctx ? void 0 : ctx.onError;
    }
    _layoutInit(_chart, items, chartLayoutRect, chartViewBox) {
        this._chartLayoutRect = chartLayoutRect, this._chartViewBox = chartViewBox, this.leftCurrent = chartLayoutRect.x, 
        this.topCurrent = chartLayoutRect.y, this.rightCurrent = chartLayoutRect.x + chartLayoutRect.width, 
        this.bottomCurrent = chartLayoutRect.height + chartLayoutRect.y, items.sort(((a, b) => b.layoutLevel - a.layoutLevel));
    }
    _layoutNormalItems(items) {
        this.layoutNormalInlineItems(items.filter((x => "normal-inline" === x.layoutType))), 
        this.layoutNormalItems(items.filter((x => "normal" === x.layoutType)));
    }
    _groupItems(items) {
        const regionItems = items.filter((x => "region" === x.layoutType)), relativeItems = items.filter((x => "region-relative" === x.layoutType)), relativeOverlapItems = items.filter((x => "region-relative-overlap" === x.layoutType)), allRelatives = relativeItems.concat(relativeOverlapItems), overlapItems = {
            left: {
                items: [],
                rect: {
                    width: 0,
                    height: 0
                }
            },
            right: {
                items: [],
                rect: {
                    width: 0,
                    height: 0
                }
            },
            top: {
                items: [],
                rect: {
                    width: 0,
                    height: 0
                }
            },
            bottom: {
                items: [],
                rect: {
                    width: 0,
                    height: 0
                }
            },
            z: {
                items: [],
                rect: {
                    width: 0,
                    height: 0
                }
            }
        };
        return relativeOverlapItems.forEach((i => {
            overlapItems[i.layoutOrient].items.push(i);
        })), {
            regionItems: regionItems,
            relativeItems: relativeItems,
            relativeOverlapItems: relativeOverlapItems,
            allRelatives: allRelatives,
            overlapItems: overlapItems
        };
    }
    layoutItems(_chart, items, chartLayoutRect, chartViewBox) {
        var _a, _b, _c;
        this._layoutInit(_chart, items, chartLayoutRect, chartViewBox);
        const secondLayoutLeftRight = null !== (_c = null === (_b = null === (_a = null == _chart ? void 0 : _chart.getSpec()) || void 0 === _a ? void 0 : _a.layout) || void 0 === _b ? void 0 : _b.secondLayoutLeftRight) && void 0 !== _c && _c;
        this._layoutNormalItems(items);
        const layoutTemp = {
            left: this.leftCurrent,
            top: this.topCurrent,
            right: this.rightCurrent,
            bottom: this.bottomCurrent
        }, {regionItems: regionItems, relativeItems: relativeItems, relativeOverlapItems: relativeOverlapItems, allRelatives: allRelatives, overlapItems: overlapItems} = this._groupItems(items);
        this.layoutRegionItems(regionItems, relativeItems, relativeOverlapItems, overlapItems, secondLayoutLeftRight), 
        this._processAutoIndent(regionItems, relativeItems, relativeOverlapItems, overlapItems, allRelatives, layoutTemp, secondLayoutLeftRight), 
        this.layoutAbsoluteItems(items.filter((x => "absolute" === x.layoutType)));
    }
    _processAutoIndent(regionItems, relativeItems, relativeOverlapItems, overlapItems = {
        left: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        right: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        top: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        bottom: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        z: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        }
    }, allRelatives, layoutTemp, secondLayoutLeftRight = !1) {
        if (allRelatives.some((i => i.autoIndent))) {
            const {top: top, bottom: bottom, left: left, right: right} = this._checkAutoIndent(allRelatives, layoutTemp);
            (top || bottom || left || right) && (this.topCurrent = layoutTemp.top + top, this.bottomCurrent = layoutTemp.bottom - bottom, 
            this.leftCurrent = layoutTemp.left + left, this.rightCurrent = layoutTemp.right - right, 
            this.layoutRegionItems(regionItems, relativeItems, relativeOverlapItems, overlapItems, secondLayoutLeftRight));
        }
    }
    layoutNormalItems(normalItems) {
        normalItems.forEach((item => {
            const layoutRect = this.getItemComputeLayoutRect(item), rect = item.computeBoundsInRect(layoutRect);
            item.setLayoutRect(rect), "left" === item.layoutOrient ? (item.setLayoutStartPosition({
                x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingLeft,
                y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
            }), this.leftCurrent += rect.width + item.layoutPaddingLeft + item.layoutPaddingRight) : "top" === item.layoutOrient ? (item.setLayoutStartPosition({
                x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingLeft,
                y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
            }), this.topCurrent += rect.height + item.layoutPaddingTop + item.layoutPaddingBottom) : "right" === item.layoutOrient ? (item.setLayoutStartPosition({
                x: this.rightCurrent + item.layoutOffsetX - rect.width - item.layoutPaddingRight,
                y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
            }), this.rightCurrent -= rect.width + item.layoutPaddingLeft + item.layoutPaddingRight) : "bottom" === item.layoutOrient && (item.setLayoutStartPosition({
                x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingRight,
                y: this.bottomCurrent + item.layoutOffsetY - rect.height - item.layoutPaddingBottom
            }), this.bottomCurrent -= rect.height + item.layoutPaddingTop + item.layoutPaddingBottom);
        }));
    }
    layoutNormalInlineItems(normalItems) {
        const leftItems = normalItems.filter((item => "left" === item.layoutOrient)), rightItems = normalItems.filter((item => "right" === item.layoutOrient)), topItems = normalItems.filter((item => "top" === item.layoutOrient)), bottomItems = normalItems.filter((item => "bottom" === item.layoutOrient)), limitWidth = this._chartLayoutRect.width + this._chartLayoutRect.x, limitHeight = this._chartLayoutRect.height + this._chartLayoutRect.y;
        leftItems.length && layoutLeftInlineItems(leftItems, this, limitHeight), topItems.length && layoutTopInlineItems(topItems, this, limitWidth), 
        rightItems.length && layoutRightInlineItems(rightItems, this, limitHeight), bottomItems.length && layoutBottomInlineItems(bottomItems, this, limitWidth);
    }
    _layoutRelativeOverlap(orient, info) {
        info.items.forEach((item => {
            const layoutRect = this.getItemComputeLayoutRect(item), rect = item.computeBoundsInRect(layoutRect);
            info.rect.width = Math.max(rect.width + item.layoutPaddingLeft + item.layoutPaddingRight, info.rect.width), 
            info.rect.height = Math.max(rect.height + item.layoutPaddingTop + item.layoutPaddingBottom, info.rect.height);
        })), info.items.forEach((item => {
            item.setLayoutRect(info.rect), "left" === orient ? item.setLayoutStartPosition({
                x: this.leftCurrent + item.layoutOffsetX
            }) : "right" === orient ? item.setLayoutStartPosition({
                x: this.rightCurrent - info.rect.width + item.layoutOffsetX
            }) : "top" === orient ? item.setLayoutStartPosition({
                x: this.topCurrent + item.layoutOffsetY
            }) : item.setLayoutStartPosition({
                x: this.bottomCurrent - info.rect.height + item.layoutOffsetY
            });
        })), "left" === orient ? this.leftCurrent += info.rect.width : "right" === orient ? this.rightCurrent -= info.rect.width : "top" === orient ? this.topCurrent += info.rect.height : this.bottomCurrent -= info.rect.height;
    }
    _layoutRelativeItem(item, layoutRect) {
        const rect = item.computeBoundsInRect(layoutRect);
        "left" === item.layoutOrient || "right" === item.layoutOrient ? item.setLayoutRect({
            width: rect.width
        }) : item.setLayoutRect({
            height: rect.height
        }), "left" === item.layoutOrient ? (item.setLayoutStartPosition({
            x: this.leftCurrent + item.layoutOffsetX + item.layoutPaddingLeft
        }), this.leftCurrent += rect.width + item.layoutPaddingLeft + item.layoutPaddingRight) : "right" === item.layoutOrient ? (this.rightCurrent -= rect.width + item.layoutPaddingLeft + item.layoutPaddingRight, 
        item.setLayoutStartPosition({
            x: this.rightCurrent + item.layoutOffsetX + item.layoutPaddingLeft
        })) : "top" === item.layoutOrient ? (item.setLayoutStartPosition({
            y: this.topCurrent + item.layoutOffsetY + item.layoutPaddingTop
        }), this.topCurrent += rect.height + item.layoutPaddingTop + item.layoutPaddingBottom) : "bottom" === item.layoutOrient && (this.bottomCurrent -= rect.height + item.layoutPaddingTop + item.layoutPaddingBottom, 
        item.setLayoutStartPosition({
            y: this.bottomCurrent + item.layoutOffsetY + item.layoutPaddingTop
        }));
    }
    _layoutRegionItem(regionItems, regionRelativeTotalWidth, regionRelativeTotalHeight) {
        const regionWidth = Math.max(Math.min(regionRelativeTotalWidth, ...regionItems.map((region => {
            var _a;
            return null !== (_a = region.maxWidth) && void 0 !== _a ? _a : Number.MAX_VALUE;
        }))), 0), regionHeight = Math.max(Math.min(regionRelativeTotalHeight, ...regionItems.map((region => {
            var _a;
            return null !== (_a = region.maxHeight) && void 0 !== _a ? _a : Number.MAX_VALUE;
        }))), 0);
        return regionItems.forEach((region => {
            const width = regionWidth - region.layoutPaddingLeft - region.layoutPaddingRight, height = regionHeight - region.layoutPaddingTop - region.layoutPaddingBottom;
            region.setLayoutRect({
                width: width,
                height: height
            }), region.setLayoutStartPosition({
                x: this.leftCurrent + region.layoutOffsetX + region.layoutPaddingLeft,
                y: this.topCurrent + region.layoutOffsetY + region.layoutPaddingTop
            });
        })), {
            regionHeight: regionHeight,
            regionWidth: regionWidth
        };
    }
    layoutRegionItems(regionItems, regionRelativeItems, regionRelativeOverlapItems, overlapItems = {
        left: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        right: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        top: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        bottom: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        },
        z: {
            items: [],
            rect: {
                width: 0,
                height: 0
            }
        }
    }, secondLayoutLeftRight = !1) {
        const leftBeforeLayout = this.leftCurrent, rightBeforeLayout = this.rightCurrent;
        let regionRelativeTotalWidth = this.rightCurrent - this.leftCurrent, regionRelativeTotalHeight = this.bottomCurrent - this.topCurrent;
        regionRelativeItems.filter((x => "left" === x.layoutOrient || "right" === x.layoutOrient)).forEach((item => {
            this._layoutRelativeItem(item, this.getItemComputeLayoutRect(item));
        })), this._layoutRelativeOverlap("left", overlapItems.left), this._layoutRelativeOverlap("right", overlapItems.right), 
        regionRelativeTotalWidth = this.rightCurrent - this.leftCurrent, regionRelativeItems.filter((x => "top" === x.layoutOrient || "bottom" === x.layoutOrient)).forEach((item => {
            this._layoutRelativeItem(item, this.getItemComputeLayoutRect(item));
        })), this._layoutRelativeOverlap("top", overlapItems.top), this._layoutRelativeOverlap("bottom", overlapItems.bottom), 
        regionRelativeTotalHeight = this.bottomCurrent - this.topCurrent, secondLayoutLeftRight && (this.leftCurrent = leftBeforeLayout, 
        this.rightCurrent = rightBeforeLayout, regionRelativeItems.filter((x => "left" === x.layoutOrient || "right" === x.layoutOrient)).forEach((item => {
            this._layoutRelativeItem(item, this.getItemComputeLayoutRect(item));
        })), regionRelativeTotalWidth = this.rightCurrent - this.leftCurrent);
        const {regionWidth: regionWidth, regionHeight: regionHeight} = this._layoutRegionItem(regionItems, regionRelativeTotalWidth, regionRelativeTotalHeight);
        regionRelativeItems.concat(regionRelativeOverlapItems).forEach((item => {
            if ([ "left", "right" ].includes(item.layoutOrient)) {
                const relativeRegion = this.filterRegionsWithID(regionItems, item.layoutBindRegionID[0]);
                item.setLayoutRect({
                    height: relativeRegion.getLayoutRect().height
                }), item.setLayoutStartPosition({
                    y: relativeRegion.getLayoutStartPoint().y + item.layoutOffsetY + item.layoutPaddingTop
                }), "right" === item.layoutOrient && item.setLayoutStartPosition({
                    x: item.getLayoutStartPoint().x + regionWidth - regionRelativeTotalWidth
                });
            } else if ([ "top", "bottom" ].includes(item.layoutOrient)) {
                const relativeRegion = this.filterRegionsWithID(regionItems, item.layoutBindRegionID[0]);
                item.setLayoutRect({
                    width: relativeRegion.getLayoutRect().width
                }), item.setLayoutStartPosition({
                    x: relativeRegion.getLayoutStartPoint().x + item.layoutOffsetX + item.layoutPaddingLeft
                }), "bottom" === item.layoutOrient && item.setLayoutStartPosition({
                    y: item.getLayoutStartPoint().y + regionHeight - regionRelativeTotalHeight
                });
            }
        }));
    }
    layoutAbsoluteItems(absoluteItems) {
        absoluteItems.forEach((item => {
            item.absoluteLayoutInRect(this._chartLayoutRect);
        }));
    }
    filterRegionsWithID(items, id) {
        var _a;
        const target = items.find((x => x.getModelId() === id));
        return target || (null !== (_a = this._onError) && void 0 !== _a ? _a : error)("can not find target region item, invalid id"), 
        target;
    }
    getItemComputeLayoutRect(item) {
        return {
            width: this.rightCurrent - this.leftCurrent - item.layoutPaddingLeft - item.layoutPaddingRight,
            height: this.bottomCurrent - this.topCurrent - item.layoutPaddingTop - item.layoutPaddingBottom
        };
    }
    _checkAutoIndent(items, layoutTemp) {
        const result = {
            top: 0,
            left: 0,
            bottom: 0,
            right: 0
        };
        return items.forEach((i => {
            if (!i.getModelVisible() || !i.autoIndent) return;
            const vOrH = "left" === i.layoutOrient || "right" === i.layoutOrient, itemOuter = i.getLastComputeOutBounds(), outer = this._getOutInLayout(itemOuter, i, layoutTemp);
            vOrH ? (result.top = Math.max(result.top, outer.top), result.bottom = Math.max(result.bottom, outer.bottom)) : (result.left = Math.max(result.left, outer.left), 
            result.right = Math.max(result.right, outer.right));
        })), result;
    }
    _getOutInLayout(itemOuter, i, tempBorder) {
        const {x: x, y: y} = i.getLayoutStartPoint(), {width: width, height: height} = i.getLayoutRect();
        return {
            left: tempBorder.left - (x - itemOuter.x1),
            right: x + width + itemOuter.x2 - tempBorder.right,
            top: tempBorder.top - (y - itemOuter.y1),
            bottom: y + height + itemOuter.y2 - tempBorder.bottom
        };
    }
}

Layout.type = "base";
//# sourceMappingURL=base-layout.js.map
