Timeout-Scheduler

== What it is ==
Timeout-Scheduler is a function which provides a simple yet versatile tool for handling multiple independent timer events.
== Some key ideas ==
* Easy handling of multiple independent, asynchronous timeout events (for example dialog timeouts for multiple users).
* One central function (in conjunction with a timer event) for getting, setting, modifying and removing timeout events.
* The data associated with the timeout event can be fetched manually or when the timeout is due.
* Hierarchical conditional selection of events, offering many possibilities to do things with very few function calls.
== Overview of the function ==
=== Important note ===
The integer data type plays a special role in the internal schedule list structure used by the function. Remember that lists can store mixed data types and that searches on lists also match the type, thus 0 != "0" != (key)"0" != 0.0. The integer 0 is used as a dummy element to indicate the beginning of user data and to make the stride length consistent. Integers (especially 0) should never occur in user data as this might corrupt the data structure. If you need to store integers, cast them to some other type like string. If you know what you're doing you can exchange 0 with some other dummy element (possibly of another type which is not used elsewhere in your user data) appropriate for your needs.
=== Calling the function ===
The sched() function takes two arguments:
*time can take three different kinds of values with different meanings:
** Positive values are used for setting new timeouts. The value is the time in seconds after which the timeout is triggered from within the timer event.
** A value of 0 is used to remove an existing event (and fetching that event's data).
** Any negative value may be used to retrieve the data associated with an existing event without deleting the event.
*data is a list of data associated with the timeout event. It is used in two ways: Firstly, it is used to look up existing timeout events matching that data. Secondly, the given data is stored in the schedule when a new timeout event is created.
== Creating simple timeout events ==
Try this to create a few simple timeout events:
<lsl>
sched(2, ["Some Other Timeout"]);
sched(3, ["Yet", "Another", "Timeout"]);
sched(1, ["First", "Timeout"]);
</lsl>
This should trigger the three timeouts in the correct chronological order.
== Implementation ==
<lsl>
////////// NOTES ///////////////////////
// Timeout-Scheduler v0.1.5-Dev (2010-12-06) by Ochi Wolfe
// You may use, change and distribute this code as you wish.
// When distributing it in source form for others to use, please
// include a note where it is from and what you have changed.
////////// VARIABLES ///////////////////
list schedule = [];
////////// FUNCTIONS ///////////////////
list sched(integer time, list data) {
 integer LEN = 3; // Max data length
 integer idx = -1; // Selected timeout
 integer now = llGetUnixTime(); // The current time
 list res; // Result data list
 // If data is given, select first matching timeout.
 // If data is empty, select next timeout that is due.
 if (data != []) {
 idx = llListFindList(schedule, [0] + data);
 } else {
 integer til = llList2Integer(schedule, 0);
 if (til && (til <= now)) idx = 1;
 }
 // If a timeout was selected, fetch its data.
 // If time == 0, delete it afterwards.
 if (~idx) {
 res = llList2List(schedule, idx+1, idx+LEN);
 if (!time) schedule = llDeleteSubList(schedule, idx-1, idx+LEN);
 }
 // If time > 0, insert a new timeout event.
 // Fill data list to make its length consistent.
 if (time > 0) {
 integer len = LEN+1-llGetListLength(data); while (--len) data += [0];
 schedule = llListSort([now+time, 0] + data + schedule, LEN+2, TRUE);
 }
 // If next timeout is in the future, (re)start timer.
 // If there are no timeouts left, stop timer.
 // Otherwise, just leave the timer as it is.
 integer til = llList2Integer(schedule, 0);
 if (til > now) llSetTimerEvent(til-now);
 else if (!til) llSetTimerEvent(0.0);
 return res;
}
////////// STATES //////////////////////
default {
 state_entry() {
 }
 timer() {
 list data;
 // Fetch and handle all timeouts that are due and delete them.
 while (data = sched(0, [])) {
 llOwnerSay("Timeout: " + llDumpList2String(data, ", "));
 }
 }
}
</lsl>