// Fields are private by default. Methods are public by default.
class Node<T> {
    let value: T
    var next: Node<T>?

    fn get() { return value }
    fn next_node() { return next }
}

class LinkedList<T> {
    var head: Node<T>?

    fn push(value: T) {
        head = Node<T>(value: value, next: head)
    }

    fn first() { return head }

    fn len() {
        var count = 0
        var cursor = head
        while cursor != null {
            let node = cursor.unwrap()
            count = count + 1
            cursor = node.next_node()
        }
        return count
    }
}

class Employee {
    let name: String
    let age: Int64

    private fn internal_name() { return name }
    public fn name_text() { return internal_name() }
    fn years() { return age }
}

// Constructor type arguments are explicit; Int32 is not implemented.
let numbers = LinkedList<Int64>(head: null)
numbers.push(10)
numbers.push(20)
print("Number count")
print(numbers.len())
print("First number")
print(numbers.first().unwrap().get())

let measurements = LinkedList<Float64>(head: null)
measurements.push(1.5)
print("First measurement")
print(measurements.first().unwrap().get())

// The same linked-list definition holds user-class references.
// These are fictional teaching records; names and ages are constructor inputs.
let employees = LinkedList<Employee>(head: null)
employees.push(Employee(name: "Lin", age: 29))
employees.push(Employee(name: "Ada", age: 36))
let employee = employees.first().unwrap().get()
print("Employee count")
print(employees.len())
print("First employee")
print(employee.name_text())
print(employee.years())

// A type argument can itself be a concrete generic class.
let nested = Node<Node<Int64>>(
    value: Node<Int64>(value: 7, next: null),
    next: null,
)
print("Nested node value")
print(nested.get().get())
