import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
//属性延迟
class LazyProperty(val initializer: () -> Int) {
    var value:Int?=null
    val lazy: Int
        get() {
            if (value==null) {
                value = initializer()
            }
            return value!!
        }

    val lazyValue: Int by lazy(initializer)
}

//属性代理
class D {
    var date: MyDate by EffectiveDate()
}

class EffectiveDate<R> : ReadWriteProperty<R, MyDate> {

    var timeInMillis: Long? = null

    override fun getValue(thisRef: R, property: KProperty<*>): MyDate {
        println("getValue----$timeInMillis")
        return timeInMillis!!.toDate()
    }

    override fun setValue(thisRef: R, property: KProperty<*>, value: MyDate) {
        timeInMillis=value.toMillis()
        println("setValue----$timeInMillis")
    }
}

fun MyDate.toMillis(): Long {
    val c = Calendar.getInstance()
    c.set(year, month, dayOfMonth)
    return c.getTimeInMillis()
}

fun Long.toDate(): MyDate {
    val c = Calendar.getInstance()
    c.setTimeInMillis(this)
    return MyDate(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DATE))
}

//builder
fun buildString(build:StringBuilder.()->Unit):String{
    val s = StringBuilder()
    s.build()
    return s.toString()
}
fun <K,V>buildMap(build:HashMap<K,V>.()->Unit):Map<K,V>{
    val map=HashMap<K,V>()
    map.build()
    return map
}

//apply
fun createString(): String {
    return StringBuilder().myApply {
        append("Numbers: ")
        for (i in 1..10) {
            append(i)
        }
    }.toString()
}
fun createMap(): Map<Int, String> {
    return hashMapOf<Int, String>().myApply {
        put(0, "0")
        for (i in 1..10) {
            put(i, "$i")
        }
    }
}

//作用域函数
fun <T> T.myApply(f: T.() -> Unit): T {
    f()
    return this
}
fun <T> T.myAlso(f: (T) -> Unit):T{
    f(this)
    return this
}

fun <T,R> T.myLet(f: (T) -> R):R{
  return f(this)
}
fun <T,R> T.myRun(f: T.() -> R):R{
  return f()
}

fun main(){

    val l=LazyProperty{3}
    println(l.value)
    println(l.lazy)
    println(l.value)

    println(l.lazyValue)

    val d=D()
    d.date=MyDate(1,2,3)
    println(d.date)

    println(buildString {
        append("Numbers: ")
        for (i in 1..10) {
            append(i)
        }
    })
    println(createString())

    println(buildMap<Int,String> {
        put(0, "0")
        for (i in 1..10) {
            put(i, "$i")
        }
    })
    println(createMap())
    println("----------")

    println("Hello World--apply".myApply { println(this)})
    println( "Hello World--also".myAlso { println(it)})

    println( "Hello World--run".myRun { println(this)})
    println( "Hello World--let".myLet { println(it)})

    partitionWordsAndLines()
    partitionLettersAndOtherSymbols()

}

//泛型应用
fun <T,C:MutableCollection<T>> Collection<T>.partitionTo(first:C,second:C,predicate:(T)->Boolean):Pair<C,C> {
    for (element in this) {
        if (predicate(element)) first += element
        else second += element
    }
    return Pair(first, second)
}

fun partitionWordsAndLines() {
    val (words, lines) = listOf("a", "a b", "c", "d e")
        .partitionTo(ArrayList(),ArrayList()){ s -> !s.contains(" ") }
    check(words == listOf("a", "c"))
    check(lines == listOf("a b", "d e"))
    println(words)
    println(lines)
}

fun partitionLettersAndOtherSymbols() {
    val (letters, other) = setOf('a', '%', 'r', '}')
        .partitionTo(HashSet(),HashSet()){ c -> c in 'a'..'z' || c in 'A'..'Z' }
    check(letters == setOf('a', 'r'))
    check(other == setOf('%', '}'))
    println(letters)
    println(other)
}