
// requires global.js -- NEEDS Function.prototype.closure = function(obj){...} from global.js

/*
Loader / Progress Bar for Google Maps
Author: Jeremy Lazarus
March 1st, 2006
Used on: http://www.motel.com/MapSearch.aspx


Description:
Provides a way to execute processor intensive tasks while not   locking up the browser. Also gives the user a true
progress bar and a way to cancel the task.

It works by creating an array of one-time closures for each call. When execute() is called, it begins consuming
small sets of closures and sets a small timeout before executing the next set of closures. The timeout allows
the browser time to process any events, such as rendering and user interaction.

Notes:
Could easily be modified to have pause/resume functionality, if that suits one's needs. Can also adjust the
timeout and steps to execute at once.

Example: (hotels is an array of hotel objects with a show method that takes a boolean argument. show calls map.addOverlay)
var loader = new MLoader(map, document.getElementById("loading"), document.getElementById("loadingText"), document.getElementById("bar"), document.getElementById("fill"), document.getElementById("loadingButton"));

loader.show("Displaying hotels...", true);

for (var i = 0; i < hotels.length; i++)
    loader.add(hotels[i], hotels[i].show, true);

loader.execute();
*/

function MLoader(map, loadingElement, loadingTextElement, barElement, fillElement, cancelButton)
{
    var err = "";
    this.map = map;
    if (null == map)
    {
        err += "map is null. ";
    }
    this.loadingElement = loadingElement;
    if (null == loadingElement)
    {
        err += "loadingElement is null. ";
    }
    this.bar = barElement;
    if (null == barElement)
    {
        err += "barElement is null. ";
    }
    this.fill = fillElement;
    if (null == fillElement)
    {
        err += "fillElement is null. ";
    }
    this.loadingTextElement = loadingTextElement;
    if (null == loadingTextElement)
    {
        err += "loadingTextElement is null. ";
    }
    this.cancelButton = cancelButton;
    if (null == cancelButton)
    {
        err += "cancelButton is null. ";
    }
    if (0 != err.length)
    {
        alert("Status: " + err);
    }
}

MLoader.prototype.map = null;
MLoader.prototype.loadingElement = null;
MLoader.prototype.loadingTextElement = null;
MLoader.prototype.cancelButton = null;
MLoader.prototype.bar = null;
MLoader.prototype.fill = null;
MLoader.prototype.counter = 0;
MLoader.prototype.show = function (text, allowCancel)
{
    this.map.disableDragging();
    this.loadingElement.style.display = "";
    this.loadingElement.style.left = (document.body.clientWidth - 160)/2 + "px";
    this.loadingTextElement.innerHTML = text;
    if (allowCancel)
    {
        this.cancelButton.style.display = "";
    }
    else
    {
        this.cancelButton.style.display = "none";
    }
    this.counter++;
}

MLoader.prototype.hide = function (force)
{
    if (force)
    {
        this.counter = 0;
    }
    else if (this.counter > 0)
    {
        this.counter--;
    }
        
    if (this.counter == 0)
    {
        this.fill.style.width = "1px";
        this.loadingElement.style.display = "none";
        this.map.enableDragging();
    }
    
}
MLoader.prototype.queue = null;
MLoader.prototype.add = function (o, f, a)
{
    if (null == this.queue)
    {
        this.queue = new Array();
    }
    var b = _MOneTimeClosure(o,f,a);
    this.queue[this.queue.length] = b;
}
MLoader.prototype.queueCounter = 0;
MLoader.prototype.execute = function ()
{
    if ((this.queueCounter > 0) && (this.queue))
    {
        this.fill.style.width = (100 * this.queueCounter / this.queue.length) + "%";
    }
    else
    {        
        this.fill.style.width = "1px";
    }
    
    var stopAt = this.queueCounter + 10;
    while ((this.queue) && (this.queueCounter < this.queue.length) && (this.queueCounter < stopAt))
    {
        this.queue[this.queueCounter]();
        this.queue[this.queueCounter++] = null;
    }
    
    if ((this.queue) && (this.queueCounter < this.queue.length))
    {
        
		setTimeout(this.execute.closure(this), 50);
    }
    else
    {
        for (var i = 0; (this.queue) && (i < this.queue.length); i++)
        {
            this.queue[i] = null;
        }
        this.queue = null;
        this.queueCounter = 0;
        this.hide(true);
        CheckForDisplayBubble();
    }
}
MLoader.prototype.cancel = function ()
{
    for (var i = 0; (this.queue) && (i < this.queue.length); i++)
    {
        this.queue[i] = null;
    }
    this.queue = null;
    this.queueCounter = 0;
    this.hide(true);
}

// Executes once and removes all references
function _MOneTimeClosure (h, f, a){
        return (function() {
            h.f = f;
            h.f(a);
            a = null;
            h.f = null;
            h = null;
        })
    }