/**委托是为了集中统一管理接口方法的实现或属性的getter/setter。从而简化程序
 * 1.类委托:统一接口方法的实现，一次书写，多次使用
 * 2.属性委托：统一属性的getter/setter，一次获取，多次使用
 * 3.provideDelegate:方便在初始化时插入属性检查等各种业务逻辑
 */
import kotlin.properties.Delegates
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

fun main() {
    //class delegation。公共接口方法实现，一次书写，多次使用
    val tomAraya = TomAraya("Thrash Metal")
    tomAraya.makeSound()
    val elvisPresley = ElvisPresley("Dancin' to the Jailhouse Rock.")
    elvisPresley.makeSound()

    //property delegation，一次获取，多次使用
    val e = Example()
    println(e.p)
    e.p = "NEW"

    //lazy,只有getter，适合val
    println("-----------------Lazy------------------")
    val lazyValue: String by lazy {
        println("computed!")
        "Hello"
    }
        println(lazyValue)
        println(lazyValue)

    //observal
    println("-----------------Observal------------------")
    class User {
        var name: String by Delegates.observable("<no name>") {
                prop, old, new ->
            println("$old -> $new")
        }
        //有条件修改
        var age: Int by Delegates.vetoable(0) {
                prop, old, new ->
            print("$old -> $new,result:")
            new > old
        }
    }
    val user = User()
    user.name = "first"
    user.name = "second"
    user.age = 20
    println("age = ${user.age}")
    user.age = 30
    println("age = ${user.age}")
    user.age = 25
    println("age = ${user.age}")

    //Storing Properties in a Map
    println("----------------Storing Properties in a Map-----------------")
    class Student(val map: Map<String, Any?>) {
        val name: String by map
        val age: Int     by map
    }
    val student = Student(mapOf(
        "name" to "John Doe",
        "age"  to 25
    ))
    println(student.map)
    println(student.name) // Prints "John Doe"
    println(student.age)  // Prints 25

    //local delegation
    println("----------------local delegation-----------------")
    var name: String by MyDelegation()
    // 访问局部变量，实际上是调用MyDelegation对象的getValue()方法
    println(name)
    // 对局部变量赋值，实际上是调用MyDelegation对象的setValue()方法
    name = "新的值"
    println(name)

    //provideDelegate
    println("----------------provideDelegate-----------------")
    // 创建对象（初始化属性），调用委托工厂的provideDelegate()方法
    val pd = MyTarget()
    // 读取属性，实际上是调用属性的委托对象的getter()方法
    println(pd.name)
    // 写入属性，实际上是调用属性的委托对象的setter()方法
    pd.name = "fkit.org"
    println(pd.name)
}

//class delegation
interface SoundBehavior {
    fun makeSound()
}

class ScreamBehavior(val n:String): SoundBehavior {
    override fun makeSound() = println("${n.toUpperCase()} !!!")
}

class RockAndRollBehavior(val n:String): SoundBehavior {
    override fun makeSound() = println("I'm The King of Rock 'N' Roll: $n")
}
class TomAraya(n:String): SoundBehavior by ScreamBehavior(n)
class ElvisPresley(n:String): SoundBehavior by RockAndRollBehavior(n)

//property delegation
class Example {
    var p: String by Delegate()                                               // 1

    override fun toString() = "Example Class"
}
class Delegate {
    operator fun getValue(thisRef: Any?, prop: KProperty<*>): String {        // 2
        return "$thisRef, thank you for delegating '${prop.name}' to me!"
    }

    operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) { // 2
        println("$value has been assigned to ${prop.name} in $thisRef")
    }
}
//local delegation
class MyDelegation{
    private var _backValue = "默认值"
    operator fun getValue(thisRef: Nothing?, property: KProperty<*>): String {
        println("${thisRef}的${property.name}属性执行getter方法")
        return _backValue
    }
    operator fun setValue(thisRef: Nothing?, property: KProperty<*>, newValue: String) {
        println("${thisRef}的${property.name}属性执行setter方法" +
                "，传入参数值为：${newValue}")
        _backValue = newValue
    }


}

//provideDelegate
class MyTarget{
    // 该属性的委托是MyDelegation对象
    var name: String by PropertyChecker()
}
class PropertyChecker {
    operator fun provideDelegate(thisRef: MyTarget,
                                 prop: KProperty<*>): ReadWriteProperty<MyTarget, String> {
        // 插入自定义代码，可执行任意业务操作
        checkProperty(thisRef, prop.name)
        // 返回实际的委托对象
        return RealDelegation()
    }
    private fun checkProperty(thisRef: MyTarget, name: String) {
        println(" ----- 检查属性  ----$name")
    }
}
class RealDelegation: ReadWriteProperty<MyTarget, String> {
    private var _backValue = "默认值"
    override operator fun getValue(thisRef: MyTarget, property: KProperty<*>): String {
        println("${thisRef}的${property.name}属性执行getter方法")
        return _backValue
    }
    override operator fun setValue(thisRef: MyTarget, property: KProperty<*>, value: String) {
        println("${thisRef}的${property.name}属性执行setter方法" +
                "，传入参数值为：${value}")
        _backValue = value
    }
}