/*
 * File: self_awareness.txt
 * -----------------------------
 */

/* In functions.txt it was explained that two reference variables are always
   available inside a function: this and self.
     this points to the function itself, and can be used for recursion and to
   access sub-variables of the function variable.
     self on the other hand is a reference to the function's PARENT variable -
   the variable of which the function is a sub-variable. So why call it self
   instead of the more logical word parent? Well, that's because most other
   languages use self in this way. JAIL needs both this and self because a
   variable may have an intrinsic value and sub-variables at the same time.
     So, remember: this is the function, self is the function's parent. The
   distinction makes sense, the choise of names does not :) */

/* Here we create a variable with four functions and two numeric variables. */
object.setPos = function(x, y) {
    self.x = x;
    self.y = y;
};

object.setSpeed = function(dx, dy) {
    self.dx = dx;
    self.dy = dy;
};

object.move = function() {
    self.x += self.dx;
    self.y += self.dy;
};

object.toString = function() {
    return "(" + tostring(self.x) + ", " + tostring(self.y) + ")";
};

/* Set position and speed and move some. */
object.setPos(0, 0);
object.setSpeed(4, 3);
wln(object.toString());
for (i = 1, 4) {
    object.move();
}
wln(object.toString());
wln();

/* This construct might look messy at a glance by the untrained eye. Note how
   both self and this are used. */
Person = function(firstName, lastName, age) {
    /* Build a variable, person, that we return a copy of at the end of this
       function. */

    /* person's name will have two sub-variables named first and last. name
       itself is a function that returns the full name as a string. */
    person.name = function() {
        return this.first + " " + this.last;
    };

    /* name also has a function, set, that sets first and last of itself. */
    person.name.set = function(first, last) {
        self.first = first;
        self.last = last;
    };

    /* person's setName sets the name using name's set function. */
    person.setName = function(first, last) {
        self.name.set(first, last);
    };

    /* person itself is a function that returns the full name and age as a
       string. */
    person = function() {
        return this.name() + " (" + tostring(this.age) + ")";
    };

    /* Function to set the age. */
    person.setAge = function(age) {
        self.age = age;
    };

    /* Initiate person with the parameters. */
    person.setName(firstName, lastName);
    person.setAge(age);

    /* Return person. */
    return ref person;
};

/* Create some persons. */
marcus := Person("Marcus", "Johansson", 39);
peter := Person("Peter", "Fischer", 56);
dolph := Person("Dolph", "Erenpoop", 13);
tyra := Person("Tyra", "Williams", 29);

/* Just messing around here by putting references to them in a list. */
persons[1] ref marcus;
persons[2] ref peter;
persons[3] ref dolph;
persons[4] ref tyra;

/* Show all persons. */
for (p: persons) {
    wln(p());
}

/* This is kind of important. When you delete a variable that has sub-variables
   that are references, the referenced variables will NOT be deleted. */
delete p;

