namespace Leaf {
    export interface PropertyDefination<T> {
        get?: (cache: PropertyCache<T>) => T
        set?: (value: T, cache: PropertyCache<T>) => void
        value?: T
    }
    export interface PropertyCache<T> {
        [index: string]: any
        value?: T
    }
    export class Property {
        static define<T>(who: any, name: string, def: PropertyDefination<T>): T {
            let cache: PropertyCache<T> = {}
            if (who[name]) cache.value = who[name]
            if (def.value) cache.value = def.value;
            let getFn = (cache: PropertyCache<T>) => {
                return cache.value
            }
            let setFn = (value: T, cache: PropertyCache<T>) => {
                cache.value = value
                return cache.value
            }
            let getIt = def.get || getFn
            let setIt = def.set || setFn
            Object.defineProperty(who, name, {
                get: () => {
                    return getIt(cache)
                },
                set: (v: T) => {
                    return setIt(v, cache)
                }
            })
            return def.value || null
        }
        static with(who: any) {
            return new WithProperty(who)
        }
    }
    export class WithProperty<T> {
        constructor(public who: any) {
        }
        public define<T>(name: string, def: PropertyDefination<T>) {
            Property.define<T>(this.who, name, def)
            return this
        }
    }
}
