import { _decorator, math, UITransform } from 'cc';
import { YXCollectionView, YXEdgeInsets, YXIndexPath, YXLayout, YXLayoutAttributes } from './yx-collection-view';
const { ccclass, property } = _decorator;

const _rectOut = new math.Rect()

enum _yx_flow_layout_alignment {

    /**
     * 节点在所处行/列内居中
     */
    CENTER,

    /**
     * 这个配置表示向前对齐，节点会向排列开始的方向对齐，具体表现为:  
     * 当列表为垂直方向列表时，如果节点排列方向是由上至下排列的，这个值就代表上对齐，如果节点排列方向是由下至上排列的，这个值就代表下对齐    
     * 当列表为水平方向列表时，如果节点排列方向是由左至右排列的，这个值就代表左对齐，如果节点排列方向是由右至左排列的，这个值就代表右对齐    
     */
    FORWARD,

    /**
     * 这个配置表示向后对齐，具体表现跟 FORWARD 相反  
     */
    BACKWARD,
}


enum _yx_flow_layout_priority {

    /**
     * 以 spacing 配置为准，弱化 sectionInset 配置  
     */
    CENTER,

    /**
     * 以 sectionInset 配置为准，弱化 spacing 配置  
     */
    SIDE,

    /**
     * 以 sectionInset.left 为准，弱化 right 配置  
     * 仅支持垂直滚动列表  
     */
    LEFT,

    /**
     * 以 sectionInset.right 为准，弱化 left 配置  
     * 仅支持垂直滚动列表  
     */
    RIGHT,

    /**
     * 以 sectionInset.top 为准，弱化 bottom 配置  
     * 仅支持水平滚动列表  
     */
    TOP,

    /**
     * 以 sectionInset.bottom 为准，弱化 top 配置  
     * 仅支持水平滚动列表  
     */
    BOTTOM,
}

enum _yx_flow_layout_reverse_mode {

    /**
     * 默认方案  
     * 水平排列方向为从左至右排列  
     * 垂直排列方向为从上至下排列  
     */
    NONE = 0,

    /**
     * 这个标识会将水平排列方向变为从右至左排列  
     */
    HORIZONTAL = 1 << 0,

    /**
     * 这个标识会将垂直排列方向变为从下至上排列  
     */
    VERTICAL = 1 << 1,
}


/**
 * 流式布局
 * 支持水平/垂直方向排列滚动
 */
export class YXFlowLayout extends YXLayout {

    /**
     * 是否开启分页滚动效果
     */
    pagingEnabled: boolean = false

    /**
     * @bug 如果节点大小差距很大，可能会导致计算屏幕内节点时不准确，出现节点不被正确添加到滚动视图上的问题
     * @fix 可以通过此属性，追加屏幕显示的节点数量
     * 设置这个值会在检查是否可见的节点时，尝试检查更多的可能处于屏幕外的节点，具体设置多少要根据实际情况调试，一般如果都是正常大小的节点，不需要考虑这个配置
     * 设置负值会检查所有的节点
     */
    extraVisibleCount: number = 0

    /**
     * 节点在行(垂直列表)或者列(水平列表)内的对齐方式  
     */
    alignment: _yx_flow_layout_alignment = YXFlowLayout.Alignment.CENTER
    static Alignment = _yx_flow_layout_alignment

    /**
     * 约束优先级  
     */
    priority: _yx_flow_layout_priority = YXFlowLayout.Priority.SIDE
    static Priority = _yx_flow_layout_priority

    /**
     * 反向排列节点  
     * @example  
     * // 水平反向排列  
     * layout.reverse = YXFlowLayout.Reverse.HORIZONTAL  
     * 
     * // 垂直反向排列  
     * layout.reverse = YXFlowLayout.Reverse.VERTICAL  
     * 
     * // 水平/垂直都反向排列  
     * layout.reverse = YXFlowLayout.Reverse.HORIZONTAL | YXFlowLayout.Reverse.VERTICAL  
     */
    reverse: _yx_flow_layout_reverse_mode = YXFlowLayout.Reverse.NONE
    static Reverse = _yx_flow_layout_reverse_mode

    /**
     * 元素大小
     */
    itemSize: math.Size | ((indexPath: YXIndexPath, layout: YXFlowLayout, collectionView: YXCollectionView) => math.Size) = new math.Size(100, 100)
    getItemSize(): math.Size {
        if (this.itemSize instanceof Function == false) {
            return this.itemSize
        }
        throw new Error("YXFlowLayout: 动态配置的布局参数不支持直接获取，请检查自己的布局逻辑并谨慎的通过动态配置自己获取，注意避免死循环");
    }

    /**
     * 元素之间垂直间距
     */
    verticalSpacing: number | ((section: number, layout: YXFlowLayout, collectionView: YXCollectionView) => number) = 0
    getVerticalSpacing(): number {
        if (this.verticalSpacing instanceof Function == false) {
            return this.verticalSpacing
        }
        throw new Error("YXFlowLayout: 动态配置的布局参数不支持直接获取，请检查自己的布局逻辑并谨慎的通过动态配置自己获取，注意避免死循环");
    }

    /**
     * 元素之间水平间距
     */
    horizontalSpacing: number | ((section: number, layout: YXFlowLayout, collectionView: YXCollectionView) => number) = 0
    getHorizontalSpacing(): number {
        if (this.horizontalSpacing instanceof Function == false) {
            return this.horizontalSpacing
        }
        throw new Error("YXFlowLayout: 动态配置的布局参数不支持直接获取，请检查自己的布局逻辑并谨慎的通过动态配置自己获取，注意避免死循环");
    }

    /**
     * 边距
     */
    sectionInset: YXEdgeInsets | ((section: number, layout: YXFlowLayout, collectionView: YXCollectionView) => YXEdgeInsets) = YXEdgeInsets.ZERO
    getSectionInset(): YXEdgeInsets {
        if (this.sectionInset instanceof Function == false) {
            return this.sectionInset
        }
        throw new Error("YXFlowLayout: 动态配置的布局参数不支持直接获取，请检查自己的布局逻辑并谨慎的通过动态配置自己获取，注意避免死循环");
    }

    prepare(collectionView: YXCollectionView): void {
        if (collectionView.scrollDirection == YXCollectionView.ScrollDirection.HORIZONTAL) {
            this._horizontal(collectionView)
            return
        }
        if (collectionView.scrollDirection == YXCollectionView.ScrollDirection.VERTICAL) {
            this._vertical(collectionView)
            return
        }
    }

    initOffset(collectionView: YXCollectionView): void {
        if (collectionView.scrollDirection == YXCollectionView.ScrollDirection.HORIZONTAL) {
            collectionView.scrollView.scrollToLeft(0)
            return
        }
        if (collectionView.scrollDirection == YXCollectionView.ScrollDirection.VERTICAL) {
            collectionView.scrollView.scrollToTop(0)
            return
        }
    }

    targetOffset(collectionView: YXCollectionView, touchMoveVelocity: math.Vec3, startOffset: math.Vec2): { offset: math.Vec2; time: number; } {
        if (this.pagingEnabled == false) {
            return null
        }
        let offset = collectionView.scrollView.getScrollOffset()
        offset.x = - offset.x
        let threshold = 0.2
        if (collectionView.scrollDirection == YXCollectionView.ScrollDirection.HORIZONTAL) {
            let idx = Math.round(offset.x / collectionView.scrollView.view.width)
            let r = touchMoveVelocity.x / collectionView.scrollView.view.width
            if (startOffset && Math.abs(r) >= threshold) {
                idx = Math.round(startOffset.x / collectionView.scrollView.view.width) + (r > 0 ? -1 : 1)
            }
            offset.x = idx * collectionView.scrollView.view.width
        }
        if (collectionView.scrollDirection == YXCollectionView.ScrollDirection.VERTICAL) {
            let idx = Math.round(offset.y / collectionView.scrollView.view.height)
            let r = touchMoveVelocity.y / collectionView.scrollView.view.height
            if (startOffset && Math.abs(r) >= threshold) {
                idx = Math.round(startOffset.y / collectionView.scrollView.view.height) + (r > 0 ? 1 : -1)
            }
            offset.y = idx * collectionView.scrollView.view.height
        }
        return { offset: offset, time: 0.25 }
    }

    layoutAttributesForElementsInRect(rect: math.Rect, collectionView: YXCollectionView): YXLayoutAttributes[] {
        if (this.extraVisibleCount < 0) {
            return super.layoutAttributesForElementsInRect(rect, collectionView)
        }

        // 二分先查出大概位置
        let midIdx = -1
        let left = 0
        let right = this.attributes.length - 1

        while (left <= right && right >= 0) {
            let mid = left + (right - left) / 2
            mid = Math.floor(mid)
            let attr = this.attributes[mid]
            if (rect.intersects(attr.frame)) {
                midIdx = mid
                break
            }
            if (rect.yMax < attr.frame.yMin || rect.xMax < attr.frame.xMin) {
                right = mid - 1
            } else {
                left = mid + 1
            }
        }
        if (midIdx < 0) {
            return super.layoutAttributesForElementsInRect(rect, collectionView)
        }

        let result = []
        result.push(this.attributes[midIdx])

        // 往前检查
        let startIdx = midIdx
        while (startIdx > 0) {
            let idx = startIdx - 1
            let attr = this.attributes[idx]
            if (rect.intersects(attr.frame) == false) {
                break
            }
            result.push(attr)
            startIdx = idx
        }

        // 追加检查
        let extra_left = this.extraVisibleCount
        while (extra_left > 0) {
            let idx = startIdx - 1
            if (idx < 0) { break }
            let attr = this.attributes[idx]
            if (rect.intersects(attr.frame)) { result.push(attr) }
            startIdx = idx
            extra_left--
        }

        // 往后检查
        let endIdx = midIdx
        while (endIdx < this.attributes.length - 1) {
            let idx = endIdx + 1
            let attr = this.attributes[idx]
            if (rect.intersects(attr.frame) == false) {
                break
            }
            result.push(attr)
            endIdx = idx
        }

        // 追加检查
        let extra_right = this.extraVisibleCount
        while (extra_right > 0) {
            let idx = endIdx + 1
            if (idx >= this.attributes.length) { break }
            let attr = this.attributes[idx]
            if (rect.intersects(attr.frame)) { result.push(attr) }
            endIdx = idx
            extra_right--
        }

        return result
    }

    layoutAttributesForItemAtIndexPath(indexPath: YXIndexPath, collectionView: YXCollectionView): YXLayoutAttributes {
        let left = 0
        let right = this.attributes.length - 1

        while (left <= right && right >= 0) {
            let mid = left + (right - left) / 2
            mid = Math.floor(mid)
            let attr = this.attributes[mid]
            if (attr.indexPath.equals(indexPath)) {
                return attr
            }
            if (attr.indexPath.section < indexPath.section || (attr.indexPath.section == indexPath.section && attr.indexPath.item < indexPath.item)) {
                left = mid + 1
            } else {
                right = mid - 1
            }
        }
        return super.layoutAttributesForItemAtIndexPath(indexPath, collectionView)
    }

    private _horizontal(collectionView: YXCollectionView) {
        collectionView.scrollView.horizontal = true
        collectionView.scrollView.vertical = false
        let contentSize = collectionView.node.getComponent(UITransform).contentSize.clone()
        let allAttributes: YXLayoutAttributes[] = []

        let numberOfSections = collectionView.numberOfSections instanceof Function ? collectionView.numberOfSections(collectionView) : collectionView.numberOfSections

        let sectionMaxX = 0
        for (let section = 0; section < numberOfSections; section++) {
            let numberOfItems = collectionView.numberOfItems instanceof Function ? collectionView.numberOfItems(section, collectionView) : collectionView.numberOfItems
            let verticalSpacing = this.verticalSpacing instanceof Function ? this.verticalSpacing(section, this, collectionView) : this.verticalSpacing
            let horizontalSpacing = this.horizontalSpacing instanceof Function ? this.horizontalSpacing(section, this, collectionView) : this.horizontalSpacing
            let sectionInset = this.sectionInset instanceof Function ? this.sectionInset(section, this, collectionView) : this.sectionInset

            sectionMaxX += sectionInset.left

            let whole = new _yx_flow_layout_whole()
            whole.verticalSpacing = verticalSpacing
            whole.horizontalSpacing = horizontalSpacing
            whole.sectionInset = sectionInset
            whole.offset = sectionMaxX
            whole.attrs = []
            whole.containerWidth = 0
            whole.containerHeight = contentSize.height
            whole.alignment = this.alignment
            whole.priority = this.priority
            whole.reverse = this.reverse

            for (let item = 0; item < numberOfItems; item++) {
                let indexPath = new YXIndexPath(section, item)
                let itemSize = this.itemSize instanceof Function ? this.itemSize(indexPath, this, collectionView) : this.itemSize

                let attr = whole.layout_horizontal_item(indexPath, itemSize)
                if (attr == null) {
                    // 返回 null 表示摆不下了，需要换列排列
                    whole.layout_horizontal_complet()
                    whole.offset = whole.offset + whole.containerWidth + horizontalSpacing
                    whole.containerWidth = 0
                    whole.attrs = []
                    attr = whole.layout_horizontal_item(indexPath, itemSize)
                }
                if (attr) {
                    allAttributes.push(attr)
                }
                sectionMaxX = Math.max(sectionMaxX, whole.offset + whole.containerWidth)
            }

            whole.layout_horizontal_complet()
            sectionMaxX += sectionInset.right
        }

        this._reverse_horizontal(allAttributes, sectionMaxX)
        this.attributes = allAttributes
        contentSize.width = Math.max(contentSize.width, sectionMaxX)
        this.contentSize = contentSize
    }

    protected _reverse_horizontal(attributes: YXLayoutAttributes[], contentWidth: number) {
        if (this.reverse & _yx_flow_layout_reverse_mode.HORIZONTAL) {
            for (let index = 0; index < attributes.length; index++) {
                const element = attributes[index];
                element.frame.x = contentWidth - element.frame.x - element.frame.width;
            }
        }
    }

    private _vertical(collectionView: YXCollectionView) {
        collectionView.scrollView.horizontal = false
        collectionView.scrollView.vertical = true
        let contentSize = collectionView.node.getComponent(UITransform).contentSize.clone()
        let allAttributes: YXLayoutAttributes[] = []

        let numberOfSections = collectionView.numberOfSections instanceof Function ? collectionView.numberOfSections(collectionView) : collectionView.numberOfSections

        let sectionMaxY = 0
        for (let section = 0; section < numberOfSections; section++) {
            let numberOfItems = collectionView.numberOfItems instanceof Function ? collectionView.numberOfItems(section, collectionView) : collectionView.numberOfItems
            let verticalSpacing = this.verticalSpacing instanceof Function ? this.verticalSpacing(section, this, collectionView) : this.verticalSpacing
            let horizontalSpacing = this.horizontalSpacing instanceof Function ? this.horizontalSpacing(section, this, collectionView) : this.horizontalSpacing
            let sectionInset = this.sectionInset instanceof Function ? this.sectionInset(section, this, collectionView) : this.sectionInset

            sectionMaxY += sectionInset.top

            let whole = new _yx_flow_layout_whole()
            whole.verticalSpacing = verticalSpacing
            whole.horizontalSpacing = horizontalSpacing
            whole.sectionInset = sectionInset
            whole.offset = sectionMaxY
            whole.attrs = []
            whole.containerWidth = contentSize.width
            whole.containerHeight = 0
            whole.alignment = this.alignment
            whole.priority = this.priority
            whole.reverse = this.reverse

            for (let item = 0; item < numberOfItems; item++) {
                let indexPath = new YXIndexPath(section, item)
                let itemSize = this.itemSize instanceof Function ? this.itemSize(indexPath, this, collectionView) : this.itemSize

                let attr = whole.layout_vertical_item(indexPath, itemSize)
                if (attr == null) {
                    // 返回 null 表示摆不下了，需要换行排列
                    whole.layout_vertical_complet()
                    whole.offset = whole.offset + whole.containerHeight + verticalSpacing
                    whole.containerHeight = 0
                    whole.attrs = []
                    attr = whole.layout_vertical_item(indexPath, itemSize)
                }
                if (attr) {
                    allAttributes.push(attr)
                }
                sectionMaxY = Math.max(sectionMaxY, whole.offset + whole.containerHeight)
            }

            whole.layout_vertical_complet()
            sectionMaxY += sectionInset.bottom
        }

        this._reverse_vertical(allAttributes, sectionMaxY)
        this.attributes = allAttributes
        contentSize.height = Math.max(contentSize.height, sectionMaxY)
        this.contentSize = contentSize
    }

    protected _reverse_vertical(attributes: YXLayoutAttributes[], contentHeight: number) {
        if (this.reverse & _yx_flow_layout_reverse_mode.VERTICAL) {
            for (let index = 0; index < attributes.length; index++) {
                const element = attributes[index];
                element.frame.y = contentHeight - element.frame.y - element.frame.height;
            }
        }
    }
}

export namespace YXFlowLayout {
    export type Alignment = _yx_flow_layout_alignment
    export type Priority = _yx_flow_layout_priority
    export type Reverse = _yx_flow_layout_reverse_mode
}

/**
 * 实现按行/列排列节点 && 调整对齐方式/约束优先级  
 * 一个 whole 对象管理一行或者一列的节点  
 */
class _yx_flow_layout_whole {

    /**
     * 当前这块内容的起始位置  
     * 可能是 x，可能是 y，取决于排列方向  
     */
    offset: number

    /**
     * flow layout 部分参数
     */
    verticalSpacing: number
    horizontalSpacing: number
    sectionInset: YXEdgeInsets
    alignment: _yx_flow_layout_alignment
    priority: _yx_flow_layout_priority
    reverse: _yx_flow_layout_reverse_mode

    /**
     * 容器相关的参数
     */
    containerWidth: number
    containerHeight: number

    /**
     * 这块内容区域目前已经摆放的节点
     */
    attrs: YXLayoutAttributes[] = []

    /**
     * 检查传进来的位置是否跟当前这块内容的其他节点重叠
     */
    intersects(rect: math.Rect) {
        for (let index = 0; index < this.attrs.length; index++) {
            const element = this.attrs[index];
            math.Rect.intersection(_rectOut, element.frame, rect)
            if (_rectOut.width > 0 && _rectOut.height > 0) {
                return true
            }
        }
        return false
    }

    /**
     * 垂直方向列表的节点的排列规则
     */
    layout_vertical_item(indexPath: YXIndexPath, itemSize: math.Size) {
        if (this.attrs.length <= 0) {
            let attributes = new YXLayoutAttributes()
            attributes.indexPath = indexPath
            attributes.frame = new math.Rect(this.sectionInset.left, this.offset, itemSize.width, itemSize.height)
            this.attrs.push(attributes)
            this.containerHeight = Math.max(this.containerHeight, attributes.frame.height)
            return attributes
        }

        const frame = new math.Rect()
        frame.size = itemSize

        // 检查所有节点的右边
        for (let index = 0; index < this.attrs.length; index++) {
            const element = this.attrs[index];
            frame.x = element.frame.xMax + this.horizontalSpacing
            frame.y = element.frame.y
            if (frame.xMax <= (this.containerWidth - this.sectionInset.right)) {
                if (this.intersects(frame) == false) {
                    let attributes = new YXLayoutAttributes()
                    attributes.indexPath = indexPath
                    attributes.frame = frame
                    this.attrs.push(attributes)
                    // this.containerHeight = Math.max(this.containerHeight, attributes.frame.height)
                    this.containerHeight = Math.max(this.containerHeight, attributes.frame.yMax - this.offset)
                    return attributes
                }
            }
        }

        // 走到这里表示这块内容区域已经摆不下了，需要换行处理
        return null
    }

    layout_vertical_complet() {

        // 反转水平方向 (如果需要的话)  
        if (this.reverse & _yx_flow_layout_reverse_mode.HORIZONTAL) {
            this.attrs = this.attrs.reverse()
        }

        // 调整对齐方式  
        if (this.alignment == _yx_flow_layout_alignment.CENTER) {
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.y = this.offset + (this.containerHeight - element.frame.height) * 0.5
            }
        }
        if (this.alignment == _yx_flow_layout_alignment.BACKWARD) {
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.y = this.offset + (this.containerHeight - element.frame.height)
            }
        }

        // 按优先级调整节点位置    
        let priority = this.priority
        if (priority == _yx_flow_layout_priority.SIDE && this.attrs.length == 1) {
            // 当设置为 side 模式但是一行内只有一个节点时，暂定为居中显示  
            priority = _yx_flow_layout_priority.CENTER
        }
        if (priority == _yx_flow_layout_priority.TOP || priority == _yx_flow_layout_priority.BOTTOM) {
            throw new Error("flow layout priority 配置错误: 不支持的优先级配置");
        }
        if (priority == _yx_flow_layout_priority.CENTER) {
            let totalWidth = 0
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                totalWidth += element.frame.width
            }
            totalWidth = totalWidth + (this.attrs.length - 1) * this.horizontalSpacing
            let left = (this.containerWidth - totalWidth) * 0.5
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.x = left
                left = element.frame.xMax + this.horizontalSpacing
            }
        }
        if (priority == _yx_flow_layout_priority.LEFT && this.reverse & _yx_flow_layout_reverse_mode.HORIZONTAL) {
            let left = this.sectionInset.left
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.x = left
                left = element.frame.xMax + this.horizontalSpacing
            }
        }
        if (priority == _yx_flow_layout_priority.RIGHT) {
            let totalWidth = 0
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                totalWidth += element.frame.width
            }
            totalWidth = totalWidth + (this.attrs.length - 1) * this.horizontalSpacing
            let left = (this.containerWidth - totalWidth) - this.sectionInset.right
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.x = left
                left = element.frame.xMax + this.horizontalSpacing
            }
        }
        if (priority == _yx_flow_layout_priority.SIDE) {
            let totalWidth = 0
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                totalWidth += element.frame.width
            }
            let horizontalSpacing = (this.containerWidth - this.sectionInset.left - this.sectionInset.right - totalWidth) / (this.attrs.length - 1)
            let offset = this.sectionInset.left
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.x = offset
                offset = element.frame.xMax + horizontalSpacing
            }
        }
    }

    /**
     * 水平方向列表的节点的排列规则
     */
    layout_horizontal_item(indexPath: YXIndexPath, itemSize: math.Size) {
        if (this.attrs.length <= 0) {
            let attributes = new YXLayoutAttributes()
            attributes.indexPath = indexPath
            attributes.frame = new math.Rect(this.offset, this.sectionInset.top, itemSize.width, itemSize.height)
            this.attrs.push(attributes)
            this.containerWidth = Math.max(this.containerWidth, attributes.frame.width)
            return attributes
        }

        const frame = new math.Rect()
        frame.size = itemSize

        // 检测所有节点的下边
        for (let index = 0; index < this.attrs.length; index++) {
            const element = this.attrs[index];
            frame.x = element.frame.x
            frame.y = element.frame.yMax + this.verticalSpacing
            if (frame.yMax <= (this.containerHeight - this.sectionInset.bottom)) {
                if (this.intersects(frame) == false) {
                    let attributes = new YXLayoutAttributes()
                    attributes.indexPath = indexPath
                    attributes.frame = frame
                    this.attrs.push(attributes)
                    // this.containerWidth = Math.max(this.containerWidth, attributes.frame.width)
                    this.containerWidth = Math.max(this.containerWidth, attributes.frame.xMax - this.offset)
                    return attributes
                }
            }
        }

        // 走到这里表示这块内容区域已经摆不下了
        return null
    }

    layout_horizontal_complet() {

        // 反转垂直方向 (如果需要的话)  
        if (this.reverse & _yx_flow_layout_reverse_mode.VERTICAL) {
            this.attrs = this.attrs.reverse()
        }

        // 调整对齐方式  
        if (this.alignment == _yx_flow_layout_alignment.CENTER) {
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.x = this.offset + (this.containerWidth - element.frame.width) * 0.5
            }
        }
        if (this.alignment == _yx_flow_layout_alignment.BACKWARD) {
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.x = this.offset + (this.containerWidth - element.frame.width)
            }
        }

        // 按优先级调整节点位置    
        let priority = this.priority
        if (priority == _yx_flow_layout_priority.SIDE && this.attrs.length == 1) {
            // 当设置为 side 模式但是一列内只有一个节点时，暂定为居中显示  
            priority = _yx_flow_layout_priority.CENTER
        }
        if (priority == _yx_flow_layout_priority.LEFT || priority == _yx_flow_layout_priority.RIGHT) {
            throw new Error("flow layout priority 配置错误: 不支持的优先级配置");
        }
        if (priority == _yx_flow_layout_priority.CENTER) {
            let totalHeight = 0
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                totalHeight += element.frame.height
            }
            totalHeight = totalHeight + (this.attrs.length - 1) * this.verticalSpacing
            let top = (this.containerHeight - totalHeight) * 0.5
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.y = top
                top = element.frame.yMax + this.verticalSpacing
            }
        }
        if (priority == _yx_flow_layout_priority.TOP && this.reverse & _yx_flow_layout_reverse_mode.VERTICAL) {
            let top = this.sectionInset.top
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.y = top
                top = element.frame.yMax + this.verticalSpacing
            }
        }
        if (priority == _yx_flow_layout_priority.BOTTOM) {
            let totalHeight = 0
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                totalHeight += element.frame.height
            }
            totalHeight = totalHeight + (this.attrs.length - 1) * this.verticalSpacing
            let top = (this.containerHeight - totalHeight) - this.sectionInset.bottom
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.y = top
                top = element.frame.yMax + this.verticalSpacing
            }
        }
        if (priority == _yx_flow_layout_priority.SIDE) {
            let totalHeight = 0
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                totalHeight += element.frame.height
            }
            let verticalSpacing = (this.containerHeight - this.sectionInset.top - this.sectionInset.bottom - totalHeight) / (this.attrs.length - 1)
            let offset = this.sectionInset.top
            for (let index = 0; index < this.attrs.length; index++) {
                const element = this.attrs[index];
                element.frame.y = offset
                offset = element.frame.yMax + verticalSpacing
            }
        }
    }
}
