import Foundation
@testable import MyModule

func sayHello(person:String) -> String {
    return "Hello, \(capitalize(word:person)). \"How're are you doin\'?\""
}

func capitalize(#word:String) -> String {
    //TODO: test this
    return word.capitalizedString
}

sayHello("Toto")

var pi = 3.1415

var foo = cast as SomeType
var foo = optionalCast as? SomeType
var foo = forcedCast as! SomeType

func halfOpenRangeLength(start:Int, end:Int) -> Int {
    return end - start
}

halfOpenRangeLength(3, 8)

if let var = option {
    if more && complex, let optional = binding, example = here where option.foo == example.foo {
        // things
    }
}

func count(string:String) -> (vowels:Int, consonants:Int, others:Int) {
    var vowels = 0, consonants = 0, emoji = 0, whitespace = 0, others = 0

    for character in string {

        switch String(character).lowercaseString {
        case "a","o","i","u","e":
            ++vowels
        case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
            ++consonants
        //TODO: Add more emoji
        case "\u{1F604}":
            ++emoji
        case "\n", "\r", "\t", "\0", "\u{A0}", "\u{205F}":
            ++whitespace
        default:
            ++others
        }
    }

    return (vowels,consonants,others)
}

count(sayHello("John"))

// Unicode and Emoji support
let 😄face = "Happy Face"
let ქართულადაც = "This is Georgian"
let こんにちは = "...and Japanese"
let 𓂀 = "and hieroglyphs"

// Integer Literals
let decimalInteger = 1234567
let decimalIntegerWithGroupings = 1_234_567
let hexadecimalInteger = 0xABCDEF
let octalInteger = 0o0644
let binaryInteger = 0b1010

// Floating-Point Literals
let decimalFloatingPoint = 1234567.89
let decimalFloatingPointWithGroupings = 1_2345_67.89
let hexadecimalFloatingPoint = 0xA.1p-3

// String Literals
let string = "Hello, world!"
let multilineString = """
All human beings are born free and equal in dignity and rights.
They are endowed with reason and conscience
and should act towards one another in a spirit of brotherhood.
"""

func join(#firstString:String,#secondString:String,joiner:String = " & ") -> String {
    return "\(firstString)\(joiner)\(secondString)"
}

join(firstString: "Toto", secondString: "Someone Other", joiner: " + ")

func alignedRight(inout #string:String, count:Int, pad:Character) -> String {
    let amountToPad = count - countElements(string)

    for _ in 1...amountToPad {
        string = pad + string
    }

    return string;
}

/* This is a multiline comment
/*
This part is nested into the parent comment
*/
Trailing part of parent comment
*/

let thisIsNotAComment = true

/* Singleline Comment */

var textToAlign = "Toto"
alignedRight(string: &textToAlign, 10, "-")
textToAlign

//MARK: Function Types
func addToInts(a:Int,b:Int) -> Int {
    return a + b
}

let addNumbers: (Int,Int)->(Int) = addToInts;
addNumbers(3,2)

func printMathProblem(mathFunction:(Int,Int)->Int,a:Int,b:Int)->String {
    return "Result " + String(mathFunction(a,b))
}
printMathProblem(addNumbers, 5, 10)

// Function return types + Nested Functions
func chooseSteperFunction(backward:Bool) -> (Int) -> Int {
    func stepForward(input:Int)->Int {
        return input + 1
    }

    func stepBackward(input:Int)->Int {
        return input + 1
    }

    return backward ? stepBackward : stepForward
}
let currentValue = 5
chooseSteperFunction(currentValue > 0)(currentValue)

// Closures
func comparator(s1:String,s2:String)->Bool {
    return s2 > s1
}
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let revised = sorted(names, comparator)

let revised2 = sorted(names, {
    (s1:String,s2:String)->Bool in
        return s2 > s1
    })

let revised3 = sorted(names, { s1, s2 in s1 > s2 })
revised3

let revised4 = sorted(names) { $0 > $1 } // This is also a trailing closure
revised4

let revised5 = sorted(names, >)

// Long closures
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

// Closure Value Capturing
func makeIncrementor(firstNumber number:Int) -> () -> Int
{
    var runningTotal = 0
    func incrementor()->Int {
        runningTotal += number
        return runningTotal
    }
    return incrementor
}

let incrementor = makeIncrementor(firstNumber: 4)
incrementor()

// @autoclosure
func simpleAssert(@autoclosure condition: () -> Bool, message: String = "Assertion failed") {
    if !condition() {
        println(message)
    }
}

func lazyAssertion(@autoclosure(escaping) condition: () -> Bool, message: String = "") {
    lazyAssertions.append(condition)
}

func autoreleasepool(@noescape code: () -> ()) {
    pushAutoreleasePool()
    code()
    popAutoreleasePool()
}

// optional function call

let maybeFunction: (() -> ())? = nil
maybeFunction?()
maybeFunction!()

// Swift 2 exceptions

func throwingFunction() throws -> String {
    throw ErrorType.Error
}

do {
    try throwingFunction()
} catch {
    println(error)
}

try! throwingFunction()

func rethrowingFunction(f: T throws -> U) rethrows -> U {}

// other swift 2 stuff

guard let x = optionalValue else {
   print("Fail")
   throw NSError(domain: "", code: 0, userInfo: nil)
}

defer { callback() }

if case let x? = optionalValue {print("Unwrapped: \(x)")}

repeat {
    // loop…
} while condition

if #available(iOS 8.0, OSX 10.10, *) {
   // Use Handoff APIs when available.
   let activity = NSUserActivity(activityType:"com.example.ShoppingList.view")
} else if #unavailable(linux) {
    // Fall back when Handoff APIs not available.
} else {
}

//MARK: Classes
public class Person : NSObject {
    let firstName: String

    private var lastName: String

    private(set) var age: Int {
    didSet {
        println("Happy Birthday")
    }
    }

    internal(set) var doubleAge = 0.0
    unowned(safe) var safeUnowned = nil
    unowned(unsafe) var unsafeUnowned = nil

    lazy var phoneNumbers = [String]()
    @NSCopying var modificationDate: NSDate = NSDate()

    required public init(name: String, age: Int) {
        self.name = name
        self.age = age
        super.init()
    }

    internal var isAdmin: Bool { return false }

    final func doSomething() {
        //TODO: Do something
    }

    dynamic func somethingDynamic() { }
}

@objc(MYCustomView) class CustomView: NSView, SomeProtocol , OtherProtocol {
    @IBOutlet var button: AnyObject!

    @IBAction func doSomething(sender: AnyObject) {
        //TODO: Do something
    }
}

//MARK: Protocols
@objc protocol Random {
    typealias T: SomeConstraint
    func random() -> Self
    optional func seed(seed: Int)
    required func foo()
}

extension SomeProtocol where T: OtherProtocol {
    func blah() {
        // default implementation
    }
}

extension SomeClass {

}

struct Stack<T, U>: Equatable {
    var items = [T]()
}

typealias Speed = Double

enum State: Equatable {
    case Stopped, Paused
    case Running(Speed)
}

@availability(OSX, introduced=10.10) func localizedCaseInsensitiveContainsString(aString: String) -> Bool

//MARK: Conditional compilation
#if os(iOS)
    sayHello("iOS")
    #if arch(arm)
        typealias View = UIView
    #elseif arch(arm64)
        typealias View = UIView64
    #else
        #warning("Unknown architecture")
    #endif
#elseif os(OSX)
    /* Uncomment this when the Mac goes 64bit
    #if arch(i386)
        typealias View = NSView
    #elseif arch(x86_64)
        typealias View = NSView64
    #endif
    */
#endif

protocol Protocol {
    associatedtype AssociatedType
    typealias TypeAlias
}

// keywords acceptable as argument names now:
NSURLProtectionSpace(host: "somedomain.com", port: 443, protocol: "https", realm: "Some Domain", authenticationMethod: "Basic")

let fn1 = someView.insertSubview(_:at:)
let fn2 = someView.insertSubview(_:aboveSubview:)

#if swift(>=2.2) || os(macOS)
  func foo(x: Int) -> (y: Int) -> () {}
#else
  func foo(x: Int)(y: Int) {}
#endif

let sel = foo(#selector(insertSubview(_:aboveSubview:)))

open class SubclassableParentClass {
    public var size : Int
    public func foo() {}
    open func bar() {}
    public final func baz() {}
    private func a() {}
    fileprivate func b() {}
}

public final class FinalClass { }

if case let x = a, case let y = b {
    func firstFunc(x: A & B) {
        let a : A & B & C = Foo()
    }
}

func anyCommonElements<T : SequenceType, U : SequenceType>(lhs: T, _ rhs: U) -> Bool where
    T.Generator.Element: Equatable,
    T.Generator.Element == U.Generator.Element
{
    let firstNameGetter = #selector(getter: Person.firstName)
    let firstNameSetter = #selector(setter: Person.firstName)
    chris.valueForKeyPath(#keyPath(Person.bestFriend.lastName)) // => Groff
    
    let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
    particleSystem.imageSequenceAnimationMode = SCNParticleImageSequenceAnimationMode.repeat
}

typealias StringDictionary<T> = Dictionary<String, T>

@available(*, unavailable, renamed: "MyRenamedProtocol")
@discardableResult func f() -> T {}

_ = #sourceLocation(file: "foo", line: 42)

@available(swift, obsoleted: 5.0.0, renamed: "foo2(file:line:)")
func foo(_ file: StaticString = #file, line: UInt = #line) { }

precedencegroup ComparisonPrecedence {
  associativity: left
  higherThan: LogicalConjunctionPrecedence
  lowerThan: Additive
}
infix operator <> : ComparisonPrecedence

// keyword as identifier
var `var` = 3

// keypath
let keypath = \Person.firstName
var keyPath: KeyPath<String, Bool> = \.isEmpty

// tuple destructuring
let (t1, t2) = (1, 2)
var ((`func`, foo), `protocol`) = ((3, 4), 5)
var ( t3 , /* comment */
    ( t4 , t5 ) ) = ("a", ("b", "c"))

// function with lambda argument
func funcWithLambdaArg(_ fn: (Int) -> Int) -> Int {
    return fn(1)
}

funcWithLambdaArg { x in x + 5 }
funcWithLambdaArg { $0 + 5 }
funcWithLambdaArg({ x in x + 5 })

func newView() -> some View {
	ViewRegistry.find(\.MyView.name)
}

@frozen
public enum Types {
	case a, b, c
	case d
}

func test(t: Types?) -> Bool {
	switch t {
	case .a?: return true
	case .b?: return true
	case .c: return true
	default: return false
	}
}

distributed actor AnActor {
  nonisolated func funcA() {}
  func funcB(otherActor: isolated AnActor) async {
    await otherActor.funcB()
    async let v = funcA()
  }
}

func existential(arg: any Proto1) -> some Proto2 {
  autoreleasepool {
  }
}

func pwrap() -> Bool {
  @SmallNum var myNum: Int = 8
  self.$myOwnNum = 8
  return $myNum
}

let res = [
  // comment not a regex
  #//#, // empty regex
  ##//##, // another
  ##//#, // unbalanced #
  #//##, // unbalanced #
  / not a regex /,
  /a regex/,
  /not a single-line
  regex/,
  /re with \/ escaped/,
  ##/usr/lib/#modules/vmlinuz/##, // unescaped / with ##
  /(#*)/(?!\s)[^\n]*(?<![\s\\])/\1/,

  #/
  multiline regex
  /#,

  ##/
  multiline # comment
  /#
  /###
  still going
  /##
]

package struct FileDescriptor: ~Copyable {
  private var fd: Int32

  consuming func close() throws {
    discard self
  }
}

func makePairs<each First, each Second>(
  firsts first: repeat each First,
  seconds second: repeat each Second
) -> (repeat Pair<each First, each Second>) {
  return (repeat Pair(each first, each second))
}

@freestanding(expression)
public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "m", type: "t")

let p = #stringify(x + y)

foo() // end-of-file comment
