declare interface Array<T> {
    /**
     * 移除一個值並且回傳
     * @param index
     */
    ExRemoveAt(index: number): T;
    /**
     * 移除全部值(注意. 參考的也會被清空)
     * @example
     *
     *  let bar: number[] = [1, 2, 3];
     *  let bar2: number[] = bar;
     *  bar.Clear();
     *  console.log(bar, bar2);
     *
     *  // {
     *  //     "bar": [],
     *  //     "bar2": []
     *  // }
     */
    Clear(): void;
    /**
     * 物件陣列排序,asc&key陣列長度請一樣
     * PS. boolean 帶false是先true在false
     * @link JavaScript Object 排序 http://www.eion.com.tw/Blogger/?Pid=1170#:~:text=JavaScript%20Object%20排序
     * @param asc 是否升序排列(小到大)
     * @param key 需排序的key(優先順序左到右)(沒有就放空)
     */
    ObjectSort(asc?: boolean[], key?: string[]): any[];
    /**
     * 設計給Array<cc.Component.EventHandler>forHoldButton使用
     * Add a non persistent listener to the UnityEvent.
     * @param call Callback function.
     */
    AddListener(call: Function): void;
}

Array.prototype.ExRemoveAt || Object.defineProperty(Array.prototype, "ExRemoveAt", {
    enumerable: false,
    value: function (index: number): any {
        let item: any = this.splice(index, 1);
        return item[0];
    }
});

Array.prototype.Clear || Object.defineProperty(Array.prototype, "Clear", {
    enumerable: false,
    value: function (): void {
        this.length = 0;

        // let foo: number[] = [1, 2, 3];
        // let bar: number[] = [1, 2, 3];
        // let foo2: number[] = foo;
        // let bar2: number[] = bar;
        // foo = [];
        // bar.length = 0;
        // console.log(foo, bar, foo2, bar2);

        // {
        //     "foo": [],
        //     "bar": [],
        //     "foo2": [
        //       1,
        //       2,
        //       3
        //     ],
        //     "bar2": []
        // }
    }
});

Array.prototype.ObjectSort || Object.defineProperty(Array.prototype, "ObjectSort", {
    enumerable: false,
    /**
     * @param asc 是否升序排列(小到大)
     * @param key 需排序的key(優先順序左到右)(沒有就放空)
     */
    value: function (asc: boolean[] = [true], key?: string[]): any[] {
        if (this.length === 0) {
            return this;
        } else if (!key || key.length === 0) {
            console.error(`ObjectSort key error`);
            return this;
        } else if (asc.length !== key.length) {
            console.error(`ObjectSort key asc error asc.length: ${asc.length}, key.length: ${key.length}`);
            return this;
        }
        for (let i: number = 0; i < key.length; i++) {
            const keyname: string = key[i];
            if (this[0][keyname] === undefined) {
                console.error(`ObjectSort has not key[${i}]: ${keyname}`);
                return this;
            }
        }
        let count: number = key ? key.length : 1;
        let arr: any[];
        for (let i: number = count - 1; i >= 0; i--) {
            arr = this.sort(function (a: any, b: any): 1 | -1 {
                let mya: any = a;
                let myb: any = b;
                if (key) {
                    mya = a[key[i]];
                    myb = b[key[i]];
                }

                // 加個等於數字相同不要再去排序到
                if (asc[i]) {
                    return mya >= myb ? 1 : -1;
                } else {
                    return mya <= myb ? 1 : -1;
                }
            });
        }
        return arr;
    }
});

Array.prototype.AddListener || Object.defineProperty(Array.prototype, "AddListener", {
    enumerable: false,
    value: function (call: Function): void {
        let EventHandler: cc.Component.EventHandler = new cc.Component.EventHandler();
        EventHandler.target = <any>"Callback";
        EventHandler.component = "Callback";
        EventHandler.handler = <any>call;
        this.push(EventHandler);
    }
});