//
// traverser.js
//
// A JavaScript object that traverses an array of generated names, calling
// registered "action" objects to perform a set of actions for each item
// traversed.  The action objects must provide a set() member function that
// takes a single array entry as an argument.
//
// Copyright 2005 Bernie Maier (code) and Kay Orchison (specification).
//

//
// Traverser base class.  I'm not sure if JavaScript can cope with function
// overloading, so to have different constructors I am defining a base class
// which constructs the object from a pre-existing array, and a bunch of
// subclasses providing different ways to construct the array.
//
function Traverser(array)
{
    this.items = array;
    this.numItems = array.length;
    this.actions = new Array;
    this.currentItem = 0;

    this.registerAction = function(action)
    {
        // Add the specified action to the array of actions
        this.actions[this.actions.length] = action;
    }

    this.getCurrent = function()
    {
        var item = this.items[this.currentItem];
        for (i = 0; i < this.actions.length; ++i)
        {
            this.actions[i].set(item);
        }
        return item;
    }

    this.next = function()
    {
        this.currentItem = this.currentItem == this.numItems - 1 ? 0
                                                 : ++this.currentItem;
        return this.getCurrent();
    }

    this.prev = function()
    {
        this.currentItem = this.currentItem == 0 ? this.numItems - 1
                                                 : --this.currentItem;
        return this.getCurrent();
    }
}

function SimpleTraverser(prefix, suffix, firstItemNum, lastItemNum)
{
    this.inheritFrom = Traverser;
    var items = new Array;
    for (i = firstItemNum; i <= lastItemNum; i++)
    {
        items[i - firstItemNum] = prefix + i + suffix;
    }
    this.inheritFrom(items);
}

function FilledTraverser(prefix, suffix, firstItemNum, lastItemNum, numDigits)
{
    this.inheritFrom = Traverser;
    var items = new Array;
    var leading = "";
    for (i = 0; i < numDigits; ++i)
    {
        leading += "0";
    }
    for (i = firstItemNum; i <= lastItemNum; i++)
    {
        var x = leading + i;
        var len = x.length;
        var filled = x.substring(len - numDigits, len);
        items[i - firstItemNum] = prefix + filled + suffix;
    }
    this.inheritFrom(items);
}

//
// This class changes the source attribute for an image tag, i.e. effectively
// changes the image being displayed.
//
function ImageSetter(elId)
{
    this.elId = elId;
    this.elem = document.getElementById(elId);

    this.set = function(imageName)
    {
        // First check that the element is already known.  It may be null if
        // this object was constructed before the tag defining this element ID
        // was created.
        if (!this.elem)
        {
            this.elem = document.getElementById(this.elId);
        }
        if (this.elem)
        {
            this.elem.src = imageName;
        }
        else
        {
            // document.write('No image');
        }
    }
}

//
// This is a proof-of-concept class that changes the text of a paragraph.
// It's a dodgy hack that only works for Mozilla-based browsers, and probably
// only recent ones at that.  It has basically only been tested in Firefox.
//
function ParagraphTextSetter(elId)
{
    this.elId = elId;
    this.elem = document.getElementById(elId);

    this.set = function(text)
    {
        if (!this.elem)
        {
            this.elem = document.getElementById(this.elId);
        }
        // Test whether this browser's DOM has the attribute we want to change.
        if (this.elem && this.elem.firstChild && this.elem.firstChild.data)
        {
            this.elem.firstChild.data = text;
        }
    }
}

