import { _decorator, Component, Node, ScrollView } from 'cc';
import { YXCollectionView, YXFlowLayout, YXIndexPath } from '../lib';
const { ccclass, property } = _decorator;

/**
 * 基于 YXCollectionView 和 YXFlowLayout 封装的一个简单的 PageView
 * 请注意，这个组件更多是为了演示如何基于 YXCollectionView 来实现 PageView 相关的需求，并非完整的功能组件
 * 如果这个组件符合业务的话可以直接拿来用，如果满足不了需求，可以根据实际业务，选择开放更多的配置或者直接使用 YXCollectionView
 * 
 * ---
 * 此组件说明
 * - 支持一般的 PageView 业务
 * - 演示了如何封装页面变化事件
 */
@ccclass('YXPageView')
export class YXPageView extends Component {

    /**
     * 监听页面变化事件
     * 在滚动过程实时的检查页面变化
     */
    static PAGE_CHANGE_EVENT1 = `YXPageView.PAGE_CHANGE_EVENT1`

    /**
     * 监听页面变化事件
     * 仅在滚动结束的时候去检查页面变化
     */
    static PAGE_CHANGE_EVENT2 = `YXPageView.PAGE_CHANGE_EVENT2`

    /**
     * 列表组件
     */
    private collectionView: YXCollectionView = null

    /**
     * 滚动方向
     */
    @property({ tooltip: `滚动方向`, type: YXCollectionView.ScrollDirection, visible: true })
    private _scrollDirection: YXCollectionView.ScrollDirection = YXCollectionView.ScrollDirection.HORIZONTAL

    set scrollDirection(value: YXCollectionView.ScrollDirection) {
        this.collectionView.scrollDirection = value
        this.collectionView.reloadData()
    }

    get scrollDirection(): YXCollectionView.ScrollDirection {
        return this.collectionView.scrollDirection
    }

    /**
     * 是否允许手势滚动
     * 关闭的话可以禁掉手势滚动业务，但仍然可以通过代码切换页面
     */
    @property({ tooltip: `是否允许手势滚动`, visible: true })
    private _scrollEnabled: boolean = true

    set scrollEnabled(value: boolean) {
        this.collectionView.scrollEnabled = value
    }

    get scrollEnabled(): boolean {
        return this.collectionView.scrollEnabled
    }

    /**
     * 保存所有的页面
     */
    private pages: Node[] = []

    /**
     * 获取所有页面
     * @returns 
     */
    getPages(): Node[] {
        return this.pages
    }

    /**
     * 新增页面到尾部
     * @param page 
     */
    addPage(page: Node) {
        this.pages.push(page)
        this._late_update_pages = true
    }

    /**
     * 获取当前页面索引
     * @returns 
     */
    getCurrentPageIndex(): number {
        if (this.collectionView.scrollDirection == YXCollectionView.ScrollDirection.HORIZONTAL) {
            let offset = this.collectionView.scrollView.getScrollOffset()
            offset.x = - offset.x
            let idx = Math.round(offset.x / this.collectionView.scrollView.view.width)
            return idx
        }
        if (this.collectionView.scrollDirection == YXCollectionView.ScrollDirection.VERTICAL) {
            let offset = this.collectionView.scrollView.getScrollOffset()
            let idx = Math.round(offset.y / this.collectionView.scrollView.view.height)
            return idx
        }
        return null
    }

    /**
     * 设置当前要显示的页面
     * 也可以视作 scrollToPage 方法
     * @param index 
     * @param timeInSecond 
     */
    setCurrentPageIndex(index: number, timeInSecond: number = 0) {
        let indexPath = new YXIndexPath(0, index)
        this.collectionView.scrollTo(indexPath, timeInSecond)
    }

    /**
     * 插入一个新页面
     * @param page 
     * @param index 
     */
    insertPage(page: Node, index: number) {
        this.pages.splice(index, 0, page)
        this._late_update_pages = true
    }

    /**
     * 移除指定页面
     * @param page 
     * @returns 
     */
    removePage(page: Node) {
        for (let index = 0; index < this.pages.length; index++) {
            let node = this.pages[index]
            if (page === node) {
                this.removePageAtIndex(index)
                return
            }
        }
    }

    /**
     * 移除指定页面
     * @param index 
     */
    removePageAtIndex(index: number) {
        this.pages.splice(index, 1)
        this._late_update_pages = true
    }

    /**
     * 移除所有页面
     */
    removeAllPages() {
        this.pages = []
        this._late_update_pages = true
    }

    /**
     * 立即更新当前页面
     */
    markForUpdatePages() {
        this.collectionView.reloadData()
        this.onScrolling()
        this.onScrollEnded()
    }

    protected onLoad(): void {
        this.collectionView = this.node.getComponent(YXCollectionView) || this.node.addComponent(YXCollectionView)

        this.collectionView.recycleInterval = 0
        this.collectionView.scrollEnabled = this._scrollEnabled
        this.collectionView.scrollDirection = this._scrollDirection
        this.collectionView.numberOfItems = () => this.pages.length
        this.collectionView.register(`cell`, () => {
            let result = new Node(`yx-page`)
            result.layer = this.collectionView.node.layer
            return result
        })
        this.collectionView.onCellDisplay = (cell, indexPath, collectionView) => {
            cell.removeAllChildren()
            let page = this.pages[indexPath.item]
            page.parent = cell
        }

        let layout = new YXFlowLayout()
        layout.pagingEnabled = true
        layout.itemSize = () => this.collectionView.scrollView.view.contentSize
        this.collectionView.layout = layout

        this.collectionView.node.on(ScrollView.EventType.SCROLLING, () => {
            this.onScrolling()
        })
        this.collectionView.node.on(ScrollView.EventType.SCROLL_ENDED, () => {
            this.onScrollEnded()
        })
    }

    protected onDestroy(): void {
        this.pages = []
    }

    private _late_update_pages: boolean = false
    protected update(dt: number): void {
        if (this._late_update_pages) {
            this._late_update_pages = false
            this.collectionView.reloadData()
            this.onScrolling()
            this.onScrollEnded()
        }
    }

    private currentPageForOnScrolling: number = null
    private onScrolling() {
        let getCurrentPageIndex = this.getCurrentPageIndex()
        if (this.currentPageForOnScrolling != getCurrentPageIndex) {
            this.currentPageForOnScrolling = getCurrentPageIndex
            this.node.emit(YXPageView.PAGE_CHANGE_EVENT1, this.currentPageForOnScrolling)
        }
    }

    private currentPageForOnScrollEnded: number = null
    private onScrollEnded() {
        let getCurrentPageIndex = this.getCurrentPageIndex()
        if (this.currentPageForOnScrollEnded != getCurrentPageIndex) {
            this.currentPageForOnScrollEnded = getCurrentPageIndex
            this.node.emit(YXPageView.PAGE_CHANGE_EVENT2, this.currentPageForOnScrollEnded)
        }
    }
}

