/*
 *  DO NOT EDIT OR DELETE THIS FILE
 *  Copyright 2007 Baynote, Inc. All Rights Reserved
 *  V1.25
 */

if (typeof(baynote_globals) == "undefined") var baynote_globals = new Object();

function BNLog()
{
    this.timeBase = new Date().getTime();
    this.lines    = new Array();
    this.lastLine = "";
    this.repCount = 0;
}

BNLog.prototype.log = function(str)
{
    if (str == this.lastLine)
    {
        ++this.repCount;
        return;
    }

    if (this.repCount > 0)
    {
        this.lines.push("___ ABOVE REPEATED " + this.repCount + " TIME"
                        + ((this.repCount > 1) ? "S" : ""));
    }

    this.lastLine = str;
    this.repCount = 0;

    var elapsed = new Date().getTime() - this.timeBase
    this.lines.push(elapsed + ": " + str);
}

BNLog.prototype.toString = function()
{
    if (this.repCount > 0)
    {
        this.lines.push("___ ABOVE REPEATED " + this.repCount + " TIME"
                        + ((this.repCount > 1) ? "S" : ""));

        this.lastLine = "";
        this.repCount = 0;
    }

    return this.lines.join("\n");
}

if (typeof(bnLog) == "undefined") 
{
    var bnLog = new BNLog();
}


// Lamport's Bakery algorithm synchronization code adapted from:
//     http://www.onjava.com/pub/a/onjava/2006/04/05/ajax-mutual-exclusion.html
// and http://taylor-hughes.com/dump/ExclusiveAction.js
function BNCriticalSectionQueue()
{
    this.waitList = new Object();
    this.lastId   = 0;
}

BNCriticalSectionQueue.prototype.issueId = function()
{
    return ++this.lastId;
}

BNCriticalSectionQueue.prototype.enqueue = function(id, item)
{
    this.waitList[id] = item;
}

BNCriticalSectionQueue.prototype.getWaiter = function(id)
{
    return (id == null) ? null : this.waitList[id];
}

BNCriticalSectionQueue.prototype.firstWaiter = function()
{
    return this.getWaiter(this.nextWaiterKeyAfter(null));
}

BNCriticalSectionQueue.prototype.nextWaiterAfter = function(id)
{
    return this.getWaiter(this.nextWaiterKeyAfter(id));
}

BNCriticalSectionQueue.prototype.nextWaiterKeyAfter = function(id)
{
    for (currKey in this.waitList)
    {
        if (id == null)
        {
            return currKey;
        }

        if (id == currKey)
        {
            id = null;  // This hack will cause NEXT key to be returned
        }
    }

    return null;
}

BNCriticalSectionQueue.prototype.nextPredecessor = function(target, start)
{
    for (var currWaiter = start;
         currWaiter != null;
         currWaiter = this.nextWaiterAfter(currWaiter.id))
    {
        if (currWaiter.enter
            ||
            (currWaiter.number != 0 &&
             (currWaiter.number < target.number
              ||
              (currWaiter.number == target.number &&
               currWaiter.id < target.id))))
        {
            return currWaiter;
        }
    }

    return null;        // Nobody in line before target
}



function BNCriticalSection(csQueue)
{
    this.csQueue = csQueue;
    this.debug   = 1;
}

BNCriticalSection.prototype.enter = function(enterFunc)
{
    this.enterFunc = enterFunc;
    this.id        = this.csQueue.issueId();

    this.csQueue.enqueue(this.id, this);

    this.enter  = true;
    this.number = (new Date()).getTime();
    this.enter  = false;

    this.attempt(this.csQueue.firstWaiter());
}

BNCriticalSection.prototype.leave = function()
{
    if (this.debug) bnLog.log("LEAVE " + this.id);
    this.number = 0;
}

BNCriticalSection.prototype.attempt = function(start)
{
    var nextReady = this.csQueue.nextPredecessor(this, start);
    if (nextReady != null)
    {
        // Someone else is ahead of us in line, try again later
        if (this.debug) bnLog.log("WAIT " + this.id);
        var me = this;
        return setTimeout(function() { me.attempt(nextReady); }, 50);
    }

    // Nobody in line before us, we have exclusive access to critical section
    if (this.debug) bnLog.log("ENTER " + this.id);
    this.enterFunc();
}



function BNResourceManager()
{
    this.csQueue   = new BNCriticalSectionQueue();
    this.critSec   = null;
    this.debug     = 1;
    this.resources = new Object();
    this.waiting   = new Object();
}

// Returns "true" if the indicated resource has been "registered". 
// Returns the resource object if the indicated resource has been "registeredAndAdded".
// Returns null if the indicated resource is still loading.
// Returns undefined if the resource has not started loading.
BNResourceManager.prototype.getResource = function(rId)
{
    return this.resources[rId];
}

BNResourceManager.prototype.loadResource = function(rId, rAddress, rType)
{
    if (typeof(this.resources[rId]) != "undefined") // if true, indicates resource is alreading loading or loaded
        return;

    this.resources[rId] = null;      // indicates resource is loading

    var critSec = new BNCriticalSection(this.csQueue);
    critSec.enter(function() {
        bnResourceManager.inject(rId, rAddress, rType, critSec);
    });
}

// This, along with registerAndAddResource, form a critical section
BNResourceManager.prototype.inject = function(rId, rAddress, rType, critSec)
{
    this.critSec = critSec;   // For registerResource

    if (this.debug) bnLog.log("INJECT " + this.critSec.id + " (" + rId + ")");

    if (!rType  ||
        rType == "script")
    {
        var scriptTag1 = document.createElement("script");
        scriptTag1.language = "javascript";
        scriptTag1.src = rAddress;
        var head = document.getElementsByTagName("head");
        head[0].appendChild(scriptTag1);
    }
    else if (rType == "img")
    {
        var img = document.createElement("IMG");

        var handler = function()
        {
            bnResourceManager.registerAndAddResource(rId, img);
        };

        // Normally we use bnEvent to do this, but that may not have been loaded yet
        if (img.addEventListener)    // DOM-compliant
        {
            img.addEventListener("load", handler, false);
        }
        else if (img.attachEvent)    // IE
        {
            img.attachEvent("onload", handler);
        }
        else
        {
            img["onload"] = handler;
        }

        // This must be done *after* setting the event handler on IE or we
        // may not see the onload event if the image is cached
        img.src = rAddress;

        // Caller is responsible for styling this image and appending it
        // to an appropriate node once it becomes ready
    }
    else
    {
        alert("Unexpected resource type to loadResource: " + rType);
    }
}

// note: if rAddress is present and the resource needs loading, it will be loaded
BNResourceManager.prototype.waitForResource = function(rId, callbackCode, rAddress, rType)
{
    with (this)
    {
        if (getResource(rId)) 
        {
            //alert("Have resource: " + rId);
            this.runCallback(callbackCode);
        }
        else
        {
            //alert("Waiting for Resource: " + rId);
            if (typeof(waiting[rId]) == "undefined") waiting[rId] = new Array();
            var waitingList = waiting[rId];
            waitingList[waitingList.length] = callbackCode;            
            if (rAddress)
            {
                this.loadResource(rId, rAddress, rType);
            }
        }
    }
}

BNResourceManager.prototype.wakeUpWaiting = function(rId)
{
    with (this)
    {
        var waitingList = waiting[rId];
        if (!waitingList) return;
        for (var i = 0; i < waitingList.length; i++)
        {
            //alert("Running: " + waitingList[i]);
            if (waitingList[i]) 
            {
                var codeToEval = waitingList[i];
                waitingList[i] = null;
                if (this.debug  &&  codeToEval) bnLog.log("CALLBACK " + rId + ": " + codeToEval);
                this.runCallback(codeToEval);
            }
        }
    }
}

BNResourceManager.prototype.registerAndAddResource = function(rId, resource)
{
    if (this.debug) bnLog.log("REGISTER " + this.critSec.id + " (" + rId + ")");
    this.resources[rId] = resource;
    this.wakeUpWaiting(rId);
    this.critSec.leave();

    setTimeout("bnResourceManager.wakeUpWaiting('" + rId + "')", 5000); // just in case
}

BNResourceManager.prototype.registerResource = function(rId)
{
    this.registerAndAddResource(rId, true);
}

BNResourceManager.prototype.runCallback = function(callback)
{
    if (typeof(callback) == "string")
    {
        eval(callback);
    }
    else if (typeof(callback) == "function")
    {
        callback();
    }
    else
    {
        alert("Invalid callback, type=" + typeof(callback));
    }
}

// Create the ResourceManager if it's not there already
if (typeof(bnResourceManager) == "undefined") 
{
    //alert("Allocating ResourceManager");
    var bnResourceManager = new BNResourceManager();
}


/************************/
/******* BNSystem *******/
/************************/

function BNSystem()
{
    this.testServer = null;
}

BNSystem.prototype.getCookieValue = function(cookieName)
{
   var cookieValue = document.cookie;
   var cookieStartsAt = cookieValue.indexOf(" " + cookieName + "=");

   if (cookieStartsAt == -1)
   {
      cookieStartsAt = cookieValue.indexOf(cookieName + "=");
   }

   if (cookieStartsAt == -1)
   {
      cookieValue = null;
   }
   else
   {
      cookieStartsAt = cookieValue.indexOf("=", cookieStartsAt) + 1;
      var cookieEndsAt = cookieValue.indexOf(";", cookieStartsAt);
      if (cookieEndsAt == -1)
      {
         cookieEndsAt = cookieValue.length;
      }
      cookieValue = unescape(cookieValue.substring(cookieStartsAt,
         cookieEndsAt));
   }

   return cookieValue;
}

BNSystem.prototype.setCookie = function(cookieName, cookieValue, cookiePath, cookieExpires, cookieDomain)
{
    cookieValue = escape(cookieValue);

    if (cookieExpires == "NEVER")
    {
        var nowDate = new Date();
        nowDate.setFullYear(nowDate.getFullYear() + 500);
        cookieExpires = nowDate.toGMTString();
    }    
    else if (cookieExpires == "SESSION")
    {
        cookieExpires = "";
    }

    if (cookiePath != "")
       cookiePath = ";Path=" + cookiePath;

    if (cookieExpires != "")
        cookieExpires = ";expires=" + cookieExpires;

    if (!cookieDomain) cookieDomain = 
        (baynote_globals.cookieDomain) ? baynote_globals.cookieDomain : "";
    if (cookieDomain != "")
        cookieDomain = ";domain=" + cookieDomain;

    var cookieStr = cookieName + "=" + cookieValue + 
       cookieExpires + cookiePath + cookieDomain;

    if (cookieStr.length > 4096) return false;
    document.cookie = cookieStr;
    return true;
}

BNSystem.prototype.removeCookie = function(cookieName, cookieDomain)
{
    this.setCookie(cookieName, "", "/", "Mon, 1 Jan 1990 00:00:00", cookieDomain);
}

BNSystem.prototype.getURLParam = function(name,url)
{
    if (!url) var url = window.location.href;
    var regex = new RegExp("[\\?&]"+name+"=([^&#]*)");
    var match = regex.exec(url);
    if(!match) 
        return null;
    else
      return match[1];
}

BNSystem.prototype.getTestServer = function()
{
    if (this.testServer != null) return this.testServer;

    var testServer = this.getURLParam("bn_test");
    if (testServer)
    {
        this.setCookie("bn_test", testServer, "/", "SESSION");
    }
    else if (testServer == "")
    {       
        this.removeCookie("bn_test");
    }
    else
    {
        testServer = this.getCookieValue("bn_test");
        if (!testServer) testServer = "";
    }

    this.testServer = testServer;
    return testServer;
}

if (typeof(bnSystem) == "undefined") 
{
    var bnSystem = new BNSystem();
}


/************************/
/****** Baynote Tag *****/
/************************/

function BNTag(previousTag)
{
    if (previousTag)
    {
        this.id = previousTag.id + 1;
        this.server = previousTag.server;
        this.customerId = previousTag.customerId;
        this.code = previousTag.code;
    }
    else
    {
        this.id = 0;
    }
    this.css = new Object();
}

BNTag.prototype.getCommonResourceId = function()
{
    return "Common";
}

BNTag.prototype.getCommonResourceAddress = function(tag)
{
    return (this.server + "/baynote/tags2/common.js");
}

BNTag.prototype.getFailsafeResourceId = function()
{
    return "Failsafe";
}

BNTag.prototype.getFailsafeResourceAddress = function()
{
    // The "x" parameter should be different each time this address is used.
    // That ensures that the browser always has to explicitly fetch this
    // resource rather than retrieving it from cache.
    return (this.server
            + "/baynote/customerstatus2?customerId="
            + this.customerId
            + "&code="
            + this.code
            + "&x="
            + this.id
            + (new Date().getTime()));
}

BNTag.prototype.show = function(parentElemId)
{
    if (this.id == 0) 
        document.write("<span id='bn_placeholder_global'></span>");
    // insert placeholder
    this.placeHolderId = "bn_placeholder" + this.id;
    if (this.placeHolderElement)
        var placeHolderType = this.placeHolderElement;
    else
        var placeHolderType = this.popup ? "span" : "div";
    if (parentElemId)
    {
        var placeHolder = document.createElement(placeHolderType);
        placeHolder.id = this.placeholderId ;
        document.getElementById(parentElemId).appendChild(placeHolder);
    }
    else
    {
        document.write("<" + placeHolderType + " id='" + 
                        this.placeHolderId  + "'></" + placeHolderType + ">");
    }

    window["bn_tags"][this.id] = this;

    var testServer = bnSystem.getTestServer();
    if (testServer) this.server = testServer;

    this.showWhenReady(this);

    baynote_tag = new BNTag(this);
}

BNTag.prototype.showWhenReady = function(tag)
{
    var failsafeId = this.getFailsafeResourceId();
    if (!bnResourceManager.getResource(failsafeId))
    {
        bnResourceManager.waitForResource(failsafeId,
                                           function() {
                                               tag.showWhenReady(tag);
                                           },
                                           this.getFailsafeResourceAddress(),
                                           "img");
        return;         // We will come back once the failsafe image is loaded
    }

    var commonId = this.getCommonResourceId();
    if (!bnResourceManager.getResource(commonId))
    {
        bnResourceManager.waitForResource(commonId,
                                           function() {
                                               tag.showWhenReady(tag);
                                           },
                                           this.getCommonResourceAddress(),
                                           "script");
        return;         // We will come back once the common code is loaded
    }

    bnTagManager.show(tag.id);
}

BNTag.prototype.noshow = function()
{
    window["bn_tags"][this.id] = this;
    baynote_tag = new BNTag(this);
}

BNTag.prototype.getParam = function(name, defaultValue)
{
    var value = this[name];
    if ( typeof(value) == "undefined" || value == null )
      return defaultValue;
    else
      return value;
}

if (typeof(baynote_tag) == "undefined")
{
    window["bn_tags"] = new Array();
    var baynote_tag = new BNTag(null);
}
