/*
*   任务队列管理器
*   1. 传入任务，进入队列顺序执行
*   2. 支持优先级（从小到大排序，priority越小优先级越高）
*   3. 支持队列Tag，允许多个互不影响的队列执行
*   4. 支持清理任务队列
*   5. 一个任务只能完成一次，避免代码的原因多次调用完成，导致后续任务提前执行
*
*   6. 调试模式下记录了每个Task添加时的堆栈，方便调试（可以快速查看哪个任务没有结束）
*   
*   2018-5-7 by 宝爷
*/


// 任务结束回调
export type TaskFinishCallback = () => void;
// 任务执行回调
export type TaskCallback = (TaskFinishCallback) => void;

class TaskInfo {
    public task: TaskCallback;
    public priority: number;
    public constructor(task: TaskCallback, priority: number) {
        this.task = task;
        this.priority = priority;
    }
}

export class TaskQueue {
    private _curTask: TaskInfo = null;
    private _taskQueue: TaskInfo[] = Array<TaskInfo>();

    // 添加一个任务，如果当前没有任务在执行，该任务会立即执行，否则进入队列等待
    public pushTask(task: TaskCallback, priority: number = 0): void {
        let taskInfo = new TaskInfo(task, priority);
        if (this._taskQueue.length > 0) {
            for (var i: number = this._taskQueue.length - 1; i >= 0; --i) {
                if (this._taskQueue[i].priority <= priority) {
                    this._taskQueue.splice(i + 1, 0, taskInfo);
                    return;
                }
            }
        }
        // 插到头部
        this._taskQueue.splice(0, 0, taskInfo);
        if (this._curTask == null) {
            this.executeNextTask();
        }
    }

    public clearTask(): void {
        this._curTask = null;
        this._taskQueue.length = 0;
    }

    private executeNextTask(): void {
        let taskInfo = this._taskQueue.shift() || null;
        this._curTask = taskInfo;
        if (taskInfo) {
            taskInfo.task(() => {
                if (taskInfo === this._curTask) {
                    this.executeNextTask();
                } else {
                    console.warn("your task finish twice!");
                }
            });
        }
    }
}

export class TaskManager {
    private static _instance: TaskManager = null;
    private _taskQueues: { [key: number]: TaskQueue } = {}

    public static getInstance(): TaskManager {
        if (!this._instance) {
            this._instance = new TaskManager();
        }
        return this._instance;
    }

    public static destory(): void {
        this._instance = null;
    }

    private constructor() {

    }

    public pushTask(task: TaskCallback, priority: number = 0): void {
        return this.getTaskQueue().pushTask(task, priority);
    }

    public pushTaskByTag(task: TaskCallback, tag: number, priority: number = 0): void {
        return this.getTaskQueue(tag).pushTask(task, priority);
    }

    public clearTaskQueue(tag: number = 0): void {
        let taskQueue = this._taskQueues[tag];
        if (taskQueue) {
            taskQueue.clearTask();
        }
    }

    public clearAllTaskQueue(): void {
        for (let queue in this._taskQueues) {
            this._taskQueues[queue].clearTask();
        }
        this._taskQueues = {}
    }

    private getTaskQueue(tag: number = 0): TaskQueue {
        let taskQueue = this._taskQueues[tag];
        if (taskQueue == null) {
            taskQueue = new TaskQueue();
            this._taskQueues[tag] = taskQueue;
        }
        return taskQueue;
    }
}

/* 测试用例：
* 1. 测试多个任务的执行顺序 + 优先级
* 2. 测试在执行任务的过程中动态添加新任务

export function testQueue() {
    let creatTask = (idx, pri): TaskCallback => {
        return (finish) => {
            console.log(`execute task ${idx} priority ${pri}`);
            finish();
        };
    };
    let tag = 0;
    let begin = (finish) => {
        for (var i = 0; i < 100; ++i) {
            let priority = 0;
            if (i % 10 == 0) {
                priority = -1;
            } else if (i == 88) {
                priority = 1;
            } else if (i == 22) {
                let task = creatTask(1.1, priority);
                TaskManager.getInstance().pushTaskByTag(task, tag, priority);
                task = creatTask(1.2, priority);
                TaskManager.getInstance().pushTaskByTag(task, tag, priority);
                task = creatTask(1.3, priority);
                TaskManager.getInstance().pushTaskByTag(task, tag, priority);
            } else if (i == 51 && tag == 2) {
                // 清理之后，添加的任务会立即执行...
                TaskManager.getInstance().clearTaskQueue(tag);
            }
            let task = creatTask(i, priority);
            Object.defineProperty(task, "idx", { value: i });
            TaskManager.getInstance().pushTaskByTag(task, tag, priority);
        }
        console.log("add task finish, start test");
        finish();
        // 测试重复调用结束
        finish();
        // tag为2时的finish两次都会报警告，因为begin已经被清理了
    }
    TaskManager.getInstance().pushTaskByTag(begin, tag);
    tag = 2;
    TaskManager.getInstance().pushTaskByTag(begin, tag);

}*/
