/*
    通用listview，支持横向或者竖向滚动
    水平方向：content的锚点为(0, 0.5)
    垂直方向: content的锚点为(0.5, 1)
*/
cc.Class({
    extends: cc.Component,

    properties: {
        itemTemplate: { // item template to instantiate other items
            default: null,
            type: cc.Node,
            tooltip: "item模板",
        },
        scrollView: {
        	default: null,
            type: cc.ScrollView,
            tooltip: "滚动视图",
        },
        anotherNum : {
            default: 1,
            tooltip: "另一个方向上的并列数",
        },
        anotherSpacing: {
            default: 0,
            tooltip: "另一个方向上的间隔",
        },
        spacing: 0, // space between each item
        appointItemCount: 0, // 指定实际创建的item数量
    },

    // 初始化数据
    initData: function() {
        this.content = this.scrollView.content; // item父节点
        this.totalCount = 0; // item总数量
        this.items = []; // 实际实例化的item
        this.itemsIndex = []; // 记录每个item当前的索引
        this.lastContentPos = 0; // use this variable to detect if we are scrolling up or down

        this.updateTimer = 0; // 更新计时
        this.updateInterval = 0.2;  // 更新间隔

        this.itemTemplate.active = false;

        this.recordItemSize();
        this.adjustContentSize();

        this.createItems();
    },
    // 得到滚动方向上的并列数
    getActualIndex: function(count) {
        if (count == undefined) {
            count = this.totalCount;
        }
        return Math.ceil(count / this.anotherNum);
    },
    // 得到非滚动方向上的并列数
    getAnotherActualIndex: function(count) {
        if (count == undefined) {
            count = this.totalCount;
        }
        let col = count - (this.getActualIndex(count) - 1) * this.anotherNum;
        return col;
    },

    // 调整content大小，水平方向调整宽度，垂直方向调整高度
    adjustContentSize: function() {
        let size = this.getActualIndex() * (this.itemSize + this.spacing) + this.spacing;
        this.content[this.direction] = size;
        this.content[this.anotherDirection] = this.anotherNum * (this.anotherItemSize + this.anotherSpacing) + this.anotherSpacing;
    },
    // 记录item的大小
    recordItemSize: function() {
        let item = cc.instantiate(this.itemTemplate);
        if (this.scrollView.horizontal) {
            this.itemSize = item.width; // item单位尺寸
            this.anotherItemSize = item.height;
            this.direction = "width"; // 
            this.anotherDirection = "height";
            this.content.anchorX = 0;
            this.content.anchorY = 0.5;
        }else {
            this.itemSize = item.height;
            this.anotherItemSize = item.width;
            this.direction = "height";
            this.anotherDirection = "width";
            this.content.anchorX = 0.5;
            this.content.anchorY = 1;
        }
    },
    // 创建能够铺满屏幕的item集合
    createItems: function() {
        let view = this.content.parent;
        let viewSize = view[this.direction];
        let oneSize = this.itemSize + this.spacing;
        let needItemCount = Math.round(viewSize / oneSize + 0.5) + 4;
        needItemCount *= this.anotherNum;
        if (this.appointItemCount > 0) {
            needItemCount = this.appointItemCount;
        }
        for (let i = 0; i < needItemCount; i++) {
            let item = cc.instantiate(this.itemTemplate);
            this.updateItemData(item, i);
            this.content.addChild(item);
            this.setItemPosByIndex(item, i);
            this.items.push(item);
            this.itemsIndex[i] = i;
        }

        this.minIndex = 0; // 最上边或者最左边的item的索引
        this.maxIndex = needItemCount - 1; // 最下边或者最右边的item的索引
    },
    // 根据item索引设置item的位置
    setItemPosByIndex: function(item, index) {
        let actualIndex = this.getActualIndex(index + 1) - 1;
        let anotherActualIndex = this.getAnotherActualIndex(index + 1) - 1;
        let pos = item[this.direction] * (0.5 + actualIndex) + this.spacing * (actualIndex + 1);
        let anotherPos = item[this.anotherDirection] * (0.5 + anotherActualIndex) + this.anotherSpacing * (anotherActualIndex + 1);
        if (this.direction == "height") {
            item.x = anotherPos - this.content.width / 2;
            item.y = -pos;
        }else {
            item.x = pos;
            item.y = -anotherPos + this.content.height / 2;
        }
    },

    // 插入一个item pos: 0 ~ this.totalCount
    insertItem: function(pos) {
        if (pos == undefined) {
            pos = this.totalCount;
        }else if (pos < 0) {
            pos = 0;
        }else if (pos > this.totalCount) {
            pos = this.totalCount;
        }
        this.totalCount++;
        this.adjustContentSize(); // 首先调整content的大小

        for (let i = 0; i < this.items.length; i++) {
            if (this.itemsIndex[i] >= pos) { // 位置不变，更新item数据
                this.updateItemData(this.items[i], this.itemsIndex[i]);
            }
        }
    },

    // 删除一个item pos: 0 ~ this.totalCount - 1
    deleteItem: function(pos) {
        if (this.totalCount <= 0) {
            return;
        }
        if (pos == undefined) {
            pos = this.totalCount - 1;
        }else if (pos < 0) {
            pos = 0;
        }else if (pos > this.totalCount) {
            pos = this.totalCount - 1;
        }

        this.totalCount--
        this.adjustContentSize(); // 首先调整content的大小

        for (let i = 0; i < this.items.length; i++) {
            if (this.itemsIndex[i] >= pos) { // 位置不变，更新item数据
                this.updateItemData(this.items[i], this.itemsIndex[i]);
            }
        }
    },
    // 删除所有item
    removeAllItems: function() {
        this.scrollView.stopAutoScroll();
        this.totalCount = 0;
        this.adjustContentSize(); // 首先调整content的大小
        for (let i = 0; i < this.items.length; i++) {
            this.updateItemData(this.items[i], this.itemsIndex[i]);
        }
    },

    // 更新item数据
    updateItemData: function(item, index) {
        let self = this;
        if (index >= 0 && index < this.totalCount) {
            item.active = true;
            if (this.updateItem) {
                this.updateItem(item, index, self.getActualIndex(index + 1) - 1, self.getAnotherActualIndex(index + 1) - 1);
            }
        }else {
            item.active = false;
            if (this.clearItem) {
                this.clearItem(item, index, self.getActualIndex(index + 1) - 1, self.getAnotherActualIndex(index + 1) - 1);
            }
        }
    },

    // 设置item更新函数 func(item, idnex)
    setItemUpdateFunc: function(func) {
        this.updateItem = func;
    },

    onLoad: function() {
        this.initData();
    },

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

    // 判断listview是否在往下或者往右滚动
    getScrollingDirection: function() {
        if ("height" == this.direction) {
            return this.content.y < this.lastContentPos;
        }else {
            return this.content.x > this.lastContentPos;
        }
    },

    // 更新上次content位置
    updateLastContentPos: function() {
        if ("height" == this.direction) {
            this.lastContentPos = this.content.y;
        }else {
            this.lastContentPos = this.content.x;
        }
    },

    update: function(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.content.parent[this.direction] / 2 + this.itemSize + this.spacing;
        let isDown = this.getScrollingDirection(); // scrolling direction
        let offset = (this.itemSize + this.spacing) * this.getActualIndex(items.length);

        while(true) {
            let isDone = true;
            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 ((!this.scrollView.horizontal && viewPos.y < -buffer && items[i].y + offset < 0) ||
                    (this.scrollView.horizontal && viewPos.x > buffer && items[i].x - offset > 0)) {
                        // 最下边的放到最上边去
                        this.maxIndex--;
                        this.minIndex--;
                        this.itemsIndex[i] = this.minIndex;
                        this.setItemPosByIndex(items[i], this.minIndex);
                        this.updateItemData(items[i], this.minIndex);
                        isDone = false;
                    }
                } else {
                    // if away from buffer zone and not reaching bottom of content
                    if ((!this.scrollView.horizontal && viewPos.y > buffer && items[i].y - offset > -this.content.height) ||
                    (this.scrollView.horizontal && viewPos.x < -buffer && items[i].x + offset < this.content.width)) {
                        // 把最上边的放到最下边去
                        this.minIndex++;
                        this.maxIndex++;
                        this.itemsIndex[i] = this.maxIndex;
                        this.setItemPosByIndex(items[i], this.maxIndex);
                        this.updateItemData(items[i], this.maxIndex);
                        isDone = false;
                    }
                }
            }

            if (isDone) {
                break;
            }
        }
        this.updateLastContentPos();
    },


    /******************************************************************************** */
    

    scrollEvent: function(sender, event) {
        switch(event) {
            case 0: 
               //this.lblScrollEvent.string = "Scroll to Top"; 
               break;
            case 1: 
               //this.lblScrollEvent.string = "Scroll to Bottom"; 
               break;
            case 2: 
               //this.lblScrollEvent.string = "Scroll to Left"; 
               break;
            case 3: 
               //this.lblScrollEvent.string = "Scroll to Right"; 
               break;
            case 4: 
               //this.lblScrollEvent.string = "Scrolling"; 
               break;
            case 5: 
               //this.lblScrollEvent.string = "Bounce Top"; 
               break;
            case 6: 
               //this.lblScrollEvent.string = "Bounce bottom"; 
               break;
            case 7: 
               //this.lblScrollEvent.string = "Bounce left"; 
               break;
            case 8: 
               //this.lblScrollEvent.string = "Bounce right"; 
               break;
            case 9: 
               //this.lblScrollEvent.string = "Auto scroll ended"; 
               break;
        }
    },

    addItem: function() {
        this.insertItem();
    },
    
    removeItem: function() {
        this.deleteItem(this.totalCount - 1);
    },
});
