import { math, UITransform, warn } from "cc";
import { YXCollectionView, YXIndexPath, YXLayout, YXLayoutAttributes } from "./yx-collection-view";

export class GridLayout extends YXLayout {

    /**
     * 节点大小  
     */
    itemSize: math.Size = new math.Size(100, 100)

    /**
     * 垂直间距  
     */
    horizontalSpacing: number = 0

    /**
     * 水平间距  
     */
    verticalSpacing: number = 0

    /**
     * 整体对齐方式  
     * 0靠左 1居中 2靠右  
     */
    alignment: number = 1

    /**
     * 获取每行最多可以容纳多少个节点  
     */
    protected getMaxItemsPerRow(collectionView: YXCollectionView): number {
        if (this._maxItemsPerRow == null) {
            let num = 1
            const width = collectionView.node.getComponent(UITransform).contentSize.width
            while ((num * this.itemSize.width + (num - 1) * this.horizontalSpacing) <= width) { num++ }
            num = Math.max(1, num - 1)
            this._maxItemsPerRow = num
        }
        return this._maxItemsPerRow
    }
    protected _maxItemsPerRow: number = null

    prepare(collectionView: YXCollectionView): void {
        if (collectionView.scrollDirection === YXCollectionView.ScrollDirection.VERTICAL) {
            this._prepare_vertical(collectionView)
            return
        }
        if (collectionView.scrollDirection === YXCollectionView.ScrollDirection.HORIZONTAL) {
            warn(`GridLayout 仅支持垂直方向排列`)
            this._prepare_vertical(collectionView)
            return
        }
    }

    protected _prepare_vertical(collectionView: YXCollectionView) {
        collectionView.scrollView.horizontal = false
        collectionView.scrollView.vertical = true

        let attrs: YXLayoutAttributes[] = []
        let contentSize = collectionView.node.getComponent(UITransform).contentSize.clone()

        // 容器宽度
        const width = contentSize.width

        // 计算每行最多可以放多少个节点
        this._maxItemsPerRow = null
        let num = this.getMaxItemsPerRow(collectionView)

        // 根据设置的对齐方式计算左边距
        let left = 0
        if (this.alignment == 1) {
            let maxWidth = (num * this.itemSize.width + (num - 1) * this.horizontalSpacing) // 每行节点总宽度
            left = (width - maxWidth) * 0.5
        }
        if (this.alignment == 2) {
            let maxWidth = (num * this.itemSize.width + (num - 1) * this.horizontalSpacing) // 每行节点总宽度
            left = width - maxWidth
        }

        const numberOfSections = collectionView.getNumberOfSections()
        if (numberOfSections > 1) { warn(`GridLayout 暂时不支持分区模式`) }

        const numberOfItems = collectionView.getNumberOfItems(0)
        for (let index = 0; index < numberOfItems; index++) {

            // 计算这个节点是第几行
            let row = Math.floor(index / num)

            // 计算这个节点是第几列
            let column = index % num

            // 计算节点 origin
            let x = left + (this.itemSize.width + this.horizontalSpacing) * column
            let y = (this.itemSize.height + this.verticalSpacing) * row

            let attr = YXLayoutAttributes.layoutAttributesForCell(new YXIndexPath(0, index))
            attr.frame.x = x
            attr.frame.y = y
            attr.frame.width = this.itemSize.width
            attr.frame.height = this.itemSize.height
            attrs.push(attr)

            // 更新内容高度
            contentSize.height = Math.max(contentSize.height, attr.frame.yMax)
        }

        this.attributes = attrs
        this.contentSize = contentSize
    }

    initOffset(collectionView: YXCollectionView): void {
        collectionView.scrollView.scrollToTop()
    }

    layoutAttributesForElementsInRect(rect: math.Rect, collectionView: YXCollectionView): YXLayoutAttributes[] {
        return this.visibleElementsInRect(rect, collectionView)
    }

    /**
     * 抽出来一个方法用来优化列表性能  
     * 在优化之前,可以先看一下 @see YXLayout.layoutAttributesForElementsInRect 关于返回值的说明  
     */
    protected visibleElementsInRect(rect: math.Rect, collectionView: YXCollectionView) {
        if (this.attributes.length <= 100) { return this.attributes } // 少量数据就不查了,直接返回全部  

        // 根据当前范围直接计算出一个区间  
        const startRow = Math.floor(rect.y / (this.itemSize.height + this.verticalSpacing))
        const endRow = Math.ceil(rect.yMax / (this.itemSize.height + this.verticalSpacing))

        // 计算每行最多可以放多少个节点
        let num = this.getMaxItemsPerRow(collectionView)

        // 计算索引区间
        const startIdx = startRow * num
        const endIdx = endRow * num

        // 只返回区间节点的布局属性
        return this.attributes.slice(startIdx, endIdx)
    }
}