//導入框架,所有Cocoa框架都已經封裝過了
import Cocoa

//基本變量
func variableTest(){
    //在調用變量時,如果 variable?.doSomeThing()中variable為nil,則返回nil,否則展開調用返回調用結果
    //由于這個原因,在swift中應該是沒有基本類型了,比如int,bool,char *等等
    var variable:Int? = 2
    variable = nil
    
    var variable2:Bool = true
    variable2 = true
    
    enum Rank: Int{
        case Ace = 1
        case Two, Three, Four, Five, Six,
        Seven,
        Eight, Nine, Ten
        case Jack, Queen, King
        
        func description()->String{
            switch self{
            case .Ace:
                return "ace"
            case .Jack:
                return "Jack"
            case .King:
                return "King"
            case .Queen:
                return "Queen"
            default:
                return String (self.toRaw())
            }
        }
    }
    
    let ace = Rank.Ace
    let aceRawValue = ace.toRaw()
    ace.description()
    
    if let convertedRank = Rank.fromRaw(3){
        let threeDescription = convertedRank.description()
    }
}
variableTest();


//自定義類型
func selfDefinitionTypeTest(){
    var str = "Hello, playground"
    var equivalentEmptyArray = Array<Int>()
    equivalentEmptyArray += 4;
    
    struct MyType: Printable {
        var name = "Untitled"
        var description: String {  //默認的描述函數,打印的時候用
        return "MyType: \(name)"
        }
    }
    let value = MyType()
    println("Created a \(value)")
    
    struct MyType2: DebugPrintable {
        var name = "Untitled"
        var debugDescription: String {
        return "MyType: \(name)"
        }
    }
    let value2 = MyType2()
}
selfDefinitionTypeTest();


//元組,C++ 中std::tuple<T>, python內核類型
func tupleTest(){
    func tuple() -> (Double, Double, Double){
        return (5, 2, 7);
    }
    //這樣接收返回值的
    var (a,b,c) = tuple()
    a
    b
    c
    //也可以這樣,然后用數字索引
    var ret = tuple()
    ret.0
    ret.1
    ret.2
}
tupleTest();


//模板測試
func templateTest(){
    struct TmpVar<T>{
        var integer = 2
        var string = "let's have a talk"
        init(var integer:Int){
            self.integer = integer
        }
    }
    
    func mySort< T > (var array:Array<TmpVar<T>>) -> Array<TmpVar<T>>{
        for x in 0 .. array.count-1 {
            if array[x].integer > array[x+1].integer {
                swap(&array[x], &array[x+1])
            }
        }
        return array
    }
    
    var myArray = [TmpVar<Int>(integer: 3), TmpVar(integer:102), TmpVar(integer:100)]
    var anotherArray = mySort(myArray)
    for x in anotherArray {
        print(x.integer)
    }
}
templateTest();


func ffpTest(){
    //函數式編程,
    //函數內嵌函數,改變外部值
    func returnFifteen() -> Int{
        var y = 10
        func add5(){
            y += 5
        }
        add5()
        return y
    }
    returnFifteen()
    
    func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
        func stepForward(input: Int) -> Int { return input + 1 }
        func stepBackward(input: Int) -> Int { return input - 1 }
        return backwards ? stepBackward : stepForward
    }
    var currentValue = -4
    let moveNearerToZero = chooseStepFunction(currentValue > 0)
    // moveNearerToZero now refers to the nested stepForward() function
    while currentValue != 0 {
        println("\(currentValue) ")
        currentValue = moveNearerToZero(currentValue)
    }
    println("zero!")
    //摘錄來自: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/us/jEUH0.l
    
    //函數返回函數
    func makeIncrementer() ->
        Double->Int{  //實際上是(Double)->Int,也就是一個函數
        func addOne(number:Double)->Int{
            return 1 + Int(number);
        }
        return addOne;
    }
    
    var increment = makeIncrementer()
    increment(7.0);
    
    func closuerTest(){
        var list:Int[] = [1,2,3]
        func hasAnyMatched(#list:Int[],  //#符號表示這個表量和外部的變量是同一個變量
            var/*表示函數內部可以改變這個值,沒有var相當于const*/
            Condition/*第二參數名*/ condition:Int->Bool) -> Bool{
            for item in list{
                if condition(item){
                    return true;
                }
            }
            return false
        }
        
        var numbers = [20, 19, 7, 12]
        var condition = { number in number < 10}
        var match = hasAnyMatched(numbers, condition)
        match
        
        numbers.map({
            (number:Int)->Int in
            return 3*number
            })
        //閉包的類型已知,不用給出參數類型,返回類型,簡化版:
        var mappedValue = numbers.map({number in number+3})
        mappedValue
        numbers
    }
    closuerTest();
}
ffpTest();


//擴展類型
//
protocol定義和擴展只能放在全局文件中
protocol Nothing{
}
extension Int{
    var simpleDescription:String{
        return "The number \(self)"
    }
    mutating func adjust(){
        self += 42
    }
}

func extensionTest(){
    var number = 7
    number.adjust()
    number.simpleDescription
}
extensionTest();


//In-Out Parameters
func In_Out_Parameters(){
    func swapTwoInts(inout a: Int, inout b: Int) {
        let temporaryA = a
        a = b
        b = temporaryA
    }
    
    var someInt = 3
    var anotherInt = 5
    
    swapTwoInts(&someInt, &anotherInt)
    someInt
    anotherInt
}
In_Out_Parameters();


//閉包
/*

Closure expression syntax has the following general form:

{ (parameters) -> return type in
    statements
}
*/
func ClosureTest(){
    var names = ["He", "Qinglong"]
    //傳入一個閉包作為排序的條件函數
    var reversed = sort(names,  { (s1: String, s2: String) -> Bool in return s1 > s2 } )
    
    //由于sort的輸入參數中,第一個參數的類型可以推導,所以閉包的參數類型也可以被推導出來,因此可以簡寫為:
    reversed = sort(names, {s1, s2 in return s1 < s2})
    
    //更進一步,隱式的返回類型
    reversed = sort(names, {s1, s2 in s1 < s2})
    
    /*Swift automatically provides shorthand argument names to inline closures,
    which can be used to refer to the values of the closure’s arguments 
    by the names $0, $1, $2, and so on.
    
*/
    reversed = sort(names, {$0 > $1})
    
    //尾隨形式
    reversed = sort(names){ $0 > $1}
    //Here, $0 and $1 refer to the closure’s first and second String arguments
    
    /*Swift’s String type defines its string-specific implementation of the greater-than
    operator (>) as a function that has two parameters of type String,
    and returns a value of type Bool
    
*/
    reversed = sort(names, >)
    
    
    //尾隨形式的解釋:
    func someFunctionThatTakesAClosure(closure: () -> ()) {
        // function body goes here
    }
    
    // here's how you call this function without using a trailing closure:
    someFunctionThatTakesAClosure({
        // closure's body goes here
        })
    
    // here's how you call this function with a trailing closure instead:
    someFunctionThatTakesAClosure() {
        // trailing closure's body goes here
    }
    
    let digitNames = [
        0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
        5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine" ]
    let numbers = [16, 58, 510]
    
    let strings = numbers.map {
        (var number) -> String in
        var output = ""
        while number > 0 {
            output = digitNames[number % 10]! + output
            number /= 10
        }
        return output
    }
    strings
    // strings is inferred to be of type String[]
    // its value is ["OneSix", "FiveEight", "FiveOneZero"]
    
    
    //返回函數的函數
    func makeIncrementor(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementor() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementor
    }
}
ClosureTest();


//Type Methods,靜態成員函數
func typeMethodsTest(){
    //在類里面使用class聲明靜態成員方法
    class SomeClass {
        var xx:Int = 0  //目前為止,沒有實現類的靜態成員變量
        class func someTypeMethod() {
            // type method implementation goes here
        }
    }
    SomeClass.someTypeMethod()
    //在結構體里面使用static聲明靜態成員方法 和 靜態成員變量
    struct LevelTracker {
        static var highestUnlockedLevel = 1
        static func unlockLevel(level: Int) {
            if level > highestUnlockedLevel { highestUnlockedLevel = level }
        }
        static func levelIsUnlocked(level: Int) -> Bool {
            return level <= highestUnlockedLevel
        }
        var currentLevel = 1
        mutating func advanceToLevel(level: Int) -> Bool {
            if LevelTracker.levelIsUnlocked(level) {
                currentLevel = level
                return true
            } else {
                return false
            }
        }
    }
}
typeMethodsTest();


//class inheritance
func inheritance(){
    //Base lcass
    class Vehicle {
        var numberOfWheels: Int
        var maxPassengers: Int
        func description() -> String {
            return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"
        }
        init() {
            numberOfWheels = 0
            maxPassengers = 1
        }
    }
    
    class Car: Vehicle {
        var speed: Double = 0.0
        init() {
            super.init()
            maxPassengers = 5
            numberOfWheels = 4
        }
        override func description() -> String {
            return super.description() + "; "
                + "traveling at \(speed) mph"
        }
    }
    
    let car = Car()
    println("Car: \(car.description())")
    
    
    class SpeedLimitedCar: Car {
        override var speed: Double  {
            get {
                return super.speed
            }
            set {
                super.speed = min(newValue, 40.0)
            }
        }
        func subClassFunc(){
            println("我的青春我做主")
        }
        
        init(){}  //構造函數/初始器
        deinit{}  //析構函數/析構器
    }
    var normalCar:Car = Car()
    normalCar.speed = 100;
    var limitedCar = SpeedLimitedCar()
    
    normalCar = limitedCar
////    ((SpeedLimitedCar*)normalCar).subClassFunc();  //看來不能強制轉換基類到子類類型,應該和接口有關
}
inheritance();


//可選類型: ? 與 !
func optionalTest(){
    class Person {
        var residence: Residence?
        init(){}
    }
    
    class Residence {
        var numberOfRooms = 1
    }
    
    let john = Person()
    
    var xx:String?
    // ? 在residence為空的時候不會崩潰,返回的值是nil
    if let roomCount = john.residence?.numberOfRooms {
        xx = "John's residence has \(roomCount) room(s)."
    } else {
        xx = "Unable to retrieve the number of rooms."
    }
    println(xx?)
    
    // !在residence為空的時候會再這里崩潰
    // this triggers a runtime error
    let roomCount = john.residence!.numberOfRooms
    
}
optionalTest();