
// Ajaaxutil class definition
//================================================
var ajaxUtil  = {};
if (! DATASTORE)
    { var DATASTORE = {}; }
var AJAX_LAST_HTTP_ERROR = '';
DATASTORE.pajajCurrentUrl = window.location.href;

ajaxUtil.processRequest = function(e, url, responder, action, preAction, extra) {
    if (e && !e.isPajajEvent)   
        { e = new DOM2Event(e, window.event, this); }
    url = (url) ?url :DATASTORE.pajajCurrentUrl;

    if (!e || !e.target) {
        var value = null;
        var data  = {
          responder:    responder,
          url:          DATASTORE.pajajCurrentUrl
        }
        if (e.id) 
            { data['id'] = e.id; data['idCurrent'] = e.id; }
    } else {
        var value = e.target.value;
        var data  = {
            responder:    responder, 
            event:        e.type, 
            id:           e.target.id, 
            tag:          e.target.tagName, 
//          class:        e.target.className,
            idCurrent:    e.currentTarget.id, 
            tagCurrent:   e.currentTarget.tagName, 
            classCurrent: e.currentTarget.className,
            value:        e.target.value, 
            url:          DATASTORE.pajajCurrentUrl
        };
  
        if (e.target.data)
            { data.data = e.target.data; }

        if (e.target.tagName == 'FORM' || e.currentTarget.tagName  == 'FORM') {
            var formTarget = (e.target.tagName == 'FORM') ?e.target :e.currentTarget;
            data.formName  = formTarget.name;
            data.formData  = Form.serialize(formTarget); // Form data
        } else if (e.currentTarget.tagName  == 'TBODY' || e.currentTarget.tagName  == 'TABLE' ) {
            data.childData = ajaxUtil.getChildData(e.currentTarget, "tr", false);
        } else if (e.currentTarget.tagName  == 'UL') {
            data.childData = ajaxUtil.getChildData(e.currentTarget, "li", true);
        } else if (e.currentTarget.tagName  == 'DIV'){
            data.childData = ajaxUtil.getChildData(e.currentTarget, "DIV", true);
        } else if (e.currentTarget.tagName  == 'A')  {
            data.href      = e.currentTarget.href;
            data.title     = e.currentTarget.title;
        }
    }
    if (typeof (extra) == 'string') 
        { data['extra'] = extra; }

    aDebug("<h2>ajaxUtil.processRequest("+ responder +") data to post:</h2><br> " + data +"<br />"); 

    var post       = stringify(data);
    var parameters = "parameters=" + encodeURIComponent(post);
    var test       = true;

    if (preAction)
        { test = preAction(e); }

    url = url.replace(/#[a-z0-9-]+$/, "");
    if (test) {
        var temp = post;
        temp      = temp.replace(/"formName"/g, '<br \>&nbsp;&nbsp; "formName"').replace(/"data"/g, '<br \>&nbsp;&nbsp;  "data"');
        aDebug("Posting ("+responder+"):= <br />&nbsp;&nbsp;*"+ temp +"<br />&nbsp;&nbsp;*to URL:= "+ url); 
    	try {
            var rslt = new Ajax.Request(url, { 
                onSuccess:    function(arg1,arg2,arg3) { AJAX_LAST_HTTP_ERROR=''; action(arg1, arg2, arg3)},
                onFailure:    function(t)              { ajaxUtil.reportError(t); },
                on404:        function(t)              { alert('Error 404: location "' + t.statusText + '" was not found. Tried(' +url +')'); },
                method:       'post',
                asynchronous: true,
                header:       [["Content-Type", "text/plain"]],
                parameters:   parameters,
                FROM_PERIODIC: (typeof(FROM_PERIODIC)!="undefined" && FROM_PERIODIC)
            });
        } catch(e) { 
            alert("Error Ajax.Request() posted to URL:="+ url); i
        }
    } else {
        var tag = (e && e.target && e.target.tagName) ?e.target.tagName :"(no tag name)";
        aDebug('ajaxUtil.processRequest(' +responder + ') test ' + preAction + ' failed! For: ' + tag); 
    }
}

ajaxUtil.processReturnTest = function(rslt) {
    if (rslt.readyState==4) {
        if (rslt.status==200){
            if (debugTest) { 
                var retCode = rslt.responseText;
                retCode     = retCode.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\\\//g, "\/").replace(/,\"/g, ",<br />\"");
                debug('<h2>ajaxUtil.processReturnTest before ajaxUtil.processReturn:</h2>'+ retCode); 
            }
            return true;
        } else if (rslt.status > 0 && rlst.statusText) { 
            alert('There was a problem retrieving data:' + rslt.statusText); 
        }
    }
    return false;
}

ajaxUtil.processReturn = function(rslt) {
   var input = eval(rslt.responseText);
   
   for(var x=0; x < input.length; x+=2) {
       var type  = input[x];
       var pre   = input[x+1];

        switch(type) {
            default:               alert('No return expected: ' + rslt.responseText); break;
            case "NONE":           break;
            case "HTML":
            case "MIXED":          var data = pre; break;
            case "OBJECT":         var dataObject = eval('(' + pre + ')'); break;
            case "ALERT":          alert(pre); break;
            case "JAVASCRIPT":     eval(pre);  break;
            case "RESET_RULES":    EventSelectors.assign(Rules); break;
            case "CHANGE_URL":     if (pre && pre != null && pre != 0)
                                        { window.location = pre; DATASTORE.pajajCurrentUrl = pre; }
                                   else { window.location.reload(); }
                                   break;
            case "RESPONDER_INFO": aDebug('<b>Responder:</b>'+ pre.responder +' <b>Method:</b>'+ pre.method +'<br />'); break;
            case "CHANGE_BACKGROUND": 
            case "CHANGE_INNERHTML":
            case "CHANGE_CLASS":
            case "ADD_CLASS":
            case "REMOVE_CLASS":
            case "TOGGLE_CLASS":
            case "CHANGE_VALUE":
            case "CHANGE_SELECTOR":
            case "SET_DATA_TAG":
            case "VISUAL_EFFECT":
            case "HIDE_SHOW":
            case "BUSY":
            case "EFFECT":
                for (var i in pre) {
                    if ($(i)) {
                        switch(type) {
                            case "CHANGE_BACKGROUND":$(i).style.backgroundImage = "url(" + pre[i] +")";  break;
                            case "CHANGE_INNERHTML": $(i).innerHTML = pre[i];                            break;
                            case "CHANGE_CLASS":     $(i).className = pre[i];                            break;
                            case "ADD_CLASS":        $(i).addClassName(pre[i]);                          break;
                            case "REMOVE_CLASS":     $(i).removeClassName(pre[i]);                       break;
                            case "TOGGLE_CLASS":     $(i).toggleClassName(pre[i]);                       break;
                            case "CHANGE_VALUE":     $(i).value     = pre[i];                            break;
                            case "CHANGE_SELECTOR":  setOptions($(i), pre[i][0], pre[i][1], null, null); break;
                            case "SET_DATA_TAG":     $(i).data = pre[i];                                 break;
                            case "SCRIPT_ACULO_US_VIS_EFFECT": new Effect.ajaja($(i));                   break;
                            case "HIDE_SHOW":        $(i).style.display = (pre[i]) ?"" :"none";          break;
                            case "BUSY":             setBusy(i, (pre[i])?1:0, 'busy', 30);               break;
                            case "EFFECT":           
                                switch(pre[i]) {
                                    case "HIGHLIGHT": new Effect.Highlight($(i), {duration: 2.0});       break;
                                }
                        }
                    }
                }
                break;
            case "LOAD_FILE":     for (var i in pre) { ajaxUtil.loadFile(pre[i], i); } break;
            case "SCROLL_TO":     for (var i in pre) { ajaxUtil.scrollTo(pre[i], i); } break;
            case "DATASTORE_SET": for (var i in pre) { DATASTORE[i] = pre[i]; }        break;
            case "DATASTORE_APPEND":
                 for (var i in pre) { 
                     if (DATASTORE[i] && typeof DATASTORE[i] == 'object' && typeof pre[i] == 'object')
                          { Object.extend(DATASTORE[i], pre[i]); }
                     else { DATASTORE[i] = pre[i]; }
                 }
                 break;
             case "TIMER_START":
                  break;
             case "TIMER_STOP":
                  break;
             case "UPDATE_CHECKER_START":
                  break;
             case "UPDATE_CHECKER_STOP":
                  break;
             case "SET_EVENT_HANDLER":
                  break;
                  
             case "UPDATE_TABLE_ROWS":
                 for (table in pre) {
                     for (row in pre[table]) {
                         for (td in pre[table][row]) {
                             if ($(td)) 
                                 { $(td).innerHTML = pre[table][row][td]; }
                         }
                     }
                 }
                 break;
             case "CODE_COMMENT":
                 break; // do nothing right now with code comments
         }
     }
     return data;
}

ajaxUtil.getChildData = function(e, tag, getChildIds) {
    var childArray    = e.getElementsByTagName(tag);
    var childCount    = childArray.length;
    var data          = new Array();
    var order         = new Array();
    
    data[data.length] = ["childCount", childCount];
    if (childCount) { 
        if (getChildIds) {
	      for(i = 0; i < childArray.length; i++)
                { order[order.length] = childArray[i].id; }
            data[data.length] = ["childOrder", order];
        }
        data[data.length] = ["firstChildId", childArray[0].id]; 
        data[data.length] = ["lastChildId",  childArray[childCount -1].id]; 
    } 

    return data;
}

ajaxUtil.loadFile = function(file, id) {
    var tag  = null;
    if (file.indexOf('.js') != -1) {
        tag      = document.createElement('script');
        tag.type = 'text/javascript';
        tag.src  = file;
    } else if (file.indexOf('.css') != -1) {
        tag      = document.createElement("link");
        tag.rel  = "stylesheet";
        tag.type = "text/css";
        tag.href = file;
    }
    if (tag) {
        tag.id   = id;
        var head = document.getElementsByTagName("head")[0];
        head.appendChild(tag);
        aDebug('Loading file: '+ file +' into browser.');
    }
}

ajaxUtil.scrollTo = function(parent, archor) {
    var holder     = (parent && parent != 'window') ?$(parent) :window;
    var pageAnchor = $(archor);
    var delta      = pageAnchor.offsetTop - holder.scrollTop;
    new Effect.Scroll(holder, { y: delta, duration: 0.2 });

//  var updateUrl  = function(){ }
//  new Effect.Scroll(holder, { y: delta, afterFinish: updateUrl, duration: 0.2 });
}

ajaxUtil.reportError = function(t) {
    var status = t.status;
    switch(status){
        // Server timeout
        case 12002:
        // dropped connections.
        case 12029:
        case 12030:
        case 12031:
        // Connection closed by server.
        case 12152:
        case 301:
            var msg1 = "Error(" + status +"): The browser is having a problem connecting to the application's web server. Reason: ";
            var msg2 = "server dropped connection";
            msg2     = (status == 12002)                  ?"timeout trying to talk to server" :msg2;
            msg2     = (status == 12152 || status == 301) ?"connection closed by server"      :msg2
            if (AJAX_LAST_HTTP_ERROR != 'connection') {
                alert (msg1 + msg2 +'.');
                AJAX_LAST_HTTP_ERROR = 'connection';
            }
            break;
        default:
            if (AJAX_LAST_HTTP_ERROR != status) {
                alert('Error(' + status + '): unknown browser error, ' + statusText +'. URL:(' + url +')'); 
                AJAX_LAST_HTTP_ERROR = status;
            }
            break;
    }
}


// Debug output
//================================================
function aDebug(text){ 
    if (debugTest) { debug(text); } 
}
function ade(event, that) {
    var eventType = event.type;
    var id        = (that.id) ?that.id :that.tagName +' with no ID';
    aDebug('<b>Firing event handler() event('+ eventType +') on ('+ id +')</b>');
}

// Other Events
//================================================
function eventOnReady() {
    this.isPajajEvent  = true;
    this.target        = window.document.body;
    this.currentTarget = window.document.body;
    this.event         = "onReady";
}

function eventOnLoad() {
    this.isPajajEvent  = true;
    this.target        = window.document.body;
    this.currentTarget = window.document.body;
    this.event         = "onLoad";
}

function elementUpdateObj(e, evt) {
    el = (e) ?$(e) :window;
    this.isPajajEvent  = true;
    this.target        = el;
    this.currentTarget = el;
    this.event         = (evt) ?evt :"elementUpdate";
    if (!el)
        { this.id = e; }
}

function methodCallObj(e, method, data) {
    this.isPajajEvent  = true;
    this.target        = e;
    this.currentTarget = e;
    this.event         = "methodCall";
    this.method        = method;
    this.data          = data;
}

// Timer event definition
//================================================
function TimeoutEventObj(e, Timer) {
    this.isPajajEvent  = true;
    this.target        = e;
    this.currentTarget = e;
    this.event         = "timeout";
    this.TimerObj      = Timer;
}

function checkUptoDateObj(e, Timer) {
    this.isPajajEvent  = true;
    this.target        = e;
    this.currentTarget = e;
    this.event         = "checkUptoDate";
    this.TimerObj      = Timer;
}


// Busy
//================================================

var BusyRequests = [];

/* 
Show or hide a busy indicator and optional message, overlaying specified
DIV.  Most styles can be defined in CSS, not here.  Dimensions and postion
of the busy layer are derived from the target element, but can be 
overridden via arg #9.
Args:
1. id: element to overlay
2. busy: 1 to show busy layer, 0 to hide it
3. busyClass: optional CSS class of busy layer, default 'busy'
4. timeOut: optional number of seconds before busy div goes away, 
   default 10.  Use -1 to indicate no timeout.
5. timeOutContent: optional string to display after timeout occurs
6. timeOutClass: optional CSS class for timeout messsage, default 
   'busytimeouterror'
7. busyText: optional message to display on the busy layer
8. busyTextDivId: optional ID for the busy text element, default 'busytext'
9. busyTextPos_json: optional JSON object that specifies top, left, 
   and width of busytext; otherwise busytext dimensions & position are 
   derived from busydiv.
*/
function setBusy(id, busy, busyClass, timeOut, timeOutContent, timeOutClass, busyText, busyTextDivId, busyTextPos_json) {
    var elem = id ? $(id) : document.body;

    // attaching the busydiv to the element's parent allows busy-ing of 
    // inputs and images, but there's a problem in ie6 i haven't figured out yet.
    //elemParent = (elem.offsetParent || document.body); <-- not working in IE6
    elemParent = elem;
    var busyid = id + '_busy';
    if (!busyClass) 
        { busyClass = 'busy'; }
    if (timeOut > 0) 
         { timeOut *= 1000; }
    else if (timeOut == 0) { timeOut = 10000; } // default = 10 seconds
    if (!timeOutClass) 
        { timeOutClass = 'busytimeouterror'; }
    if (!busyTextDivId) 
        { busyTextDivId = 'busytext'; }

    if (busy && !($(busyid))) {
        var busydiv = document.createElement('div');
        busydiv.id = busyid;
        busydiv.className = busyClass;
        elemParent.appendChild (busydiv);

        Position.absolutize (busydiv);
        Position.clone (elem, busydiv, true, true, true, true);        
        if (busyText) {
            var txtNode = document.createElement('div');
            txtNode.id = busyTextDivId;
            txtNode.className = 'busytext';
            txtNode.innerHTML = busyText;
            elemParent.appendChild (txtNode);            
        }
        setBusySize(busyid, elem.id, busyTextDivId, busyTextPos_json);

        if (timeOut > 0) {
            // increment the counter on how many busy
            // requests there are for this id
            if (!BusyRequests[id]) 
                { BusyRequests[id] = 0; }
            ++BusyRequests[id];

            var autostop = "setBusy('"+ id +"', 0, '"+ busyClass +"', -1, '"+ timeOutContent +"', '"+ timeOutClass +"', '', '"+ busyTextDivId +"')";
            //alert (autostop);
            setTimeout (autostop, timeOut);
        }
    } else if (!busy && $(busyid)) {
        if (BusyRequests[id]) 
            { --BusyRequests[id]; }
        if (!BusyRequests[id]) {
            if ((timeOutContent && timeOutContent != 'undefined')) {
                // timeout error message set - display it
                $(busyid).className = timeOutClass;
                var contentNode = document.createElement('div');
                if (!timeOutClass) 
                    { timeOutClass = 'busytimeouterror'; }
                contentNode.className = timeOutClass;
                contentNode.innerHTML = timeOutContent;                
                $(busyid).appendChild (contentNode);

                if ($(busyTextDivId)) 
                    { discardElement ($(busyTextDivId)); } 

                // prevent any further timout updates to this div
                if (BusyRequests[id]) 
                    { BusyRequests[id] = 0; }
            } else {
                // remove busy div
                discardElement ($(busyid)); 
                if ($(busyTextDivId)) 
                    { discardElement ($(busyTextDivId)); } 
            }
        }
    }
}

/* 
Sets size and position of #busyDivId to match #busyElemId, and calculate
dimensions for busytext.
Args:
1. busyDivId: busy overlay div
2. busyElemId: target of busy overlay
3. busyTextId: optional ID of text message to display along with overlay.  If
   not specified, next arg is ignored.
4. busyTextPos_json: optional JSON object that specifies top, left, and width
   of busytext; otherwise dimensions & position are derived from #busyDivId.
*/
function setBusySize(busyDivId, busyElemId, busyTextId, busyTextPos_json) {

    if ($(busyDivId)) {
        if (busyElemId) {
            Position.clone ($(busyElemId), $(busyDivId), true, true, true, true);        
        } else {
            var L, T;
            if (typeof (window.pageYOffset) != 'undefined') {
                T = window.pageYOffset;
                L = window.pageXOffset;
            } else if (window.document.documentElement && typeof (window.document.documentElement.scrollTop) != 'undefined') {
                T = window.document.documentElement.scrollTop;
                L = window.document.documentElement.scrollLeft;
            } else if (window.document.body) {
                T = document.body.scrollTop;
                L = document.body.scrollLeft;
            }

            $(busyDivId).style.top  = T + 'px';
            $(busyDivId).style.left = L + 'px';
            

            if (self.innerHeight) {  // all except Explorer
                windowWidth = self.innerWidth;
                windowHeight = self.innerHeight;
            } else if (document.body) { // other Explorers
                windowWidth = document.body.clientWidth;
                windowHeight = document.body.clientHeight;
            } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
                windowWidth = document.documentElement.clientWidth;
                windowHeight = document.documentElement.clientHeight;
            }  
            
            $(busyDivId).style.height = windowHeight + 'px';
            $(busyDivId).style.width  = windowWidth  + 'px';
            
        }

        if ($(busyTextId)) {
            var txtNode = $(busyTextId);
            var busydiv = $(busyDivId);
            var busyLeft = parseInt(busydiv.style.left);
            var busyTop = parseInt(busydiv.style.top);
            var busyHeight = parseInt(busydiv.style.height);
            var busyWidth = parseInt(busydiv.style.width);
            var txtWidth = (busyWidth / 2);
            if(busyTextPos_json) {
                busyTextPos = busyTextPos_json.evalJSON(true);
                txtNode.style.top   = busyTextPos['top'];
                txtNode.style.left  = busyTextPos['left'];
                txtNode.style.width = busyTextPos['width'];
                busyTextPos_json = ",'" + busyTextPos_json +"'";
            }else{
                txtNode.style.top   = (busyTop + (busyHeight * .25)) + 'px';
                txtNode.style.left  = (busyLeft + ((busyWidth - txtWidth)/2)) + 'px';
                txtNode.style.width = txtWidth + 'px';
            }
        }

        // check again in 500 ms
        if (typeof busyTextPos_json == 'undefined') var busyTextPos_json = '';
        setTimeout("setBusySize ('"+ busyDivId +"', '"+ busyElemId +"', '"+ busyTextId +"'"+ busyTextPos_json +")", 500);
    }
}

// this is a one off since I keep running into RoboHelp, sorry I know it is bad coding
// RoboHelp Support
function doRoboHelpFromDataStore() { 
    if (RH_ShowHelp && DATASTORE && DATASTORE.roboHelpDir && DATASTORE.helpIndex) 
        { RH_ShowHelp(0,DATASTORE.roboHelpDir,HH_HELP_CONTEXT, DATASTORE.helpIndex); }
}
function doRoboHelpRoot() {
    if (RH_ShowHelp && DATASTORE && DATASTORE.roboHelpDir) 
        { RH_ShowHelp(0,DATASTORE.roboHelpDir,HH_HELP_CONTEXT, 0); }
}

// borrowed from
// http://www.outofhanwell.com/ieleak/index.php?title=Fixing_Leaks
// Removes element without causing IE memory leak
function discardElement(element) {
    var garbageBin = document.getElementById('IELeakGarbageBin');
    if (!garbageBin) {
        garbageBin = document.createElement('DIV');
        garbageBin.id = 'IELeakGarbageBin';
        garbageBin.style.display = 'none';
        document.body.appendChild(garbageBin);
    }

    // move the element to the garbage bin
    garbageBin.appendChild(element);
    garbageBin.innerHTML = '';
}

