// JSCafe Version Alpha 2.0, Complete Rewrite for cleaner coding and re-used routines.
// Seems to be noticabely faster, and should be much smaller.
// More advanced effects (combinations of other effects) and functions are included in a seperate file, and you can
// include your own function called "custom" to accept custom variables and functions.
// ------------------------------------------------------------------------------------
/*
    This file is subject to copright to Web Fresh.
    Public Sites and Partners must get approval to use the developer version, otherwise
    please use the smaller, compressed, and encrypted Application Version.
    >>> Works with IE7, Safari, Firefox, Opera and IE6 - We want TOTAL browser compatibilty and/or fallbacks
   
    Version: Private Alpha
    - As of June 11th
    
*/
// Required Variables
// -----------------------------
var method = "GET";
var jsCafe = null;                                  // The actual JSCafe Init Object
var thisObj = null;                               // The last object to execute an event
var serverURL = "backend";                        // URL to pass/retrieve data to/from
var taskbarObj = null;                            // UL object of the taskbar
var eventHandler = new eventHandlerObj();         // Event Handler Object
var tempId = new cTempId();                          // Assigns and Destroys Temporary ID's to objects
var dbug = null;                                  // Debug Object to Append Data to
var eventArray = new Array();                      // Array list of all events (hidden from the user)
var autoLoadOff;                                  // Set this to be true if you want to block the auto-load statement
var tempIdCounter = 0;                              // Temporay ID Counter for Effect Statements

var ie = window.ActiveXObject;                            // Detects usage of Internet Explorer (any version)
var ff=(String.prototype.__defineGetter__);               // Detects usage of Firefox
var nn6=(document.getElementById)&&(!document.all);   // Detects uage of Netscape Navigator 6

// Parsed Data
// -----------------------------
function ex(rawdata)
{
 // Parse data for an ":!"
 var lines = rawdata.split(":!");
 // Each command is split by spaces or linebreaks, and is not case sensitive
     for (var i = 0; i < lines.length; i++)
     {
        var curLine = lines[i].ltrim();
        var curline = curLine;
        if (curLine && curLine != "" && curLine.indexOf(":!"))
        {
            // Process Event, curLine has something in it.
            if (!getVar(curline, "delay", 0))
            {
                    // Not a delayed statement, execute immediately
                var cmd = getCommand(curLine);
                switch (cmd)
                {
					case "EVAL":
					  var code = getVar(curline, "code", "");
					  eval(code);
					break;
					
                    case "GETDATA":
                       var objects = getVar(curline, "obj", 0);
                       var param = getVar(curline, "param", "app");
                       var sendto = getVar(curline, "sendto", "");
					   var withid = getVar(curline, "withid", 0);
                       objects = objects.split(";");
                       
                       // Create JSCafe Ajax Object
                       var ajax = new jsAjax();
                       ajax.addParam(param, sendto);
                    
                       for (var n = 0; n < objects.length; n++)
                       {
                          var parsed = objects[n].split(">=");
                          var ident = parsed[1];
                          var obj = getElements(parsed[0]);
                          var strbuffer = "";
						  // Each object needs an id if withid is specified
						  
						  
                          for (var q = 0; q < obj.length; q++)
                          {
						
							var tVal = getValue(obj[q]);
							if (tVal + 1)
							{
							  if (!withid)
							  {
                             	 strbuffer = strbuffer + tVal + ";;";
							  }
							  else
							  {
							    tempId.assign(obj[q]);
							  	strbuffer = strbuffer + tVal + "=;" + obj[q].getAttribute("id") + ";;";  
							  }
							}
							
                          }
                          
                          ajax.addParam(ident, strbuffer);
						  
						 
                          
                       }
                       ajax.send();
                    break;
					
					
                    case "STRETCH":
                        // Stretches one object to match another's width (use for absolute positioned that can't use 100%)
                        // For use with items that NEED to be the object's width, use minwidth='atleastobj'
                        var obj = getElements(getVar(curline, "obj", blankArray()));
                        var stretchto = getElements(getVar(curline, "stretchto", blankArray()));
                        var minwidth = getVar(curline, "min", 0);
                        
                        
                        
                        
                        stretchto = stretchto[0];
                        
                        // Execute it man, execute it.
                        for (var n = 0; n < obj.length; n++)
                        {
                            var tWidth = stretchto.offsetWidth;
                            var min2 = minwidth;
                            
                            if (min2 == "atleastobj")
                            {
                                // Find the objet's width
                                min2 = obj[n].offsetWidth;
                            }
                            

                            if (tWidth < min2){tWidth = min2;}
                            
                            // IE adds extra, use ieadjust property
                            if (ie)
                            {
                                var ieadjust = getVar(curline, "ieadjust", 0);    
                                tWidth = tWidth + parseFloat(ieadjust);
                            }

                            	obj[n].style.width = tWidth + "px";
                        }
                    break;
                    
                    case "EVENT":
                        // Assign event using event manager
                        var obj = getElements(getVar(curline, "obj", blankArray()));
                        var type = getVar(curline, "type", "click");
                        var code = getVar(curline, "code", "");
						var del = getVar(curline, "delete", 0);
                        
                        // function(object, code, type)
                        for (var n = 0; n < obj.length; n++)
                        {
							if (!del)
							{
                           	 eventHandler.addAction(obj[n], code, type);
							}
							else
							{
							 eventHandler.removeAction(obj[n], type);	
							}
                        }
                    break;
                    
                    case "EFFECT":
                        var streffect = getVar(curline, "type", 0).toLowerCase();
                        var obj = getElements(getVar(curline, "obj", blankArray()));
                        var display = getVar(curline, "display", "");
                        
                        // Go through all objects, and assign temporary id's if needed.
                        for (var n = 0; n < obj.length; n++)
                        {
                            tempId.assign(obj[n]);    
                        }
                        
                        switch (streffect)
                        {
                            // Scale Function
                            /*
                                Scales an object dynamically for visual effect of popping in or out
                                From = Top, Bottom
                            */
                            case "scale":
                                var execTime = getVar(curline, "time", 1000);
                                switch (getVar(curline, "from", "top").toLowerCase())
                                {
                                    case "top":
                                        // Show, start from top
                                        // Default is inline
                                        var display = getVar(curline, "display", "");
                                        for (var n = 0; n < obj.length; n++)
                                        {
                                            // We need it invisible for slower browsers
                                            obj[n].style.visibility = "hidden";
                                            
                                            // Change the display property
                                            obj[n].style.display = display;
                                            
                                            // Retrieve the offsetHeight
                                            obj[n].style.height = "";
                                            var maxExecute = obj[n].offsetHeight;
                                            
                                            // And make it visible again
                                            obj[n].style.visibility = "";
                                            
                                            // Set height at start, zero.
                                            obj[n].style.height = "0px";    
                                            
                                            // Overflow needs to be hidden for this to work
                                            var oldOverflow = obj[n].style.overflow;
                                            obj[n].style.overflow = "hidden";
                                            
                                            // Finally, get object's id
                                            var myId = obj[n].id;
                                            
                                            // Generate how quickly we should execute it based on execTime and maxHeight
                                            var ms = execTime / maxExecute;    
                                            ////////////////////////////
                                            // Execute Scale Function
                                            ////////////////////////////
                                            // function delay(id, style, value, ms)
                                            
                                            for (var qq = 0; qq <= maxExecute; qq++)
                                            {
                                                delayStyle(myId, "height", qq + "px", ms * qq);
                                            }
                                            
                                            // Reset overflow at the end
                                            delayStyle(myId, "overflow", oldOverflow, ms * qq);
                                            
                                        }
                                    break;
                                    case "bot":
                                        // Hide, start from bottom
                                        // Display will be none at end
                                        var display = "none";
                                        for (var n = 0; n < obj.length; n++)
                                        {
                                            // Retrieve the offsetHeight
                                            var maxExecute = obj[n].offsetHeight;
                                            
                                            // Overflow needs to be hidden for this to work
                                            var oldOverflow = obj[n].style.overflow;
                                            obj[n].style.overflow = "hidden";
                                            
                                            // Finally, get object's id
                                            var myId = obj[n].id;
                                            
                                            // Generate how quickly we should execute it based on execTime and maxHeight
                                            var ms = execTime / maxExecute;    
                            
                                            ////////////////////////////
                                            // Execute Scale Function
                                            ////////////////////////////
                                            // function delay(id, style, value, ms)
                                            var qq = 0;
                                            
                                            for (var q = maxExecute; q >= 0; q--)
                                            {
                                                delayStyle(myId, "height", q + "px", ms * qq);
                                                qq++;
                                            }
                                            
                                            // Reset overflow at the end and hide
                                            delayStyle(myId, "overflow", oldOverflow, ms * qq);
                                            delayStyle(myId, "display", "none", ms * qq);
                                        }
                                    break;
                                }
                            break;
                            
                            // Adjacent Function
                            /*
                                Places an object (positioned absolutely) above, below, on another object,
                                with chosen padding if any.
                            */
                            case "adjacent":
                                // Get the object to place next to, this isnt ready for multiple element placing yet
                                var objNext = getElements(getVar(curline, "nextto", blankArray()));
                                var padding = getVar(curline, "padding", 0);
                                objNext = objNext[0];
                                switch (getVar(curline, "position", "below").toLowerCase())
                                {
                                    
                                    case "on":
                                        var adjustleft = -20; //getVar(curline, "adjustleft", 0);
                                        var adjusttop = -10; //getvar(curline, "adjusttop", 0);
                                        
                                        for (var n = 0; n < obj.length; n++)
                                        {
                                            // No padding, just placed ON the object's left and top coordinates
                                            // However, we have adjustment values
                                            var pos = findPos(objNext);
                                            
                                            obj[n].style.top = (pos[1] + adjusttop) + "px";
                                            obj[n].style.left = (pos[0] + adjustleft) + "px";
                                        }
                                    break;
                                    
                                    case "below":
                                        for (var n = 0; n < obj.length; n++)
                                        {
                                            var pad = padding;
                                            // Object Padding or Absolute Padding?
                                            if (padding && padding.substring(0, 4) == "obj+")
                                            {
                                                pad = obj[n].offsetHeight + parseFloat(padding.substring(4));
                                            }
                                            
                                            var pos = findPos(objNext);
                                            
                                            obj[n].style.top = (parseFloat(pos[1]) + parseFloat(objNext.offsetHeight) + parseFloat(pad)) + "px";
                                            obj[n].style.left = pos[0] + "px";
                                        }
                                    break;
                                    case "above":
                                        for (var n = 0; n < obj.length; n++)
                                        {
                                            var pad = padding;
                                            // Object Padding or Absolute Padding?
                                            if (padding && padding.substring(0, 4) == "obj+")
                                            {
                                                pad = obj[n].offsetHeight + parseFloat(padding.substring(4));
                                            }
                                            
                                            var pos = findPos(objNext);
                                            obj[n].style.top = (parseFloat(pos[1]) - parseFloat(pad)) + "px";
                                            obj[n].style.left = pos[0] + "px";
                                        }
                                    break;
                                }
                            break;
                        }
                        
                        // Go through all objects, and remove temporary id's if needed.
                        for (var n = 0; n < obj.length; n++)
                        {
                            clearTemp(obj[n].id, ms * qq + 1);
                        }
                        
                    break;
                    // Launches a window, many new options available
                    /*
                        Action = Create (default), Set Property (setprop),
                        Get Property (getprop), Show (make visible, remove from taskbar),
                        Hide (make invisible), Minimize (Hide and add to taskbar), Maximize (Maximize automatically)
                        
                        Need to allow auto-centering of the window!!!
                        oh and Modal Format.
                        
                        Id = Id of Window, Always required.
                        
                        Max = 0 (No Max Button) 1 (Max Button)
                            OnResize: A server-sensitive resize (specifify application parameter)
                            - Sends Height and Width of the Window as well as the Id
                            
                        Min = 0 (No Minimize Button) 1 (Minimize Button)
                            OnMini: A server-sensitive minimize (specifify application parameter)
                            - Sends 'Visible' = True if Visible, or False if minimized as well as the Id
                            
                        Close = 0 (No Close Button) 1 (Close Button)
                            OnClose: A server-sensitive close (specifiy application paramter)
                            - A window with onClose will NOT close, but mearly tell the server
                              that the user wishes to close their window. You must send back
                              a kill statement with the window id to "close" it, or perhaps
                              a dialog or other options.
                        

                        Height and Width Variables of course
                        
                        Title = Text, For a title-less window (it cant be moved or resized), do not enter a title
                        
                        Locked = 0 (Not locked, freely movable), 1 = (locked in place)
                        
                        InnerText = Text, A new option to place HTML directly inside without a seperate edit statement
                        
                        Hidden = 0 (Visible) 1 (Hidden). Often used if you want the window to "fly in", or other entry effects
                        
                        Icon = URL (url to a 32x32 icon for the titlebar)
    
                        ***** Options to add in later releases *****
                        - Set/get properties of a window
                        - Check window to see if its currently visible
                        - Add Icons to the statusbar, and you can make those clickable
                        StatusText = Text, You can set the status bar text of the window
                        Resizable = 0 (Not resizable) or 1 (resizable freely, needs statusbar fyi)
                        Locked 2 = (locked and centered)
                        
                        onClose, onMini, onResize, getprop, setprop, hide, minimize, maximize
    
                        
                    */
                    case "WINDOW":
                        var straction = getVar(curline, "action", "create").toLowerCase();
                        var id = getVar(curline, "id", 0);
                        var obj = document.getElementById(id);
                        
                        // Default of show if window already exists
                        if (obj && straction == "create")
                        {straction = "show";}
                        
                        switch (straction)
                        {
                            case "show":
                            // Shows window if it exists
                            if (obj)
                            {
                                obj.style["display"] = "";
                            }
                            
                            case "create":
                            // Creates a window if it does NOT exist
                            if (!obj)
                            {
                                var newWindow = document.createElement("div");
                                var vLocked = getVar(curline, "locked", 0);
                                
                                // Some window parts just work different on different browsers
                                // Cross checks launched for IE and Firefox, everything else is labeled Opera and Safari
                                
                                if (ie)
                                    {
                                        newWindow.className = "ie window";
                                    }
                                    else
                                    {
                                        if (ff)
                                        {
                                            newWindow.className = "ff window";
                                        }
                                        else
                                        {
                                            newWindow.className = "opera safari window";
                                        }
                                    }
                                newWindow.id = id;
                                
                                // Retrieve Variables
                                var vTitle = getVar(curline, "title", null);
                                if (vTitle)
                                {
                                    // If we have a titlebar
                                    var newTitle = document.createElement("div");
                                    newTitle.className = "titlebar";    
                                    
                                    // Check if its locked, if not add classname of freedrag (freely draggable)
                                    if (!vLocked)
                                    {
                                        newTitle.className = newTitle.className + " freedrag dragparent";
                                    }
                                    
                                    // If we have an icon
                                    var vIcon = getVar(curline, "icon", null);
                                    if (vIcon)
                                    {
                                        var newIcon = document.createElement("img");
                                        newIcon.src = vIcon;
                                        newTitle.appendChild(newIcon);
                                    }
                                    
                                    // Once the icon may or may not be in place, insert the title of the window
                                    addData(newTitle, vTitle, 0);
                                    
                                    
                                    // Now add the buttons, if applicable
                                    var vMax = getVar(curline, "max", 0);
                                    var vMin = getVar(curline, "min", 0);
                                    var vClose = getVar(curline, "close", 0);
                                    
                                    if (vMin)
                                    {
                                        var newMin = document.createElement("span");
                                        newMin.className = "winbtn min";
                                        
                                        // *** Add event to minimize
                                        // \\
                                        
                                        newTitle.appendChild(newMin);
                                    }
                                    
                                    if (vMax)
                                    {
                                        var newMax = document.createElement("span");
                                        newMax.className = "winbtn max";
                                        
                                        // *** Add event to maximize
                                        // \\
                                        
                                        newTitle.appendChild(newMax);
                                    }
                                    
                                    if (vClose)
                                    {
                                        var newClose = document.createElement("span");
                                        newClose.className = "winbtn close";
                                        
                                        // *** Add event to close
                                        // \\
                                        
                                        newTitle.appendChild(newClose);
                                    }
                                    
                                    // --- Titlebar complete, add to window
                                    newWindow.appendChild(newTitle);
                                }
                                
                                
                                
                                // Set innerText inside of object
                                var innerText = getVar(curline, "innertext", "");
                                addData(newWindow, innerText, 0);
                                
                                // No status bar for now *** implement ***
                                
                                // Other properties of the window
                                var vHidden = getVar(curline, "hidden", 0);
                                if (vHidden){newWindow.style["display"] = "none";}
                                newWindow.style["height"] = getVar(curline, "height", "300px");
                                newWindow.style["width"] = getVar(curline, "width", "300px");
                                
                                
                                // Finally, insert it into the DOM
                                document.body.appendChild(newWindow);
                                
                                
                            }
                        }
                    break;
                    
					// On Focus Select Text
					case "ONFOCUS_SELECT":
					 var obj = getElements(getVar(curline, "obj", 0));
					 for (var n = 0; n < obj.length; n++)
                     {
						eventHandler.add(obj[n], "focus", function(){this.select();}); 
					 }
					break;
					
                    // Easy On Focus
                    case "ONFOCUS":
                    var obj = getElements(getVar(curline, "obj", 0));
                     var class3 = getVar(curline, "class", "focus");
                     for (var n = 0; n < obj.length; n++)
                     {
                        // function editClass(object, className, type, newClass)
                        eventHandler.add(obj[n], "focus", function()
                        {
                            editClass(this, class3, "", "");
                        });
                        
                        eventHandler.add(obj[n], "blur", function()
                        {
                            editClass(this, class3, "rep", "");
                        });
                     }
                    break;
                    
                    // Easy Rollover
                    case "ROLLOVER":
                     var obj = getElements(getVar(curline, "obj", 0));
                     var class2 = getVar(curline, "class", "hover");
                     for (var n = 0; n < obj.length; n++)
                     {
                        // function editClass(object, className, type, newClass)
                        eventHandler.add(obj[n], "mouseover", function()
                        {
                            editClass(this, class2, "", "");
                        });
                        
                        eventHandler.add(obj[n], "mouseout", function()
                        {
                            editClass(this, class2, "rep", "");
                        });
                     }
                    break;
                    
                    // Redirects the user to another page or site
                    case "REDIRECT":
                    
                    var url = getVar(curline, "url", window.location);
                    
                    var obj = getElements(getVar(curline, "obj", 0));
                    if (obj)
                    {
                        url = extractVarFromObject(obj[0], url);
                    }
                    
                    window.location = url;
                    
                    break;
                    
                    // Ping "bounces back" the parameter
                    case "PING":
                    
                    var paramName = getVar(curline, "param", "app");
                    var paramValue = getVar(curline, "value", "pong");
                      quickAjax(paramName, paramValue);
                    
                    break;
                    
                    // Disable/enable the input
                    case "ENABLE":
                    var obj = getElements(getVar(curline, "obj", 0));
                    var disabled = getVar(curline, "disabled", null);
                    
                    for (var n = 0; n < obj.length; n++)
                        {
                            obj[n].disabled = disabled;
                        }
                    break;
                    
                    // Physically Remove
                    case "KILL":
                    var obj = getElements(getVar(curline, "obj", 0));
                    for (var n = 0; n < obj.length; n++)
                        {
                            obj[n].parentNode.removeChild(obj[n]);
                        }
                    break;
                    
                    // Style statement
                    case "STYLE":
                     var obj = getElements(getVar(curline, "obj", 0));
                     var strStyle = getVar(curline, "style", "display");
                     var value = getVar(curline, "value", "");
                        for (var n = 0; n < obj.length; n++)
                        {
                            if (strStyle != "reset")
                            {
                                obj[n].style[strStyle] = value;
                            }
                            else
                            {
                                obj[n].style.cssText = "";
                            }
                        }
                        
                    break;
                        
                    // Select statement
                    case "SELECT":
                     var obj = getElements(getVar(curline, "obj", 0));
                        for (var n = 0; n < obj.length; n++)
                        {
                            obj[n].select();
                        }
                        
                    break;
                    // Unsimple clear statement
                    case "CLEAR":
                     var obj = getElements(getVar(curline, "obj", 0));
                        for (var n = 0; n < obj.length; n++)
                        {
                            setValue(obj[n], null);
                        }
                    break;
                    
                    // Simple focus statement
                    case "FOCUS":
                     var obj = getElements(getVar(curline, "obj", 0));
                        for (var n = 0; n < obj.length; n++)
                        {
                            obj[n].focus();    
                        }
                    break;
                    
                    // Simple alert statement
                    case "ALERT":
                        alert(getVar(curLine, "text", ""));
                    break;
                    
                    // Class Editor
                    case "CLASS":
                        var className = getVar(curline, "class", "");
                        var newClass = getVar(curline, "newclass", "");
                        var obj = getElements(getVar(curline, "obj", 0));
                        var type = getVar(curLine, "type", "add");
                        
                        for (var n = 0; n < obj.length; n++)
                        {
                            editClass(obj[n], className, type, newClass);
                        }
                    break;
                    
					// Submit a form with Javascript
					case "SUBMIT":
						var obj = getElements(getVar(curline, "obj", 0));
						for (var n = 0; n < obj.length; n++)
                        {
						 obj[n].submit();	
						}
					break;
					
                    // Append or Depend Inner HTML
                    case "APPEND":
                        var text = getVar(curline, "text", "");
                        var obj = getElements(getVar(curline, "obj", 0));
                        var top = getVar(curline, "top", 0);
                        
                        for (var n = 0; n < obj.length; n++)
                        {
                            addData(obj[n], text, top);    
                        }
                    break;
                    
                    // Edit INNER HTML of an Object
                    case "EDIT":
                        var text = getVar(curline, "text", "");
                        var obj = getElements(getVar(curline, "obj", 0));
                        for (var n = 0; n < obj.length; n++)
                        {
                            editData(obj[n], text);
                        }
                    break;
                    
                    // Other, probably an extender
                    default:
                    // Do we have JSCafe extended enabled?
                        if (typeof extended == "function")
                        {
                            if (0) //!extended(cmd, curLine))
                            {
                                // Do we have JSCafe custom?
                                if (typeof custom == "function")
                                {
                                    custom(cmd, curLine);    
                                }
                            }
                        }
                        else
                        {
                            if (0) // !extended(cmd, curLine))
                            {
                                // Do we have JSCafe custom?
                                if (typeof custom == "function")
                                {
                                    custom(cmd, curLine);    
                                }
                            }
                        }
                    break;
                }
            
            }
            else
            {
                // Delayed Execution
                var ms = getVar(curline, "delay", 0);
                var newLine = ":!" + curLine.replace("delay=", "_=");
                var code = "ex(\"" + newLine;
                setTimeout(code + "\")", ms);
            }
            
        }
        else
        {
            // Probably threw a server error or no proper code received, debug it
            dbugIt("[JSCafe] Could not handle: " + curLine);
        }
    }
}

// Required Functions
// -----------------------------
function setValue(object, value)
{
    switch (object.tagName.toLowerCase())
    {
        case "textarea":
            object.innerHTML = value;
        break;
        case "input":
            switch (object.getAttribute("type").toLowerCase())
            {
             case "hidden":
              object.value = value;
             break;
             case "password":
              object.value = value;
             break;
             case "text":
              object.value = value;
             break;
             case "checkbox":
              object.checked = value;
             break;
             case "radio":
              object.checked = value;
             break;
            }
        break;
        
        default:
         object.value = value;
        break;
    }
}

function getValue(object)
{
    switch (object.tagName.toLowerCase ())
    {
        case "textarea":
            return object.value;
        break;
        case "input":
            switch (object.getAttribute("type").toLowerCase())
            {
             case "hidden":
              return object.value;
             break;
             case "password":
              return object.value;
             break;
             case "text":
              return object.value;
             break;
             case "checkbox":
              if (object.checked)
              {
                 return object.value;
              }
              else
              {
                  return 0;
              }
             break;
             case "radio":
              if (object.checked )
              {
                 return object.value;
              }
              else
              {
                  return 0;
              }
             break;
            }
        break;
        
        case "select":
            if (object.options)
            {
                // Internet Explorer uses a different way for selections
                return object.options(object.selectedIndex ).innerHTML;
            }
            else
            {
                return object.value;
            }
        break;
    }
}

function editClass(object, className, type, newClass)
{
	if (object)
	{
    switch (type.toLowerCase())
    {    
     case "rep":
     object.className = object.className.replace(className, newClass);
     break;
    
     case "set":
     object.className = className;
     break;
        
     default:
     // Add to className
     if (object.className.indexOf(className) == -1)
     {
         object.className = object.className + " " + className;
     }
     break;
    }
	}
}

function dbugIt(data)
{
if (dbug)
 {
     // If we have a debug object, append text and a linebreak
    addData(dbug, data + "<br />", 0);
 }    
}

function editData(object, data)
{
    if (object)
    {
     object.innerHTML = data;
    }
}

function addData(object, data, top)
{
 if (object)
 {
  // If object exists, append data to the object's HTML
  if (top == 1)
  {
  object.innerHTML = data + object.innerHTML;
  }
  else
  {
  object.innerHTML = object.innerHTML + data;
  }
 }
}

// Trim all left spaces
String.prototype.ltrim = function() {
    return this.replace(/^\s+/,"");
}

// Easily add one variable
function quickAjax(varname, varvalue)
{
    var newAjax = new jsAjax();
    newAjax.addParam (varname, varvalue);
    newAjax.send();
}

// doAnimate --- Not implemented in 1.1 yet (thinking rework to support multiple on-going animations)
function doAnimate(id, ms)
{
    
}

// Retrieves command from the currently parsed line
function getCommand(text)
 {
    var temp = text.substr (0, text.indexOf ("!"));
    temp = temp.toUpperCase();
    return temp;
 }

// Retrieves a variable from the currently parsed line
function getVar(curLine, varname, defaultVar)
{
    var vartemp = "[" + varname + "='";
    if (curLine.indexOf(vartemp) != -1)
    {
        var temp = curLine.substring (curLine.indexOf(vartemp) + 3 + varname.length);
        temp = temp.substring(0, temp.indexOf("']"));
    
        
        return temp;
    }
    else
    {
        return defaultVar;
    }
}

// Prototype Function for getting dyanmic values (user inputs)
/*
    We can now refrence objects and get attributes from then as a variable :)
    Start the paramter name with + to activate this
*/

function extractVarFromObject(object, value)
{
    if (value.substring(0, 1) == "+")
    {
        var oldThisObj = thisObj;
        
        // Set a new thisObj
        thisObj = object;
        
        // Run get elements
        var objTemp = getElements(value.substring(0, value.indexOf(";;")));
                                                                   
        // Get something or do something using that object and javascript (you can use objTemp as the refrenced object)
        var objTemp = objTemp[0];
        eval("var newValue = " + value.subtring(value.indexOf(";;") + 2));
        
        thisObj = oldThisObj;
    }
    else
    {
        return value;    
    }
}

// Setup JSCafe Object, No Initialize Routine - Just create object
function jsCafeObject(sUrl, sTaskbarId, sDebugId)
{
    // Update serverURL (default is backend, whether this is a folder or an index file)
    if (sUrl){serverURL = sUrl;}
    
    // Update tasbarObj (default is null)
    if (sTaskbarId)
    {
        var taskbarTemp = document.getElementById(sTaskbarId);
        if (taskbarTemp){taskbarObj = taskbarTemp;}
    }
    // Update dbug (default is null)
    if (sDebugId)
    {
        var debugTemp = document.getElementById(sDebugId);
        if (debugTemp){dbug = debugTemp;}
    }
}

// New JSAjax Object, reUses Code Better and Permenant fix for IE's caching problem
function jsAjax()
{
    // Constructor
    var receiveReq = getXmlHttpRequestObject();
    var params = "";
    
    jsAjax.prototype.addParam = function(name, value)
        {
            if ( params.length)
            {

                params = params + "&" + name + "=" + value;
            }
            else
            {
                params = "?" + name + "=" + value;  
            }
        }
        
    jsAjax.prototype.send = function()
        {
            if (receiveReq)
            {
                // State changed
                receiveReq.onreadystatechange = function(){
                switch(receiveReq.readyState )
                {
                    case 1: // loading
                  
                     break;
                  
                    case 2: // loaded
                  
                     break;
                  
                    case 3: // interative?
                  
                     break;
                  
                    case 4: // Data received
                        // var tempdata = receiveReq.responseText.replaceAll ("<", "&lt;").replaceAll(">", "&gt");
                        // Attempt to debug, if enabled.
                        // dbugit("<<< <code>" + tempdata + "</code>");
						// alert(receiveReq.responseText);
                        // Parse Incoming Data
                        ex( receiveReq.responseText );
                     break;
                }
                }
              
                // Open and send connection
                if (ie)
                {
                    // IE caches... So we add a quick variable to fix this (we could use POST, but there are some problems with ISS)
                    this.addParam("ie", new Date().getTime());
                }

                // dbugit(">>> <strong>" + serverURL + params + "</strong>");
				// alert(serverURL + params);
                receiveReq.open(method, serverURL + params, true);
                
                receiveReq.send(null);
                
            }
        }
}

// Browser-Compatible XMLHTTP Object
function getXmlHttpRequestObject() {
    if (window.XMLHttpRequest ) {
        return new XMLHttpRequest(); //Not IE6 or lower
    } else if( window.ActiveXObject ) {
        return new ActiveXObject("Microsoft.XMLHTTP"); //IE6 or lower
    } else {
        // Fail gracefully
        return false;
    }
}

// Brand new function, allows selection of local elements (this, parentNode, childNode, childNodes) instead of a CSS selector
function getThisElement(selector)
{
    var localObject = null;
    
    if (!thisObj)
    {
        
        // Fail gracefully
        return blankArray();
    }
    else
    {
        if (selector == "")
        {
            // Just local object
            return new Array(thisObj);
        }
        else
        {
            // Parse by Spaces
            localObject = thisObj;
            var parseObj = selector.split(" ");
            for (var n = 0; n < parseObj.length; n++)
            {
                switch (parseObj[n].substring(0, 2).toLowerCase())
                {
                    case "pn":
                        // Make sure we have a parentNode
                        if (localObject.parentNode)
                        {
                            localObject = localObject.parentNode;
                        }
                        else
                        {
                            return blankArray();
                        }
                    break;
                    case "cn":
                        // Make sure we have that child node
                        var childid = parseFloat(selector.substring(2));

                        if ( localObject.childNode[childid])
                        {
                            localObject = localObject.childNode[childid];
                        }
                        else
                        {
                            return blankArray();    
                        }
                    break;

                    case "cs":
                        // Just return childNodes as array
                        return localObject.childNodes;
                    break;
                }
            }


            
            // Done, return localObject
            return new Array(localObject);
        }
    }
}

// Brand new Object (eventHandler)
/*
    .add <element> <type> <function>
    Add's an event to <element> on<type>, executing <function>'
    .remove <element> <type> <function>
    
    Action object
        .add <object> <code> <type>
        Add's a specific action <code> to execute on<type> to <object>
        .remove <object> <type>
*/
function eventHandlerObj()
{
    eventHandlerObj.prototype.add = function(obj, type, fn) {
        
     if ( obj.attachEvent ) {
       obj['e'+type+fn] = fn;
       obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
       obj.attachEvent ( 'on'+type, obj[type+fn] );
     } else {
       obj.addEventListener ( type, fn, false );    
     }}
    
    eventHandlerObj.prototype.remove = function(obj, type, fn)
    {
     if ( obj.detachEvent ) {
       obj.detachEvent ( 'on'+type, obj[type+fn] );
       obj[type+fn] = null;
     }
     else
     {
       obj.removeEventListener ( type, fn, false );    
     }
    }
    
    eventHandlerObj.prototype.addAction = function(object, code, type)
    {
            var gAction = object.getAttribute("action");
            if (gAction == null || gAction == "null"){gAction = "";}
            
            
            var myAction = eventArray.length;
                eventArray[myAction] = code;
                
            // Add the actual event to the object
            object.setAttribute("action", gAction + type + myAction + "! ");
            
            eventHandler.add(object, type, function(){
                listenEvent(this, type);
            });
    }
        
     eventHandlerObj.prototype.removeAction = function(object, type)
     {
        object.setAttribute("action", "");
        eventHandler.remove(object, type, function(){listenEvent(this, type);});
     }
        
     eventHandlerObj.prototype.runCode = function(theCode)
     {
		  if (theCode)
		  {
            var myCode = theCode.replaceAll("=`", "='").replaceAll("`]", "']").replaceAll(";!", ":!");
            ex(myCode);
		  }
     }
	 
}

// Replaces all instances of the given substring.
String.prototype.replaceAll = function(
strTarget, // The substring you want to replace
strSubString // The string you want to replace in.
){
var strText = this;
var intIndexOfMatch = strText.indexOf( strTarget );
 
// Keep looping while an instance of the target string
// still exists in the string.
while (intIndexOfMatch != -1){
// Relace out the current instance.
strText = strText.replace( strTarget, strSubString )
 
// Get the index of any next matching substring.
intIndexOfMatch = strText.indexOf ( strTarget );
}
 
// Return the updated string with ALL the target strings
// replaced out with the new substring.
return( strText );
}

function listenEvent(referObj, eventLaunched)
{
    // Event called from 'referObj' (reffering object)
    // Instead of using inline invalid attributes (which can be EASILY seen), we store them in an array  
    
    // Remember to set the global variable
    thisObj = referObj;
    
    // Find the action using the objects "actionId"
    // referObj.getAttribute("action") = click2! mouseover4!
    var strAction = referObj.getAttribute("action");
      var indexEvent = strAction.indexOf(eventLaunched);
      var strAction = strAction.substring(indexEvent + eventLaunched.length);
      strAction = strAction.substring(0, strAction.indexOf("!"));
      
    // Using the String Action, we retrieve the action id
    strAction = parseFloat(strAction);
    strAction = eventArray[strAction];
     eventHandler.runCode(strAction);
    
}

// Returns blank array
function blankArray()
{
    return new Array();    
}

function getElements(selector) {
 
  // New feature implemented in selector =]
  // JSCafe "knows" what element last called an event, and you can use such to your advantage.
 
  // Choose a selector starting with = to access...
  /*
     This (automatically), This.ParentNode, This.ChildNode, This.ChildNodes
     =                       = pN             = cN0            = cS
     Or combine them...
     = pN pN cN[s]
  */
 
  if (selector.substring(0,1) == "=")
  {
    return getThisElement(selector.substring(1).ltrim());  
  }
 
  // Attempt to fail gracefully in lesser browsers

  if (!document.getElementsByTagName) {
    return blankArray();
  }
 
  // Split selector in to tokens
  var tokens = selector.split(' ');
  var currentContext = new Array(document);
  for (var i = 0; i < tokens.length; i++) {
    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
    if (token.indexOf('#') > -1) {
      // Token is an ID selector
      var bits = token.split('#');
      var tagName = bits[0];
      var id = bits[1];
      var element = document.getElementById (id);
      if (tagName && element.nodeName.toLowerCase() != tagName) {
        // tag with that ID not found, return false
        return new Array();
      }
      // Set currentContext to contain just this element
      currentContext = new Array(element);
      continue; // Skip to next token
    }
    if (token.indexOf ('.') > -1) {
      // Token contains a class selector
      var bits = token.split ('.');
      var tagName = bits[0];
      var MATINAME = bits[1];
      if (!tagName) {
        tagName = '*';
      }
      // Get elements matching tag, filter them for class selector
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (found[k].className && found[k].className.match(new RegExp('\\b'+MATINAME+'\\b'))) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // Code to deal with attribute selectors
    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
      var tagName = RegExp.$1;
      var attrName = RegExp.$2;
      var attrOperator = RegExp.$3;
      var attrValue = RegExp.$4;
      if (!tagName) {
        tagName = '*';
      }
      // Grab all of the tagName elements within current context
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      var checkFunction; // This function will be used to filter the elements
      switch (attrOperator) {
        case '=': // Equality
          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
          break;
        case '~': // Match one of space seperated words
          checkFunction = function(e) { return ( e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
          break;
        case '|': // Match start with value followed by optional hyphen
          checkFunction = function(e) { return ( e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
          break;
        case '^': // Match starts with value
          checkFunction = function(e) { return (e.getAttribute (attrName).indexOf(attrValue) == 0); };
          break;
        case '$': // Match ends with value - fails with "Warning" in Opera 7
          checkFunction = function(e) { return (e.getAttribute (attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
          break;
        case '*': // Match ends with value
          checkFunction = function(e) { return (e.getAttribute (attrName).indexOf(attrValue) > -1); };
          break;
        default :
          // Just test for existence of attribute
          checkFunction = function(e) { return e.getAttribute(attrName); };
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (checkFunction(found[k])) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // If we get here, token is JUST an element (not a class or ID selector)
    tagName = token;
    var found = new Array;
    var foundCount = 0;
    for (var h = 0; h < currentContext.length; h++) {
		if (!currentContext[h]){return currentContext;}
      var elements = currentContext[h].getElementsByTagName(tagName);
      for (var j = 0; j < elements.length; j++) {
        found[foundCount++] = elements[j];
      }
    }
    currentContext = found;
  }
  return currentContext;
}

/* That revolting regular expression explained
/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
  \---/  \---/\-------------/    \-------/
    |      |         |               |
    |      |         |           The value
    |      |    ~,|,^,$,* or =
    |   Attribute
   Tag
*/

// Temporay ID assigner
function cTempId()
{
    cTempId.prototype.assign = function(obj)
    {
		if (!obj){return false;}
		
        if (obj.id)
        {
            return obj.id;    
        }
        else
        {
            // Assign obj an id
            obj.id = "temp" + tempIdCounter;
            
            // Assign or reset the next temporary id
            tempIdCounter++;    
            if (tempIdCounter > 10000){tempIdCounter = 0;}
            return obj.id;
        }
    }
    
    cTempId.prototype.remove = function(obj)
    {
		if (!obj){return false;}
		
        // If they are using a temporary id, remove it.
        if (obj.id.substring(0, 4) == "temp")
        {
            obj.id = "";    
        }
    }
}

// Delay Assistants
function delayStyle(id, style, value, ms)
{
    setTimeout("document.getElementById('" + id + "').style['" + style + "']='" + value + "'", ms);
}
function clearTemp(id, ms)
{
    setTimeout("tempId.remove(document.getElementById('" + id + "'))", ms);
}
// Bootup Statement
eventHandler.add(window, "load", function()
{
    // Run setup statements, unless autoLoad = False
    if (!autoLoadOff)
    {
        var jsCafe = new jsCafeObject("backend", "taskbar", "debug");
    }
    
    // Setup document for browser-specific-ness
    if (ie)
    {
     document.body.style["width"] = "98%";
    }
    
    // Setup widgets if they are placed already and we included the JSCafe widgets
    /*
        Note: If you create widgets at real-time
        you need to run the JSCafe statement
        'widgetize' on the object.
        
        You can also use 'rewidget' to go through
        all widgets in the document
        
        also... windows and tooltips are NOT considered widgets, though they have
        similar functionality. Thanks.
    */
    if (typeof rewidget == "function"){rewidget();}
    
    // If their is a seperate bootup function
    if (typeof bootup == "function"){bootup();}
});

function movemouse(e)
{
  if (isdrag)
  {
      var left = nn6 ? tx + e.clientX - x : tx + event.clientX - x;
    dobj.style.left = left + "px";
      var top = nn6 ? ty + e.clientY - y : ty + event.clientY - y;
    dobj.style.top   = top + "px";
    return false;
  }
}

function selectmouse(e)
{
  var fobj       = nn6 ? e.target : event.srcElement;
  var topelement = nn6 ? "HTML" : "BODY";
  var lastobj = null;
 
  while (fobj.tagName != topelement &&  fobj.className.indexOf("freedrag") == -1 && lastobj != fobj)
  {
        lastobj = fobj;
        fobj = nn6 ? fobj : fobj.parentElement;
  }

  if (fobj.className.indexOf("freedrag") != -1)
  {
    isdrag = true;
    
    if (fobj.className.indexOf("dragparent") != -1)
    {
         dobj = fobj.parentNode;
    }
    else
    {
      dobj = fobj;    
    }
    
    tx = parseInt(dobj.style.left+0);
    ty = parseInt(dobj.style.top+0);
    x = nn6 ? e.clientX : event.clientX;
    y = nn6 ? e.clientY : event.clientY ;
    document.onmousemove=movemouse ;
    return false;
  }
}

document.onmousedown=selectmouse;
document.onmouseup=new Function("isdrag=false");

// Find X and Y position of any object (thanks to: http://www.howtocreate.co.uk/tutorials/javascript/browserspecific )
// -----------------------------------
function findPos( oLink ) {
    try
    {
      if( oLink.offsetParent ) {
        for( var posX = 0, posY = 0; oLink.offsetParent; oLink = oLink.offsetParent ) {
          posX += oLink.offsetLeft ;
          posY += oLink.offsetTop ;
        }
        return [ posX, posY ];
      } else {
        return [ oLink.x, oLink.y ];
      }
    }
    catch(ex)
    {
       
    }
}

function findMouse(e) {
	var posx = 0;
	var posy = 0;
	if (!e) var e = window.event;
	if (e.pageX || e.pageY) 	{
		posx = e.pageX;
		posy = e.pageY;
	}
	else if (e.clientX || e.clientY) 	{
		posx = e.clientX + document.body.scrollLeft
			+ document.documentElement.scrollLeft;
		posy = e.clientY + document.body.scrollTop
			+ document.documentElement.scrollTop;
	}
	
	return [ posx, posy ];
}

