/**
 *
 * $Id: util.js 63843 2009-02-09 23:15:05Z kchiu $
 * $Author: kchiu $
 * $Revision: 63843 $
 * $Name$
 * $Date: 2009-02-09 15:15:05 -0800 (Mon, 09 Feb 2009) $
 *
 * @package     PriceGrabber
 * @category    JavaScript
 *
 * @author      Philip Snyder <philip@pricegrabber.com>
 * @copyright   Copyright &copy; 2006 2007, Philip Snyder, PriceGrabber.com
 * @version     $Revision: 63843 $
 *
 * @todo        Finish documentation.
 */

/**
 * Checks the object to see if it implements a certain function.
 *
 * @access public
 * @since  v1.1
 * @param  string   funcName   Name of function to check for
 * @return boolean
 */



/**
 * Generates an xml string representation of the object.
 *
 * @access public
 * @since  v1.1
 * @param  string   tagname   Tag name to use for the object
 * @return string
 */
/*
Object.prototype.simpleXmlify = function(tagname) {
    var xml = "<"+tagname;
    for (var prop in this) {
        if (!(this[prop] instanceof Function)) {
            xml += " "+prop+"=\""+this[prop]+"\"";
        }
    }
    xml += "/>";
    return xml;
}
*/


/**
 * Finds the index of a value in the array or returns false if not found.
 *
 * @acccess public
 * @since   v1.1
 * @param   mixed val     Value to search array for
 * @return  int | false
 */
Array.prototype.inArray = function(val) {
    for (var i=0; i<this.length; i++) {
        if (this[i] == val) return i;
    }
    return false;
}
// Remove object helper methods from array
Array.prototype.simpleXmlify   = null;
// Remove object helper methods from Error
Error.prototype.simpleXmlify   = null;






/**
 * Generalize namespace for utility functions
 *
 * @access public
 * @since  v1.1
 */
var util = new Object;






/**
 * Manages image cacheing
 *
 * @todo   Confirm this image cacheing scheme works in IE & FF via fiddler
 *
 * @access public
 * @since  v1.1
 */
util.resourceManager = {

    cache: new Array,

    index: new Array,

    /**
     * Handles cacheing and returns the image src of a url.
     * 
     * @access public
     * @since  v1.1
     * @param  string   url
     * @return Image.src
     */ 
    get: function(url) {
        var ptr = util.resourceManager.index.inArray(url);
        if (ptr === false) {
            ptr                                 = util.resourceManager.index.length;
            util.resourceManager.index[ptr]     = url;
            util.resourceManager.cache[ptr]     = new Image;
            util.resourceManager.cache[ptr].src = url;
        }
        return util.resourceManager.cache[ptr].src;
    }
    
};



/**
 * This function returns the name of a given function.
 *
 * It does this by converting the function to a string,
 * then using a regular expression to extract the
 * function name from the resulting code.
 *
 * @access public
 * @since  v1.1
 * @param  Function  f
 * @return string
 */
function funcname(f) {
    var matches = f.toString().match(/function (\w*)/);
    if ((matches == null) || (matches.length == 0)) return "anonymous";
    if (matches.length == 2) return matches[1];
    else return matches.join(',');
}

/**
 * This function returns a string that contains a "stack trace".
 *
 * @access public
 * @since  v1.1
 * @return string
 */
function stacktrace() {
    var s = "";  // This is the string we'll return.
    // Loop through the stack of functions, using the caller property of
    // one arguments object to refer to the next arguments object on the
    // stack.
    for (var a=arguments.caller; a!=null; a=a.caller) {
        // Add the name of the current function to the return value.
        s += funcname(a.callee) + "\n";
        // Because of a bug in Navigator 4.0, we need this line to break.
        // a.caller will equal a rather than null when we reach the end 
        // of the stack. The following line works around this.
        if (a.caller == a) break;
    }
    return s;
}















/***** BEGIN MESSAGE QUEUE *******/




util.MessageQueue = function(type) {
    this.queued = new Array;
    this.containerId = 'message';
    this.type = type || util.MessageQueue.types.ALL;
    this.queueId = util.MessageQueue.queues.length;
    this.waitingForResponse = false;
    util.MessageQueue.queues[this.queueId] = this;
    return this;
};

util.MessageQueue.settings = {
    timer:     null,
    interval:  5, // in seconds
    immediate: true
};

util.MessageQueue.types  = { NONE:0, ERROR:1, DEBUG:2, USER:4, ALL:7 };
util.MessageQueue.queues = [];


util.MessageQueue.attach = function(queue) {
    if (!util.MessageQueue.queues.inArray(queue)) {
        util.MessageQueue.queues.push(queue);
    }
    return true;
}

util.MessageQueue.detach = function(queue) {
    var retain = [];
    var found  = false;
    while (util.MessageQueue.queues.length) {
        var queuePop = util.MessageQueue.queues.pop();
        if (queue !== queuePop) retain.push(queuePop);
        else                    found = queuePop;
    }
    util.MessageQueue.queues = retain;
    return found;
}


util.MessageQueue.prototype.add = function(obj, test) {
    //alert('util.MessageQueue.add called: '+obj.title+' -> '+obj.content);
    test = test === false ? false : true;
    test = true;
    if ((test && this.isMessage(obj)) || !test) {
        //alert(obj);
        this.queued.push(obj);
        //alert(this.queued.toString());
    }
    if (util.MessageQueue.settings.immediate) this.renderNext();
}

util.MessageQueue.prototype.isMessage = function(obj) {
    return obj.implementsProp('title') && obj.implementsProp('content') && obj.implementsProp('type');
} 

util.MessageQueue.prototype.render = function(type) {
    if (this.queued.length > 0) {
        var body = document.getElementsByTagName('body')[0];
        if (body) {
            var types = util.MessageQueue.types;
            type = type <= types.ALL ? type : types.ALL;
            var messages = new Array;
            if (type == types.ALL) {
                messages = this.queued;
                this.queued = new Array;
            } else {
                var retain = new Array;
                for (var i=0; i<this.queued.length; i++) {
                    var msg = this.queued[i];
                    if (msg.type == type) {
                        messages.push(msg);
                    } else {
                        retain.push(msg);
                    }
                }
                this.queued = retain;
            }
            if (!this.container) {
                this.container = document.createElement('div');
                this.container.className = 'messageContainer';
                body.appendChild(this.container);
            }
            for (var i=0; i<messages.length; i++) {
                var mesg = messages[i];
                mesg.displayHandler();
            }
        }
    }
}









util.MessageQueue.prototype.renderNext = function(force) {
    force = force || false;
    if (force) {
        this.waitingForResponse = false;
        clearInterval(this.renderNextTimeout);
        this.renderNextTimeout = null;
    }
    if (this.queued.length > 0) {
        if (!this.waitingForResponse) {
            //Assert.warn('util.MessageQueue.renderNext:displaying from queue '+this.queueId+', queue length = '+this.queued.length);
            var body = document.getElementsByTagName('body')[0];
            if (!body) throw new Error('Unable to find body element');
            var message = null;
            var queueHead = new Array;
            do {
                message = this.queued.shift();
                //Assert.warn('util.MessageQueue.renderNext:shift message type = '+message.type);
                if (message.type != this.type && this.type != util.MessageQueue.types.ALL) {
                    //Assert.warn('util.MessageQueue.renderNext:not all queue, not our message type');
                    queueHead.push(message);
                    message = null;
                }
            } while (!message && this.queued.length > 0);
            while (queueHead.length > 0) {
                this.queued.unshift(queueHead.shift());
            }
            if (message) {
                this.waitingForResponse = true;
                message.displayHandler();
            }
        } else if (!this.renderNextTimer) {
            //Assert.warn('util.MessageQueue.renderNext:setting renderNext timer -- '+this.queued.length+' messages remain');
            this.renderNextTimer = setInterval('util.MessageQueue.queues['+this.queueId+'].renderNext()', 1000);
        }
    }
}




window.messageQueue = new util.MessageQueue(util.MessageQueue.types.ALL);


/***** END MESSAGE QUEUE *******/

















/***** COOKIE MANAGEMENT *****/

/**
 * Creates a cookie via javascript
 *
 * @since  1.1.2.8
 * @access public
 * @param  string    name
 * @param  string    value
 * @param  int       ttl      Time to live, in seconds - defaults to session [optional]
 * @param  string    path     [optional]
 * @param  string    domain   [optional]
 * @param  boolean   secure   [optional]
 * @return void
 */
util.createCookie = function createCookie(name,value) {
    // Support optional arguments
    var argv    = arguments;
    var argc    = arguments.length;
    var ttl     = (argc > 2) ? argv[2]*1000 : null;
    var path    = (argc > 3) ? argv[3]      : null;
    var domain  = (argc > 4) ? argv[4]      : null;
    var secure  = (argc > 5) ? argv[5]      : false;
    // If we have a ttl to work with, calculate the expires
    if (ttl) {
        var expires = new Date();
        expires.setTime(expires.getTime()+ttl);
    }
    // Create the actual cookie
    document.cookie = name + "=" + escape (value) + 
                      ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + 
                      ((path    == null) ? "" : ("; path=" + path)) + 
                      ((domain  == null) ? "" : ("; domain=" + domain)) + 
                      ((secure  == true) ? "; secure" : "");
}

/**
 * Returns the value of a cookie
 * 
 * @since  1.1.2.8
 * @access public
 * @param  string    name
 * @return string
 */
util.readCookie = function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return unescape(c.substring(nameEQ.length,c.length));
    }
    return null;
}

/**
 * Removes a cookie
 *
 * @since  1.1.2.8
 * @access public
 * @param  string    name
 * @return void
 */
util.eraseCookie = function eraseCookie(name) {
    util.createCookie(name,"",-1);
}


