/**横向排布拖动*/
export const SCROLL_HORIZONTAL: number = 1;
/**竖向排布拖动*/
export const SCROLL_VERTICAL: number = 2;

import {
    _decorator,
    Node,
    Prefab,
    instantiate,
    ScrollView,
    UITransform,
    Vec3,
    Vec2,
} from "cc";
import {ScrollListItem} from "./ScrollListItem";

const {ccclass, property} = _decorator;

@ccclass("ScrollList")
export class ScrollList extends ScrollView {
    /**item子节点预制体*/
    @property({type: Prefab, tooltip: "item子节点预制体"})
    itemPrefab: Prefab = null;

    /**单条记录高度*/
    private _itemSize: number;

    /**需要多少个记录组件 在可视范围内+2条*/
    private _numItem: number = 0;

    private _itemArr: Array<Node> = [];

    /**当前最大节点下标*/
    private _itemIndex: number = 0;

    /**当前最大数据下标*/
    private _dataIndex: number = 0;

    /**数据源*/
    _dataArr: any[];

    /**滚动方向*/
    private _direction: number = 0;

    /**间隙 0=开始边框，1=结束边框，2=间隙*/
    private _gapNum: number[];

    /**子节点刷新绑定事件，或者使用item继承的模式*/
    public onItemRender: Function;

    /**渲染完毕执行*/
    public arriveBottom: Function;

    /** 是否执行了触底函数 */
    isExec: boolean = false;

    /** 自定义传参 */
    params: any = {}

    start() {
        super.start();
        this.node.on("scrolling", this.scrollCheck, this);
    }

    onDestroy() {
        // super.onDestroy();
        // if (this.node) {
        //   this.node.off("scrolling", this.scrollCheck, this);
        // }
    }

    /**设置数据
     * @param dataArr : 数据源
     * @param direction : 滚动方向，默认上下
     * @param gap : [开始边框距离，结束边框距离，每个之间空隙]
     */
    public setDataList(
        dataArr: any[],
        direction: number = SCROLL_VERTICAL,
        gap?: number[],
        arriveBottom?: Function,
        ...params
    ) {

        this._itemArr = [];

        this.content.destroyAllChildren();
        this._dataArr = dataArr;
        this._direction = direction;
        this._gapNum = gap;
        this.arriveBottom = arriveBottom;
        this.params = params;
        this.createItem();
    }

    updateDataList(dataArr: any[]) {
        this._dataArr = dataArr;

        //设置容器大小
        this.setContentSize();

    }

    /**获得数据后开始创建*/
    private createItem() {
        // console.log(`%c 开始渲染`, "font-size: 32px; color: pink");
        // console.log("node", this.node, this._dataArr.length);
        let _showSize = this.node.getComponent(UITransform).height;
        // console.log("height: ", _showSize)
        //获得预制体的高度
        if (!this._itemSize) {
            let pNode = instantiate(this.itemPrefab);
            if (this._direction == SCROLL_HORIZONTAL) {
                this._itemSize = pNode.getComponent(UITransform).contentSize.width;
                _showSize = this.node.getComponent(UITransform).width;
            } else {
                this._itemSize = pNode.getComponent(UITransform).contentSize.height;
            }
            pNode.destroy();
            // log("---_itemSize--", this._itemSize);
        }

        //可视范围，对应可以创建多少个实体单例item
        this._numItem = Math.floor(_showSize / this._itemSize) + 4;
        // console.log(_showSize, "初始化获得数量：", this._numItem);
        if (this._dataArr.length < this._numItem) {
            this._numItem = this._dataArr.length;
        }

        this._itemArr.length = 0;
        // console.log("numItem: ", this._numItem);
        for (let index = 0; index < this._numItem; index++) {
            let pNode = instantiate(this.itemPrefab);
            pNode.parent = this.content;
            this._itemArr.push(pNode);
            this.itemRender(pNode, index);
        }

        this.setContentSize();

        this._itemIndex = this._dataIndex = this._itemArr.length - 1;
        // console.log("初始化结束：", this._dataIndex, this._itemArr.length);
    }

    setContentSize() {
        //设置容器大小
        let contentSize = this._itemSize * this._dataArr.length;
        //前面距离边框
        if (this._gapNum && this._gapNum[0]) {
            contentSize += this._gapNum[0];
        }
        //后面距离边框
        if (this._gapNum && this._gapNum[1]) {
            contentSize += this._gapNum[1];
        }
        //间隙距离
        if (this._gapNum && this._gapNum[2]) {
            contentSize += this._gapNum[2] * (this._dataArr.length - 1);
        }

        if (this._direction == SCROLL_HORIZONTAL) {
            this.content.getComponent(UITransform).width = contentSize;
        } else {
            this.content.getComponent(UITransform).height = contentSize;
        }

    }

    private scrollCheck() {
        let nowPos = this.getScrollOffset().y;
        let topPos = (this._dataIndex + 1 - this._numItem) * this._itemSize; //当前屏幕中靠近最开始的坐标

        //前面边框
        if (this._gapNum && this._gapNum[0]) {
            topPos += this._gapNum[0];
        }
        //间隙距离
        if (this._gapNum && this._gapNum[2]) {
            topPos += this._gapNum[2] * (this._dataIndex + 1 - this._numItem);
        }

        // let topPos = this.countPosByIndex(this._dataIndex + 1 - this._numItem);
        let size = this._itemSize;
        if (this._direction == SCROLL_HORIZONTAL) {
            nowPos = this.getScrollOffset().x;
            topPos = -topPos;
            size = -this._itemSize;
        }

        //判断向结束端滚动，滚动点和初始点对比
        if (
            (this._direction == SCROLL_VERTICAL && nowPos > size + topPos) ||
            (this._direction == SCROLL_HORIZONTAL && nowPos < size + topPos)
        ) {
            let newIndex = this._dataIndex + 1;
            // log(this._dataIndex, "-判断向结束端滚动 1 --将头部item转移到最后---", nowPos, topPos);
            if (newIndex >= this._dataArr.length) {
                if (!!this.arriveBottom && !this.isExec) {
                    this.arriveBottom(nowPos);
                    this.isExec = true;
                }
                return; //如果滚动到底部最后一条数据，不再进行写入
            }

            this._dataIndex = newIndex;

            let topItemIndex = this._itemIndex + 1;
            if (topItemIndex >= this._numItem) {
                topItemIndex = 0;
            }

            let item = this._itemArr[topItemIndex];
            if (item) {
                this.itemRender(item, newIndex);
                // error(topItemIndex, "转移到最后", item.node.position);
            }

            this._itemIndex = topItemIndex;
            // console.log("_itemIndex", this._itemIndex);
        }

        //判断向开始端滚动
        else if (
            (this._direction == SCROLL_VERTICAL && nowPos < topPos) ||
            (this._direction == SCROLL_HORIZONTAL && nowPos > topPos)
        ) {
            let newIndex = this._dataIndex + 1 - this._numItem - 1;
            // log(this._dataIndex, "-判断向上滚动 2 -将最后item转移到头部----", newIndex);
            if (newIndex < 0) {
                // warn("如果滚动到第一条数据，不再进行写入", newIndex)
                return; //如果滚动到第一条数据，不再进行写入
            }
            this._dataIndex--;
            // error(this._itemIndex, "将最后item转移到头部", this._dataIndex, newIndex, newIndex * -this._itemSize);
            let item = this._itemArr[this._itemIndex];
            if (item) {
                this.itemRender(item, newIndex);
                // error(this._itemIndex, "转移头部", item.node.position);
            }

            this._itemIndex--;
            if (this._itemIndex < 0) {
                this._itemIndex = this._numItem - 1;
            }
        }
    }

    /**刷新单项*/
    private itemRender(node: Node, newIndex: number) {
        //设置有全局得刷新事件
        if (this.onItemRender) {
            this.onItemRender(node, newIndex, this.params);
        }
        //没有全局，使用继承的item
        else {
            const item = node.getComponent(ScrollListItem);
            if (item) {
                item.onItemRender(this._dataArr[newIndex], newIndex, this.params);
            }
        }

        this.setPos(node, newIndex);
    }

    /**设置坐标*/
    private setPos(node: Node, index: number) {
        let pos = this.countPosByIndex(index);
        if (this._direction == SCROLL_HORIZONTAL) {
            node.setPosition(new Vec3(pos, 0));
        } else {
            node.setPosition(new Vec3(0, -pos));
        }
    }

    /**根据下标计算坐标。 0 ~ length-1*/
    private countPosByIndex(index: number): number {
        let pos = (1 / 2 + index) * this._itemSize;
        //前面距离边框
        if (this._gapNum && this._gapNum[0]) {
            pos += this._gapNum[0];
        }
        //间隙距离
        if (this._gapNum && this._gapNum[2]) {
            pos += this._gapNum[2] * index;
        }
        return pos;
    }

    /**滚动到指定下标*/
    public scroll2Index(index: number) {
        this.stopAutoScroll();
        //太靠近结束点，需要回退屏幕显示数量
        if (index > this._dataArr.length - this._numItem - 2) {
            index = this._dataArr.length - this._numItem - 2;
        }
        if (index < 0) {
            index = 0;
        }

        /**设置滚动坐标*/
        let pos = this.countPosByIndex(index) - (1 / 2) * this._itemSize;
        let ve = new Vec2(0, -pos);
        if (this._direction == SCROLL_HORIZONTAL) {
            ve = new Vec2(pos, 0);
        }
        this.scrollToOffset(ve, 0.5); //滚动

        for (let x = 0; x < this._itemArr.length; x++) {
            this.itemRender(this._itemArr[x], index + x);
        }

        this._dataIndex = this._itemArr.length - 1 + index; //数据下标
        this._itemIndex = this._itemArr.length - 1; //重新赋值后节点下标为数组内当前最大
    }
}
