/// <reference path="leaf.ts" />
namespace Leaf {
    export class Util {
        constructor() { }
        static clone<T>(obj: T): T {
            if (!obj) return obj
            if (obj instanceof Array) {
                return obj.map((item) => {
                    return Util.clone(item)
                }) as any as T
            }
            if (obj instanceof Date) {
                return obj as any as T
            }
            if (obj instanceof String) {
                return new String(obj) as any as T
            }
            if (typeof obj === "object") {
                let result: any = {}
                for (let prop in obj) {
                    result[prop] = this.clone(obj[prop] as any)
                }
                return result as any as T
            }
            return obj
        }
        static capitalize(str: string): string {
            if (!str) return str
            return str.charAt(0).toUpperCase() + str.slice(1)
        }
        static uncapitalize(str: string): string {
            if (!str) return str
            return str.charAt(0).toLowerCase() + str.slice(1)
        }
        static camelToSlug(str: string): string {
            if (!str) return str
            return str.replace(/[a-z][A-Z]/g, (match) => {
                return match[0] + "-" + match[1].toLowerCase()
            }).toLowerCase()
        }
        static slugToCamel(str: string): string {
            if (!str) return str
            return str.replace(/-[a-z]/ig, (match) => {
                return match.slice(1).toUpperCase()
            })
        }
        static deepEqual(a: any, b: any): boolean {
            if (a === b) return true
            if (typeof a !== typeof b) return false
            if (typeof a !== "object") return false
            if (a instanceof Array) {
                if (a.length != b.length)
                    return false
                for (let i = 0; i < a.length; i++) {
                    if (a[i] != b[i]) return false
                    return true
                }

            } else {
                let pas = Object.getOwnPropertyNames(a)
                let pbs = Object.getOwnPropertyNames(b)
                if (pas.length != pbs.length) {
                    return false
                }
                for (let i = 0; i < pas.length; i++) {
                    let key = pas[i]
                    if (a[key] != b[key]) return false
                }
                return true
            }
        }
        static arrayDiff<T>(arr1: T[] = [], arr2: T[] = [], identical?: (a: T, b: T) => boolean): {
            left: T[]
            right: T[]
            interact: T[]
        } {
            if (!identical) {
                identical = (a, b) => {
                    return a === b
                }
            }
            arr1 = arr1.slice()
            arr2 = arr2.slice()
            let interact: T[] = []
            for (let i = 0; i < arr1.length; i++) {
                for (let j = 0; j < arr2.length; j++) {
                    if (identical(arr2[j], arr1[i])) {
                        i--;
                        interact.push(arr1[i])
                        arr1.splice(i, 1)
                        arr2.splice(j, 1)
                        break;
                    }
                }
                if (!arr1[i]) break
            }
            return {
                left: arr1,
                right: arr2,
                interact
            }
        }
        static getBrowserInfo(): BrowserInfo {
            if (typeof navigator === "undefined") {
                return {
                    name: "None",
                    version: "None",
                    mobile: false
                }
            }
            let N = navigator.appName
            let ua = navigator.userAgent
            let M = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
            let tem = ua.match(/version\/([\.\d]+)/i)
            if (M && tem != null) {
                M[2] = tem[1]
            }
            M = M ? [M[1], M[2]] : [N, navigator.appVersion, '-?']
            return { name: M[0], version: M[1], mobile: Util.isMobile() }
        }

        static isMobile(): boolean {
            if (navigator && navigator.userAgent) {
                return (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i)) && true
            }
            else {
                return false
            }
        }
        static browser: BrowserInfo
    }
    export interface BrowserInfo {
        name: string
        version: string
        mobile: boolean
    }
    Property.define<BrowserInfo>(Util, "browser", {
        get: (cache) => {
            if (!cache.value) {
                cache.value = Util.getBrowserInfo()
            }
            return cache.value
        }
    })
}

