/**构建内部DSL是Kotlin的一个突出特色，主要用到下列语言特性
 * 1.扩展函数、扩展属性
 * 2.带接收者的Lambda表达式与高阶函数
 * 3.中缀调用
 * 4.invoke约定
 */
import java.time.LocalDate
import java.time.Period

class A {
    fun function1() {
        function2()
    }

    fun function2() {
       println("function2 running......")
    }
}

// 扩展函数：限制函数的调用范围
fun A.function3() {
    function1()
    function2()
}

//带接收者的Lambda表达式：保证API中的嵌套关系
val receiver: A.(Int) -> Unit = {
    println("my age is $it")
}

//扩展属性
val Int.days:Period
    get() = Period.ofDays(this)
val Period.ago:LocalDate
    get() = LocalDate.now() - this

object 前
infix fun Int.天(ago:前) = LocalDate.now() - Period.ofDays(this)

//invoke约定
class X(val name:String){
    operator fun invoke(){
        println("my name is $name")
    }
}
class Y : (String) -> Unit {
    override fun invoke(str: String) {
        println(str)
    }
}

class Z{
    fun compile(coordinate:String){
        println("----- $coordinate-----")
    }
    operator fun invoke(block:Z.()->Unit){
        block()
    }
}

//为String扩展一个方法
inline operator fun String.invoke(block: (String) -> Unit) {
    block(this)
}
fun main(){
    //扩展函数
    val a = A()
    a.function1()
    a.function2()
    a.function3()

    //带接收者的Lambda表达式
    a.receiver(3)   //等同于receiver(a,3) 或 receiver.invoke(a,3)

    //扩展属性
    val yesterday = 1.days.ago
    println(yesterday)

    //中缀调用
    val yesterdayBefore= 2 天 前
    println(yesterdayBefore)

    //invoke约定：让对象像函数一样直接调用,调用时会执行invoke中的代码
    val x = X("Smith")
    x()

    val y = Y()
    y("Hello")

    val z = Z()
    z{
        compile("abc")
        compile("123")
    }

    "hello"{
        println("String Block: $it")
    }
    //综合示例
    val trip = trip {
        name = "Trip"
        address = " 上海市长宁区金钟路968号凌空SOHO"
        city = "北京、上海、西安、成都"
//      city{cname="北京、上海、西安、成都"}
        department {
            name = " 机票 "
            nameEn = "flight"

        }
        department {
            name = " 酒店 "
            nameEn = "hotel"
        }
        department {
            name = " 火车票 "
            nameEn = "train"
        }
    }
    trip culture "Customer、Teamwork、Respect、Integrity、Partner"
    println("result: $trip")
}

//明确哪些隐式接收者是同一个DSL的一部分，并且只允许调用最近层的接收者的成员
@DslMarker
annotation class TripDsl

data class Department(var name: String = "", var nameEn: String = "")
data class Trip(var name: String? = "", var address: String? = "", var departments: List<Department>? = mutableListOf(),
                var city: List<String>? = mutableListOf(), var culture: String? = "")
@TripDsl
class TripBuilder {
    var name: String? = ""
    var address: String? = ""
    var cities=listOf<String>()
    var city: String = ""

//    fun city(block:CityBuilder.() -> Unit) {
//        cities=CityBuilder().apply(block).build()
//    }

    var departments = mutableListOf<Department>()
    fun department(block: DepartmentBuilder.() -> Unit) {
        val departmentBuilder = DepartmentBuilder()
        block.invoke(departmentBuilder)   // 等同于 departmentBuilder.block() 或 block(departmentBuilder)
        departments.add(departmentBuilder.build())
        /*等效替换
          departments.add(DepartmentBuilder().apply(block).build()) */
    }

    fun build():Trip  {
        cities= city.split("、")
        return Trip(name, address, departments,cities)
    }
}

@TripDsl
class CityBuilder{
    var cname: String = ""
    fun build(): List<String> = cname.split("、")
}

@TripDsl
class DepartmentBuilder {
    var name: String = ""
    var nameEn: String = ""
    fun build(): Department = Department(name, nameEn)
}
fun trip(block: TripBuilder.() -> Unit) :Trip= TripBuilder().apply(block).build()

infix fun Trip.culture(culture: String) {
    this.culture = culture
}
