function SwkClientGui()
{
    /**
     * Gets a field object by element ID or name (only returns 1 field)
     * 
     * @param string fieldName
     * @return HTMLDOMElement
     */
    this.getFieldObj = function(fieldName)
    {
        var field = document.getElementById(fieldName);
        
        // if we weren't able to find the field by id, try by name
        if (field == null)
        {
            field = document.getElementsByName(fieldName);
            
            // if at least one item was found by the given name, use the first item found
            if (field != null && field.length > 0)
            {
                field = field[0];
            }
        }
        
        return field;
    }

    /**
     * Gets a field's value
     * 
     * @param string fieldName
     * @return string
     */
    this.getFieldValue = function(fieldName)
    {
        var field = this.getFieldObj(fieldName);
        
        if (field != null)
        {
            return field.value;
        }
    }

    /**
     * Sets the inner HTML of a field
     * 
     * @param string fieldName
     * @param string newContent
     * @return void
     */
    this.setInnerHtml = function(fieldName, newContent)
    {
        var field = this.getFieldObj(fieldName);
        
        if (field != null)
        {
            field.innerHTML = newContent;
        }
    }

    /**
     * Toggle's a fields visibility through CSS properties
     * 
     * @param string fieldName
     * @param string visibleDisplayType
     * @return void
     */
    this.toggleFieldVisibility = function(fieldName, visibleDisplayType)
    {
        var field = this.getFieldObj(fieldName);
        
        if (field != null)
        {
            if (field.style.display == 'none' || field.style.visibility == 'hidden')
            {
                this.showField(fieldName, visibleDisplayType);
            }
            else
            {
                this.hideField(fieldName);
            }
        }
    }

    /**
     * Hides a field
     * 
     * @param string fieldName
     * @return void
     */
    this.hideField = function(fieldName)
    {
        var field = this.getFieldObj(fieldName);
        
        if (field != null)
        {
            field.style.display = 'none';
            field.style.visibility = 'hidden';
        }
    }

    /**
     * Shows a field
     * 
     * @param string fieldName
     * @param string displayStyle
     * @return void
     */
    this.showField = function(fieldName, displayStyle)
    {
        var field = this.getFieldObj(fieldName);
        
        if (field != null)
        {
            // if 'none' or an invalid type was specified, default to block
            switch (displayStyle.toLowerCase())
            {
                case 'block':
                case 'inline':
                case 'list-item':
                case 'run-in':
                case 'inline-block':
                case 'table':
                case 'table-row-group':
                case 'table-header-group':
                case 'table-footer-group':
                case 'table-row':
                case 'table-column-group':
                case 'table-column':
                case 'table-cell':
                case 'table-caption':
                case 'inherit':
                    break;
                default:
                    displayStyle = 'block';
                    break;
            }
        
            field.style.display = displayStyle;
            field.style.visibility = 'visible';
        }
    }

    /**
     * Appends a CSS class to an element
     * 
     * @param string fieldName
     * @param string cssClass
     * @return void
     */
    this.cssAppendClass = function(fieldName, cssClass)
    {
        if (cssClass.length > 0)
        {
            var field = this.getFieldObj(fieldName);
            
            if (field != null)
            {
                if (cssClass.charAt(1) != ' ')
                    cssClass = ' ' + cssClass;
                
                field.className += cssClass;
            }
        }
    }

    /**
     * Removes a CSS class which may have been appened with cssAppendClass
     * 
     * @param string fieldName
     * @param string cssClass
     * @return void
     */
    this.cssRemoveClass = function(fieldName, cssClass)
    {
        if (cssClass != null && cssClass.length > 0)
        {
            var field = this.getFieldObj(fieldName);
            
            if (field != null)
            {
                if (cssClass.charAt(1) != ' ')
                    cssClass = ' ' + cssClass;
                
                field.className = field.className.replace(cssClass, '');
            }
        }
    }

    /**
     * Toggles a panel's visibility, and can do so with animation
     * 
     * @param string toggleId
     * @param string contentId
     * @param Spry effectObj
     */
    this.togglePanel = function(toggleId, contentId, effectObj)
    {
        if(typeof Spry != "undefined")
        {
            //use the Adobe Spry framework for effects if available
            effectObj.start();
        }
        else
        {
            //otherwise, just toggle the fields visibility
            this.toggleFieldVisibility(contentId, 'block');
        }
        
        var toggleField = swkGui.getFieldObj(toggleId);
        
        if (toggleField != null)
        {
            if (toggleField.className.indexOf("expanded") > -1)
            {
                this.cssRemoveClass(toggleId, "expanded");
                this.cssAppendClass(toggleId, "contracted");
            }
            else
            {
                this.cssRemoveClass(toggleId, "contracted");
                this.cssAppendClass(toggleId, "expanded");
            }
        }
    }

    /**
     * Returns an XMLHttpRequest object, used for AJAX functions
     * 
     * @return XmlHttpRequest
     */
    this.getXmlHttpRequestObj = function()
    {
        var xmlreq = false;
        
        if (window.XMLHttpRequest)
        {
            xmlreq = new XMLHttpRequest();
        }
        else if (window.ActiveXObject)
        {
            // Try ActiveX
            try
            {
                xmlreq = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e1)
            {
                // first method failed
                try
                {
                    xmlreq = new ActiveXObject('Microsoft.XMLHTTP');
                }
                catch (e2)
                {
                     // both methods failed
                     return null;
                }
            }
        }
        
        return xmlreq;
    }

    /**
     * Performs a synchronous XML-HTTP request
     * 
     * @param string httpMethod
     * @param string urlStr
     * @param string dataStr
     * @param string returnType ("xml" or "text")
     * @return mixed
     */
    this.httpRequestSynchronous = function(httpMethod, urlStr, dataStr, returnType)
    {
        returnType = returnType.toLowerCase();
        httpMethod = httpMethod.toUpperCase();
        
        // make sure a valid response type has been specified
        if (returnType != 'xml' && returnType != 'text')
            return null;
        
        // make sure a valid HTTP method has been specified
        if (httpMethod != 'GET' && httpMethod != 'POST')
            return null;
        
        // get a new XmlHttpRequest object
        var reqObj = this.getXmlHttpRequestObj();
        
        // make sure we got a valid XmlHttpRequest object
        if (reqObj == null)
            return null;
        
        // open the connection
        reqObj.open(httpMethod, urlStr, false);
        // set the headers
        reqObj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        // send the data
        reqObj.send(dataStr);
        
        // make sure the HTTP request did not error out
        if (reqObj.status != 200)
            return null;
        
        // return the appropriate data
        switch (returnType)
        {
            case 'xml':
                return reqObj.responseXML;
                break;
            case 'text':
                return reqObj.responseText;
                break;
        }
    }

    /**
     * Performs an asynchronous XML-HTTP request
     * 
     * @param string httpMethod
     * @param string urlStr
     * @param string dataStr
     * @param XmlHttpRequest reqObj
     * @param callback callbackFunction
     * @return mixed (string or XML DOM object)
     */
    this.httpRequestAsynchronous = function(httpMethod, urlStr, dataStr, reqObj, callbackFunction)
    {
        httpMethod = httpMethod.toUpperCase();
                
        // make sure a valid HTTP method has been specified
        if (httpMethod != 'GET' && httpMethod != 'POST')
            return null;
        
        // make sure we got a valid XmlHttpRequest object
        if (reqObj == null)
            return null;
        
        // set the callback handler function
        reqObj.onreadystatechange = callbackFunction;
        // open the connection
        reqObj.open(httpMethod, urlStr, true);
        // set the headers
        reqObj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        // send the data
        reqObj.send(dataStr);
    }
    
    

    /**
     * Shows a rich tool-tip via DomTT
     * 
     * @param HTMLDOMElement theObject
     * @param string theEvent
     * @param string caption
     * @param string content
     * @return void
     */
    this.showRichToolTipWithCaption = function(theObject, theEvent, caption, content)
    {
        domTT_activate(theObject, theEvent, 'caption', caption, 'content', content, 'trail', 'x');
    }

    /**
     * Shows a page overlay.  topElement may be a string ID or reference to an element.
     * 
     * @param string overlayId
     * @param mixed topElement
     * @return void
     */
    this.showOverlay = function(overlayId, topElement)
    {
        var overlay = document.getElementById(overlayId);

        if (null == overlay)
            return;

        overlay.style.display = "block";
        overlay.style.visibility = "visible";

        //adjust the height of the overlay div depending on the browser being used.
        switch (this.ieVersion)
        {
            case 6:
            case 7:
                overlay.style.width = "105%";
                overlay.style.height = (250 + window.screen.height).toString() + "px";
                break;
            case 0:
            default:
                try
                {
                    overlay.style.height = (100 + document.body.offsetHeight).toString() + "px";
                }
                catch (ex)
                {
                    overlay.style.height = (250 + window.screen.height).toString() + "px";
                }
                break;
        }

        if (null != topElement)
        {
            var position = this.getElementPosition(topElement);
            overlay.style.paddingTop = position.top.toString() + "px";

            //alert("Top is " + position.top + "px");
        }
    }

    /**
     * Hides a page overlay
     * 
     * @param string overlayId
     * @return void
     */
    this.hideOverlay = function(overlayId)
    {
        var overlay = document.getElementById(overlayId);

        if (null == overlay)
            return;

        overlay.style.display = "none";
        overlay.style.visibility = "hidden";
    }

    /**
     * Get's an element's position (parameter may be an object reference or an object's ID
     * 
     * @param mixed o
     * @return object
     */
    this.getElementPosition = function(o)
    {
        /***** ORIGINAL FUNCITON FROM: http://www.javascripttoolbox.com/lib/objectposition/source.php *****/
        /* LICENSE TEXT:
        * Copyright (c)2005-2007 Matt Kruse (javascripttoolbox.com)
        * 
        * Dual licensed under the MIT and GPL licenses. 
        * This basically means you can use this code however you want for
        * free, but don't claim to have written it yourself!
        * Donations always accepted: http://www.JavascriptToolbox.com/donate/
        * 
        * Please do not link to the .js files on javascripttoolbox.com from
        * your site. Copy the files locally to your server instead.
        * 
        */
        //MIT License text at: http://www.opensource.org/licenses/mit-license.php
        var fixBrowserQuirks = true;
        // If a string is passed in instead of an object ref, resolve it
        if (typeof (o) == "string")
        {
            o = document.getElementById(o);
        }

        if (o == null)
        {
            return null;
        }

        var left = 0;
        var top = 0;
        var width = 0;
        var height = 0;
        var parentNode = null;
        var offsetParent = null;


        offsetParent = o.offsetParent;
        var originalObject = o;
        var el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references
        while (el.parentNode != null)
        {
            el = el.parentNode;
            if (el.offsetParent == null)
            {
                //do nothing
            }
            else
            {
                var considerScroll = true;
                /*
                In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already 
                take its scroll position into account. If elements further up the chain are scrollable, their 
                scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value
                which must be ignored.
                */
                if (fixBrowserQuirks && window.opera)
                {
                    if (el == originalObject.parentNode || el.nodeName == "TR")
                    {
                        considerScroll = false;
                    }
                }
                if (considerScroll)
                {
                    if (el.scrollTop && el.scrollTop > 0)
                    {
                        top -= el.scrollTop;
                    }
                    if (el.scrollLeft && el.scrollLeft > 0)
                    {
                        left -= el.scrollLeft;
                    }
                }
            }
            // If this node is also the offsetParent, add on the offsets and reset to the new offsetParent
            if (el == offsetParent)
            {
                left += o.offsetLeft;
                if (el.clientLeft && el.nodeName != "TABLE")
                {
                    left += el.clientLeft;
                }
                top += o.offsetTop;
                if (el.clientTop && el.nodeName != "TABLE")
                {
                    top += el.clientTop;
                }
                o = el;
                if (o.offsetParent == null)
                {
                    if (o.offsetLeft)
                    {
                        left += o.offsetLeft;
                    }
                    if (o.offsetTop)
                    {
                        top += o.offsetTop;
                    }
                }
                offsetParent = o.offsetParent;
            }
        }


        if (originalObject.offsetWidth)
        {
            width = originalObject.offsetWidth;
        }
        if (originalObject.offsetHeight)
        {
            height = originalObject.offsetHeight;
        }

        return { 'left': left, 'top': top, 'width': width, 'height': height };
    }
}
