function ms_QueueManager() {

    // INTERNAL VARS
    var queue = [];
    var queueCurrentItem = null;
    var iframeDivId = '';
    var iframeId = '';
    var iframeBlankUrl = '';
    var isIframeReady = false;
    var isQueueRunning =  false;
    var requestMade = false;
    var waitingForResponse = false;
    
    // TIMERS
    var blankIframeTimer = null;
    var requestTimer = null;
    
    // COUNTERS
    var queuePosition = -1;
    var iframeTimeoutCounter = 0;
    var requestTimeoutCounter = 0;
    
    // CONSTANTS
    var TIMEOUT = 50; // in miliseconds
    var REQUEST_TIMEOUT = 10; // in seconds
    
    this.init = function(divId, blankUrl) {
		document.write('<div id="'+divId+'" style="position:absolute; bottom:0; left: -700px;"></div>');
        iframeDivId = divId;
        iframeId = divId+'_iframe';
        iframeBlankUrl = blankUrl;
        REQUEST_TIMEOUT = REQUEST_TIMEOUT * 1000; // set time to be in seconds
    }

    this.addRequest = function(queueItem) {
        queue[queue.length] = queueItem;
        if(isQueueRunning == false) {
            isQueueRunning = true;
            processQueue();
        }
    }
    
    this.requestReceived = function() {
        waitingForResponse = false;
        clearWaitForRequest();
        destroyIframe();
        processQueue();
    }
    
    var processQueue = function() {
        queuePosition++;
        if (queuePosition >= queue.length) {
            resetQueue(); // we have reached the end of the queue
        } else { // this is a new request to be made
            queueCurrentItem = queue[queuePosition];
            createIframe();
        }
    }
    
    var createIframe = function() {
		isIframeReady = false;
		//$(iframeDivId).innerHTML = '<iframe name="'+iframeId+'" id="'+iframeId+'" style="width: 100px; height: 100px; border: solid 1px blue;"></iframe>';
		//$(iframeId).src = iframeBlankUrl;
	  var thebody = document.getElementsByTagName("body")[0];
      var tempIFrame=document.createElement('iframe');
      tempIFrame.setAttribute('id',iframeId);
      tempIFrame.setAttribute('name',iframeId);
      tempIFrame.style.position='absolute';
      tempIFrame.style.bottom='0';
      tempIFrame.style.left='-600px';
	  //tempIFrame.src=iframeBlankUrl;
      thebody.appendChild(tempIFrame);
	  frames[iframeId].location.replace(iframeBlankUrl);
      //return false;
	  waitForRequest('iframe');


   }
    
    var destroyIframe = function() {
        $(iframeDivId).innerHTML = '';
		x = window.frames[iframeId];
		x.document.body.innerHTML = ""; 
    }
    
    var resetQueue = function() {
        isQueueRunning = false;
        destroyIframe();
        queue = [];
        queuePosition = -1;
        queueItem = null;
    }
    
    var doGet = function() {
        waitingForResponse = true;
        var url = makeQueryString(queueCurrentItem);
        frames[iframeId].location.replace(url);
        waitForRequest('get');
    }
    
    var doPost = function() {
        var html = drawForm(queueCurrentItem, 'msHiddenIframeForm');
        var iframeWin = getIframeWindow();
        waitingForResponse = true;
        iframeWin.document.body.innerHTML = html;
        iframeWin.document.getElementById('msHiddenIframeForm').submit();
        waitForRequest('post');
    }
    
    var waitForRequest = function(type) {
        switch(type) {
            case "post":
                if(waitingForResponse == false) {
                    clearWaitForRequest();
                    processQueue();
                    return;
                }
                break;
            case "get":
                if(waitingForResponse == false) {
                    clearWaitForRequest();
                    processQueue();
                    return;
                }
                break;
            case "blankForPost":
                if(isIframeReady == true) {
                    clearWaitForRequest();
                    doPost();
                    return;
                }
                break;
            case "iframe":
                if(isIframeReady == true) {
                    clearWaitForRequest();
                    if(queueCurrentItem.method == 'post') {
                        doPost();
                    } else {
                        doGet();
                    }
                    return;
                }
                break;
        }
        if((requestTimeoutCounter * TIMEOUT) >= REQUEST_TIMEOUT) {
            clearWaitForRequest();
            requestFailed(type);
            return;
        } else {
            requestTimeoutCounter++;
            requestTimer = setTimeout(function timeoutWaitForRequest() { waitForRequest(type) }, TIMEOUT);
        }
    }
    
    var clearWaitForRequest = function() {
        clearTimeout(requestTimer);
        requestTimeoutCounter = 0;
    }
    
    var requestFailed = function(type) {
        destroyIframe();
        var response = {};
        response['errors'] = ['request timed out'];
        eval(queueCurrentItem.params.callback + '(response);');
        processQueue();
    }
    
    var makeQueryString = function(queueItem) {
        var queryString = '';
        queryString += queueItem.url;
        if(queueItem.params.len > 0) {
            queryString += '?';
            var i = 0;
            for(key in queueItem.params) {
                if(key != 'len') {
                    queryString += key + '=' + escapeParam(queueItem.params[key]);
                    if(i < (queueItem.params.len - 1)) queryString += '&';
                }
                i++;
            }
        }
        return queryString;
    }
    
    var escapeParam = function(param) {
        return escape(param).replace(/\+/g, '%2b');
    }
    
    var drawForm = function(queueItem, formId) {
        var html = '';
        for(key in queueItem.params) {
            html += '<input type="hidden" name="'+key+'" value="'+queueItem.params[key]+'"/>';
        }
        html = '<form id="'+formId+'" method="'+queueItem.method+'" action="'+queueItem.url+'">' + html + '</form>';
        return html;
    }

    var getIframeWindow = function() {
        var r = $(iframeId).contentWindow || $(iframeId).contentDocument;
        return r;
    }
    
    this.setIframeReady = function() {
		isIframeReady = true;
    }
}

function ms_QueueItem(inUrl, inMethod) {
    
    var url = inUrl;
    var method = inMethod;
    var params = {};
    
    this.addParam = function(key, value) {
        params[key] = value;
    }
    
    this.getQueueItem = function() {
        var i=0;
        for(key in params) {
            i++;
        }
        params['len'] = i;
        return {
            "url": url,
            "method": method,
            "params": params
        };
    }
}
