class ListViewAdapter {

    constructor(scrollView) {
        this.scrollView = scrollView;
        this.content = scrollView.content;
        this.items = []; // array to store spawned items
        this.dataList = [];
        // this.initialize();
        this.updateTimer = 0;
        this.updateInterval = 0.1;
        this.lastContentPosY = 0; // use this variable to detect if we are scrolling up or down
        this.spawnCount = 16;
        this.itemHeight = 0;
        this.bufferZone = 500;
        this.spacing = 25;
        this.scriptName = '';

        this.fuckingItem = null;
    }

    initialize(itemTemplate) {
        console.log(this.scriptName);
        let actualCount = this.dataList.length < this.spawnCount ? this.dataList.length : this.spawnCount;
        // let actualCount = this.dataList.length;
        this.items = [];
        this.content.removeAllChildren();
        for (let i = 0; i < actualCount; ++i) { // spawn items, we only need to do this once
            let item = cc.instantiate(itemTemplate);
            if (this.itemHeight === 0) {
                this.itemHeight = item.height; // get total content height
                this.content.height = (this.itemHeight + this.spacing) * this.dataList.length;
            }
            this.content.addChild(item);
            item.setPosition(0, -item.height * (0.5 + i) - this.spacing * (i + 1));
            item.getComponent(this.scriptName).setListViewAdapter(this);
            item.getComponent(this.scriptName).updateItem(this.dataList[i], i);
            this.items.push(item);
        }
    }

    getPositionInView(item) { // get item position in scrollview's node space
        let worldPos = item.parent.convertToWorldSpaceAR(item.position);
        let viewPos = this.scrollView.node.convertToNodeSpaceAR(worldPos);
        return viewPos;
    }

    update(dt) {
        this.updateTimer += dt;
        if (this.updateTimer < this.updateInterval) return; // we don't need to do the math every frame
        this.updateTimer = 0;
        let items = this.items;
        let buffer = this.bufferZone;
        let isDown = this.content.y < this.lastContentPosY; // scrolling direction

        let offset = (this.itemHeight + this.spacing) * items.length;

        for (let i = 0; i < items.length; ++i) {
            let viewPos = this.getPositionInView(items[i]);
            if (isDown) {
                // if away from buffer zone and not reaching top of content
                if (viewPos.y < -buffer && items[i].y + offset < 0) {
                    items[i].setPositionY(items[i].y + offset);
                    let item = items[i].getComponent(this.scriptName);
                    let itemId = item._itemId - items.length;
                    item.updateItem(this.dataList[itemId], itemId);
                }
            } else {
                // if away from buffer zone and not reaching bottom of content
                if (viewPos.y > buffer && items[i].y - offset > -this.content.height) {
                    items[i].setPositionY(items[i].y - offset);
                    let item = items[i].getComponent(this.scriptName);
                    let itemId = item._itemId + items.length;
                    item.updateItem(this.dataList[itemId], itemId);
                    if (itemId === (this.dataList.length - 1)) {
                        if (this.loadMore != undefined) {
                            this.loadMore();
                        }
                    }
                }
            }
        }
        // update lastContentPosY
        this.lastContentPosY = this.content.y;
    }

    updateItems(dataList, itemPrefab, scriptName) {
        this.scriptName = scriptName;
        this.itemTemplate = itemPrefab;
        this.dataList = dataList;
        this.initialize(itemPrefab);
    }

    addData(newdataList) {
        this.dataList = this.dataList.concat(newdataList);
        this.content.height = (this.itemHeight + this.spacing) * this.dataList.length; // get total content height
    }

    setLoadMoreCallBack(loadMore) {
        this.loadMore = loadMore;
    }

    playRemoveItemAnimation(itemScript, animCallback) {
        this.dataList.splice(itemScript._itemId, 1);
        this.content.height = (this.itemHeight + this.spacing) * this.dataList.length; // get total content height

        let sequ = cc.sequence(cc.moveBy(0.2, -750, 0), animCallback);
        itemScript.node.runAction(sequ);
    }

    updateItemsAndDataList(itemScript) {
        let index = itemScript._itemId;
        let items = this.items;

        if (this.dataList.length >= items.length) {
            itemScript.scheduleOnce(() => {
                itemScript.node.x = 0;
            }, 0.2);

            for (let i = 0; i < items.length; ++i) {
                let itemNode = items[i];
                let script = itemNode.getComponent(this.scriptName);
                let itemId = script._itemId;
                if (itemId < this.dataList.length) {
                    if (script._itemId > index) {
                        let finish = cc.callFunc(() => {
                            itemNode.y = itemNode.y - (this.itemHeight + this.spacing);
                            script.updateItem(this.dataList[itemId], itemId);
                        }, this);
                        let s = cc.sequence(cc.moveBy(0.2, 0, (this.itemHeight + this.spacing)), finish);
                        itemNode.runAction(s);
                    } else {
                        itemScript.scheduleOnce(() => {
                            script.updateItem(this.dataList[itemId], itemId);
                        }, 0.2);
                    }
                }
            }
        } else {

            for (let i = 0; i < items.length; ++i) {
                let itemId = items[i].getComponent(this.scriptName)._itemId;
                if (itemId === itemScript._itemId) {
                    this.items.splice(i, 1);
                }
            }

            for (let i = 0; i < items.length; ++i) {
                let itemNode = items[i];
                let script = itemNode.getComponent(this.scriptName);
                if (script._itemId > index) {
                    let newId = script._itemId - 1;
                    itemNode.runAction(cc.moveBy(0.2, 0, (this.itemHeight + this.spacing)));
                    script.updateItem(this.dataList[newId], newId);
                }
            }

            itemScript.node.destroy();
        }
    }

    removeItem(itemScript) {
        let finish = cc.callFunc(() => {
            this.updateItemsAndDataList(itemScript);
        });
        this.playRemoveItemAnimation(itemScript, finish);
    }

    onDestroy() {
        this.items = [];
        this.content.removeAllChildren();
    }
}
module.exports = ListViewAdapter;
