///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// This works with JavaScript 1.2 or greater         //
// These classes designed to work with HTML5 & XHTML //
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////

///////////////////////////////
// Preload sideHighlight.png //
///////////////////////////////

var preloadedImage = new Image();
preloadedImage.src = "/images/sideHighlight.png";

//////////////////////////////////////////
// Do Any Small Device Specific Changes //
//////////////////////////////////////////

SmallDeviceChanges();

///////////////////////
// String prototypes //
///////////////////////

//---------------------------------------------//
// Used in FramedImaged and Thumbnail objects. //
//---------------------------------------------//

String.prototype.stripAmp = function(bCompress)
{
    var str = this;

    if(typeof bCompress == "undefined")
    {
        bCompress = true;
    }

    if(bCompress)
    {
        str = str.replace(/\&amp;/g, "&");
    }
    else
    {
        str = str.replace(/\&/g, "&amp;");
    }

    return str;
};

String.prototype.stripBrackets = function(bCompress)
{
    // this is used so that HTML can be embedded in strings be compliant to
    // strict XHTML

    var str = this;

    if(typeof bCompress == "undefined")
    {
        bCompress = true;
    }

    if(bCompress)
    {
        str = str.replace(/\[/g, "<");
        str = str.replace(/\]/g, ">");
    }
    else
    {
        str = str.replace(/</g, "[");
        str = str.replace(/>/g, "]");
    }

    return str;
};

String.prototype.stripGtLt = function(bCompress)
{
    // not sure if this is needed

    var str = this;

    if(typeof bCompress == "undefined")
    {
        bCompress = true;
    }

    if(bCompress)
    {
        str = str.replace(/\&lt;/g, "<");
        str = str.replace(/\&gt;/g, ">");
    }
    else
    {
        str = str.replace(/</g, "&lt;");
        str = str.replace(/>/g, "&gt;");
    }

    return str;
};

String.prototype.stripX = function(bCompress)
{
    // not sure if this is needed

    var str = this;

    if(typeof bCompress == "undefined")
    {
        bCompress = true;
    }

    str = str.stripAmp(bCompress);
    str = str.stripGtLt(bCompress);

    return str;
};

String.prototype.stripHtmlFormatting = function()
{
    var str = this;

    // remove anything between "[" and "]" (my HTML formatting)
    str = str.replace(/[(.*)]/g, " ");

    return str;
};

///////////////////
// Footer object //
///////////////////

function Footer(email, link, description)
{
    // public methods

    // public properties

    // private methods

    // private properties

    // constructor

    {
        var html = "";
        var linkExists = (typeof link != "undefined");

        html += "<hr />";
        html += "<table id='footer'>";
        html += "<tr>";
        html += "<td id='footerLeft'>";
        if(linkExists)
        {
            html += "<a href='" + link + "'>" + description + "</a>";
        }
        html += "</td>";
        html += "<td id='footerRight'>";
        if(email != "")
        {
            html += "<address>E-Mail: " + GetEmail(email) + "</address>";
        }
        html += "</td>";
        html += "</tr>";
        html += "</table>";

        document.writeln(html);
    }

    // public methods

    // private methods

    function GetEmail(which)
    {
        var retVal  = "";
        var address = "";
        var name    = "";
        var atDomainNameDotCom = "&#064MikeMcCollister&#046&#099&#111&#109";

        // Note that address like "Mike&#064MikeMcCollister&#046&#099&#111&#109"
        // are not XHTML compliant.
        switch(which.toLowerCase())
        {
            case "debbie":
                address = "Deb" + atDomainNameDotCom;
                name    = address;
                break;

            case "mike":
                address = "Mike" + atDomainNameDotCom;
                name    = address;
                break;

            case "mikeanddebbie":
                address = "MikeAndDebbie" + atDomainNameDotCom;
                name    = address;
                break;

            case "support":
                address = "support" + atDomainNameDotCom;
                name    = address;
                break;
        }

        if(address != "")
        {
            retVal = "<a href='mailto:" + address + "'>" + name + "</a>";
        }

        return retVal;
    }
}

////////////////////////
// FramedImage object //
////////////////////////

//---------------------------------------------------------------//
// Note: Add <meta http-equiv="imagetoolbar" content="no" /> to  //
//       head so that the image toolbar does not show up on IE6. //
//---------------------------------------------------------------//

function FramedImage(bFrame)
{
    // public methods

    this.Last        = Last;
    this.SetImageDir = SetImageDir;
    this.Show        = Show;

    // public properties

    // private methods

    // private properties

    var _eImageDir = "images";
    var _bLast     = false;
    var _bFrame    = true;

    // constructor

    {
        if(bFrame != null)
        {
            _bFrame = bFrame;
        }
    }

    // public methods

    function Last()
    {
        _bLast = true;
    }

    function SetImageDir(imageDir)
    {
        _eImageDir = escape(imageDir);
    }

    function Show(image, width, height, caption)
    {
        var html = "";
        var eImage = escape(image.stripX());

        if(_eImageDir != "")
        {
            eImage = _eImageDir + "/" + eImage;
        }

        html += "<div class='framedImage' ";
        if(_bLast)
        {
            html += "style='padding-bottom:0' ";
            _bLast = false;
        }
        html += ">";
        html += "<img class='framedImageImage' src='" + eImage + "' ";
        if(_bFrame == false)
        {
            html += "style='border:none' ";
        }
        html += "alt='' width='" + width + "' height='" + height + "' />";
        html += "<div class='framedImageCaption'>" + caption.stripBrackets();
        html += "</div>";
        html += "</div>";

        document.writeln(html);
    }
}

///////////////////////////////
// SmallDeviceChanges object //
///////////////////////////////

function SmallDeviceChanges()
{
    // public methods

    // public properties

    // private methods

    // private properties

    // constructor

    {
        if(IsSmallDevice())
        {
            // disable the selection flash
            document.documentElement.style.webkitTapHighlightColor =
                "rgba(0,0,0,0)";

            // hide URL bar
            RegisterEvent(window,
                          function() { setTimeout(HideUrlBar, 0); },
                          "load");
/*
            RegisterEvent(window,
                          function() { setTimeout(HideUrlBar, 0); },
                          "orientationchange");
*/
        }
    }

    // public methods

    // private methods

    function HideUrlBar()
    {
        window.scrollTo(0, 1);
    }

    function IsSmallDevice()
    {
        var bRetVal = false;

        if(navigator.userAgent.match(/iPhone/i)  ||
           navigator.userAgent.match(/iPod/i)    ||
           navigator.userAgent.match(/Android/i)    )
        {
            bRetVal = true;
        }

        return bRetVal;
    }

    function RegisterEvent(target, functionRef, taskType)
    {
        taskType = (window.addEventListener) ? taskType : "on" + taskType;

        if(target.addEventListener)
        {
            target.addEventListener(taskType, functionRef, false);
        }
        else if(target.attachEvent)
        {
            target.attachEvent(taskType, functionRef);
        }
    }
}

///////////////////////
// PopupImage object //
///////////////////////

//---------------------------------------------------------------//
// Note: Add <meta http-equiv="imagetoolbar" content="no" /> to  //
//       head so that the image toolbar does not show up on IE6. //
//---------------------------------------------------------------//

function PopupImage(assigneeName)
{
    ///////////////////////////////////////////////////////////////////////////
    // Some of this code was inspired from the Image Thumbnail Viewer Script //
    // from http://www.dynamicdrive.com.                                     //
    ///////////////////////////////////////////////////////////////////////////

    // public methods

    this.AddImageInfo        = AddImageInfo;
    this.CopyCachedFullImage = CopyCachedFullImage;
    this.HandleClicks        = HandleClicks;
    this.Hide                = Hide;
    this.NextImage           = NextImage;
    this.PrevImage           = PrevImage;
    this.SetImageDir         = SetImageDir;
    this.Show                = Show;
    this.ToggleSize          = ToggleSize;

    // public properties

    // private methods

    // private properties

    var _assigneeName            = null;
    var _copyright               = "&copy; Mike McCollister";
    var _copyrightLoading        = "Loading...";
    var _eImageDir               = "images";
    var _popupImageBar           = null;
    var _popupImageBarPrev       = null;
    var _popupImageBarNext       = null;
    var _popupImageBarClose      = null;
    var _popupImageBarButtonSize = null;
    var _popupImage              = null;
    var _popupImageTopBarTable   = null;
    var _popupImageCopyright     = null;
    var _popupImageCaption       = null;
    var _fullImage               = null;
    var _fullImageCache          = null;
    var _imageInfoArray          = [];
    var _currentImage            = 0;
    var _backgroundColor         = "";
    var _bImageSizeFit           = true;
    var _fullImageWidth          = 0;
    var _fullImageHeight         = 0;
    var _widthThreshold          = 760;
    var _clickTimer              = null;
    var _imagePaddingPx          = 0;
    var _imageBorderPx           = 0;
    // var _popupImageBarUpdateId   = null; // ??? iPad

    // constructor

    {
        var html = "";

        _assigneeName = assigneeName;

        // popup image bar division
        html += "<div id='popupImageBar'>";
        html += "<table>";
        html += "<tr>";
        html += "<td class='left'>";
        html += "<span class='popupImageBarButton' " +
                "title='Previous Image' " +
                "onclick='" + _assigneeName + ".PrevImage()' " +
                ">&larr;</span>";
        html += "&nbsp;&nbsp;";
        html += "<span class='popupImageBarButton' " +
                "title='Next Image' " +
                "onclick='" + _assigneeName + ".NextImage()' " +
                ">&rarr;</span>";
        html += "</td>";
        html += "<td class='right'>";
        html += "<span id='popupImageBarButtonSize' class='popupImageBarButton' " +
                "title='Toggle Image Size' " +
                "onclick='" + _assigneeName + ".ToggleSize()' " +
                ">Size</span>";
        html += "&nbsp;&nbsp;";
        html += "<span class='popupImageBarButton' " +
                "title='Click to Close Image' " +
                "onclick='" + _assigneeName + ".Hide()' " +
                ">&times;</span>";
        html += "</td>";
        html += "</tr>";
        html += "</table>";
        html += "</div>";

        // popup image division
        html += "<div id='popupImage'>";
        html += "<div id='popupImageFrame'>";
        html += "<table id='popupImageTopBar'>";
        html += "<tr>";
        html += "<td id='popupImageCopyright'>";
        html += "</td>";
        html += "<td id='popupImageButtons'>" +
                "<span class='popupImageButton' " +
                "onclick='" + _assigneeName + ".Hide()' " +
                "title='Click to Close' " +
                ">&times;</span>";
        html += "</td>";
        html += "</tr>";
        html += "</table>";
        html += "<img id='popupImageImage' src='' " +
                "title='Click to Close, Double Click to Toggle Size' " +
                "alt='' onmouseup='" + _assigneeName + ".HandleClicks()' />";
        html += "</div>";
        html += "<div id='popupImageCaption'>";
        html += "</div>";
        html += "</div>";

        document.writeln(html);

        // set global variables
        _popupImageBar        = document.getElementById("popupImageBar");
        _popupImageBarPrev    = document.getElementById("popupImageBarPrev");
        _popupImageBarNext    = document.getElementById("popupImageBarNext");
        _popupImageBarClose   = document.getElementById("popupImageBarClose");
        _popupImageBarButtonSize =
            document.getElementById("popupImageBarButtonSize");
        _popupImage            = document.getElementById("popupImage");
        _popupImageTopBarTable = document.getElementById("popupImageTopBar");
        _popupImageCopyright   = document.getElementById("popupImageCopyright");
        _popupImageCaption     = document.getElementById("popupImageCaption");
        _fullImage             = document.getElementById("popupImageImage");

        _imagePaddingPx = parseInt(GetStyle(_popupImage, "margin-left"));
        _imageBorderPx  = parseInt(GetStyle(_fullImage,  "border-left-width"));

        // register events
        RegisterEvent(window, ResizeImage, "resize");
        RegisterEvent(window, ResizeImage, "orientationchange");
        
        // ??? iPad
        // if(navigator.userAgent.match(/iPad/i))
        // {
            // RegisterEvent(document, RepositionImageBar, "scroll");
            // RegisterEvent(document,  IBClear, "touchmove");
            // RegisterEvent(document,  IBShow, "touchend");
            // _popupImageBar.style.position = "absolute";
        // }

        // disable text selection in the popup window
        DisableTextSelection(_popupImageBar);
        DisableTextSelection(_popupImage);

        // get background color
        _backgroundColor = document.body.style.backgroundColor;
    }

    // public methods

    function AddImageInfo(eThumb, tWidth, tHeight,
                          eImage, iWidth, iHeight,
                          eTitle, date)
    {
        imageInfo = new ImageInfo();

        imageInfo.eThumb  = eThumb;
        imageInfo.tWidth  = tWidth;
        imageInfo.tHeight = tHeight;
        imageInfo.eImage  = eImage;
        imageInfo.iWidth  = iWidth;
        imageInfo.iHeight = iHeight;
        imageInfo.eTitle  = eTitle;
        imageInfo.date    = date;

        _imageInfoArray.push(imageInfo);
    }

    function CopyCachedFullImage()
    {
        if(_fullImageCache.complete == true)
        {
            _fullImage.src                 = _fullImageCache.src;
            _popupImageCopyright.innerHTML = _copyright;
        }
        else
        {
            // check again 250 ms later
            setTimeout(_assigneeName + ".CopyCachedFullImage()", 250);
        }
    }

    function HandleClicks()
    {
        if(_clickTimer != null)
        {
            // double click
            clearTimeout(_clickTimer);
            _clickTimer = null;
            ToggleSize();
        }
        else
        {
            // single click
            _clickTimer = setTimeout(function() { _clickTimer = null; Hide(); },
                                     250);
        }
    }

    function Hide()
    {
        document.onkeydown                  = null;
        _popupImageBar.style.display        = "none";
        _popupImage.style.display           = "none";
        document.body.style.backgroundColor = _backgroundColor;
    }

    function NextImage()
    {
        var newOne;
        var index = _currentImage + 1;

        if(index == _imageInfoArray.length)
        {
            index = 0;
        }

        newOne = _imageInfoArray[index];

        Show(newOne.eThumb, newOne.eImage,
             newOne.iWidth, newOne.iHeight,
             newOne.eTitle, newOne.date);
    }

    function PrevImage()
    {
        var newOne;
        var index = _currentImage - 1;

        if(index < 0)
        {
            index = _imageInfoArray.length - 1;
        }

        newOne = _imageInfoArray[index];

        Show(newOne.eThumb, newOne.eImage,
             newOne.iWidth, newOne.iHeight,
             newOne.eTitle, newOne.date);
    }

    function SetImageDir(imageDir)
    {
        _eImageDir = escape(imageDir);
    }

    function Show(tImage, fImage, fWidth, fHeight, caption, date)
    {
        var tImage2;
        var fImage2;
        var bCopyCachedImage = true;

        _currentImage = ImageIndex(tImage);

        // move image away to avoid scroll bar blinks
        _popupImage.style.top  = "-10000px";
        _popupImage.style.left = "-10000px";

        if(caption != "")
        {
            _popupImageCaption.innerHTML     = "<b>" + unescape(caption) +
                                               "</b><br /><em>" + date +
                                               "</em>";
            _popupImageCaption.style.display = "block";
        }
        else
        {
            _popupImageCaption.style.display = "none";
        }

        tImage2 = _eImageDir + "/" + tImage;
        fImage2 = _eImageDir + "/" + fImage;

        _fullImageCache     = new Image();
        _fullImageCache.src = fImage2;

        if(_fullImageCache.complete == false)
        {
            _popupImageCopyright.innerHTML = _copyrightLoading;
            _fullImage.src                 = tImage2;
            bCopyCachedImage               = true;
        }
        else
        {
            _fullImage.src                 = fImage2;
        }

        _fullImage.style.width  = fWidth  + "px";
        _fullImage.style.height = fHeight + "px";

        if(navigator.userAgent.match(/MSIE 6/i) ||
           navigator.userAgent.match(/MSIE 7/i)    )
        {
            _popupImageTopBarTable.style.width = "0";
        }

        _fullImageWidth  = fWidth;
        _fullImageHeight = fHeight;

        document.body.style.backgroundColor = "gray";
        _popupImage.style.display           = "block";

        if(GoodBrowser())
        {
            _popupImageBar.style.display = "block";
        }

        SizeImage();

        // ??? possible iPad stuff
        // if(GoodBrowser() == false)
        // {
            // // have it update the popup image bar every 10 ms
            // _popupImageBarUpdateId = setInterval(RepositionImageBar, 10);
        // }
        
        document.onkeydown = HandleKeyDown;

        if(bCopyCachedImage == true)
        {
            CopyCachedFullImage();
        }
    }

    function ToggleSize()
    {
        _bImageSizeFit = _bImageSizeFit ? false : true;

        SizeImage();
    }

    // private methods

    function CenterImage()
    {
        // This method was used instead of the "50% method" because the
        // "50% method" did not work on the iPhone.
        var dp   = GetDocProperties();
        var left = Math.round((dp.clientWidth              / 2) -
                              _imagePaddingPx                   -
                              (_popupImage.offsetWidth     / 2)   );
        var top  = Math.round(dp.scrollTop +
                              (_popupImageBar.offsetHeight / 2) +
                              (dp.clientHeight             / 2) -
                              _imagePaddingPx                   -
                              (_popupImage.offsetHeight    / 2)   );

        _popupImage.style.top  = top  + "px";
        _popupImage.style.left = left + "px";
    }

    function DisableTextSelection(target)
    {
        if (typeof target.onselectstart != "undefined")
        {
            // Internet Explorer
            target.onselectstart = function() { return false; };
        }
        else if (typeof target.style.MozUserSelect != "undefined")
        {
            // Firefox
            target.style.MozUserSelect = "none";
        }
        else
        {
            // All Others
            target.onmousedown = function() { return false; };
        }
    }

    function GetDocProperties()
    {
        var clientWidth;
        var clientHeight;
        var scrollTop;

        if(navigator.userAgent.match(/iPhone/i)  ||
           navigator.userAgent.match(/iPad/i)    ||
           navigator.userAgent.match(/iPod/i)    ||
           navigator.userAgent.match(/Android/i)    )
        {
            clientWidth  = window.innerWidth;
            clientHeight = window.innerHeight;
        }
        else
        {
            clientWidth  = document.documentElement.clientWidth;
            clientHeight = document.documentElement.clientHeight;
        }

        if(window.pageYOffset != undefined)
        {
            scrollTop = window.pageYOffset;
        }
        else
        {
            scrollTop = document.documentElement.scrollTop;
        }
        
        return {clientWidth  : clientWidth,
                clientHeight : clientHeight,
                scrollTop    : scrollTop
               };
    }

    function GetStyle(element, styleProp)
    {
        var y = null;

        if(element.currentStyle)
        {
            styleProp =
                styleProp.
                    replace(/\-(\w)/g,
                            function(sMatch, p1) { return p1.toUpperCase(); });
            y = element.currentStyle[styleProp];
        }
        else if(window.getComputedStyle)
        {
            y = document.defaultView.getComputedStyle(element, null).
                    getPropertyValue(styleProp);
        }

        return y;
    }

    function GoodBrowser()
    {
        var bRetVal = true;

        // no good if screen width is too small
        if(screen.width <= _widthThreshold)
        {
            bRetVal = false;
        }

        // no good for these devices because they don't do position:fixed
        if(navigator.userAgent.match(/iPhone/i)  ||
           navigator.userAgent.match(/iPad/i)    ||
           navigator.userAgent.match(/iPod/i)    ||
           navigator.userAgent.match(/Android/i)    )
        {
            bRetVal = false;
        }

        // no good if less than IE 7
        var regExp = new RegExp("MSIE (\\d+\\.\\d+)");
        if(regExp.exec(navigator.userAgent))
        {
            var ieVersion = parseFloat(RegExp.$1);

            if(ieVersion < 7.0)
            {
                bRetVal = false;
            }
        }

        return bRetVal;
    }

    function HandleKeyDown(e)
    {
        var keyCodeEscape     = 27;
        var keyCodeArrowLeft  = 37;
        var keyCodeArrowRight = 39;
        var keyCodeLowercaseA = 65;
        var keyCodeLowercaseC = 67;
        var keyCodeLowercaseF = 70;
        var keyCodeLowercaseN = 78;
        var keyCodeLowercaseP = 80;
        var keyCodeLowercaseS = 83;
        var keyCodeLowercaseT = 84;
        var keyCodeLowercaseX = 88;

        var bRetVal           = true;

        if(e == null)
        {
            e = window.event;
        }

        if(e.altKey == false) // don't do switch if alt key pressed
        {
            bRetVal = false;

            switch(e.keyCode)
            {
                case keyCodeLowercaseA: // Actual size
                case keyCodeLowercaseF: // Fit
                case keyCodeLowercaseS: // Size toggle
                case keyCodeLowercaseT: // Toggle size
                    ToggleSize();
                    break;

                case keyCodeEscape:
                case keyCodeLowercaseC: // Close
                case keyCodeLowercaseX: // "x"
                    Hide();
                    break;

                case keyCodeArrowLeft:
                case keyCodeLowercaseP: // Previous
                    PrevImage();
                    break;

                case keyCodeArrowRight:
                case keyCodeLowercaseN: // Next
                    NextImage();
                    break;

                default:
                    bRetVal = true;
                    break;
            }
        }

        return bRetVal;
    }

    // ??? ipad
    // function IBClear()
    // {
        // _popupImageBar.style.display = "none";
    // }

    // ??? ipad
    // function IBShow()
    // {
        // if(_popupImage.style.display == "block")
        // {
            // _popupImageBar.style.display = "block";
        // }
    // }

    function ImageIndex(eThumb)
    {
        var imageIndex = 0;
        var numItems   = _imageInfoArray.length;

        for(var i = 0; i < numItems; i++)
        {
            if(eThumb == _imageInfoArray[i].eThumb)
            {
                imageIndex = i;
                break;
            }
        }

        return imageIndex;
    }

    function ImageInfo()
    {
        var eThumb;
        var tWidth;
        var tHeight;
        var eImage;
        var iWidth;
        var iHeight;
        var eTitle;
        var date;
    }

    function RegisterEvent(target, functionRef, taskType)
    {
        taskType = (window.addEventListener) ? taskType : "on" + taskType;

        if(target.addEventListener)
        {
            target.addEventListener(taskType, functionRef, false);
        }
        else if(target.attachEvent)
        {
            target.attachEvent(taskType, functionRef);
        }
    }

    // ??? iPad
    // function RepositionImageBar()
    // {
        // if(_popupImage.style.display == "block")
        // {
            // var dp = GetDocProperties();

            // _popupImageBar.style.top = dp.scrollTop + "px";
        // }
        // // else
        // // {
            // // clearInterval(_popupImageBarUpdateId); // ??? not needed
        // // }
    // }

    function ResizeImage()
    {
        if(_popupImage.style.display == "block")
        {
            SizeImage();
        }
    }

    function SizeImage()
    {
        var dp           = GetDocProperties();
        var extraWidth   = _popupImage.offsetWidth        -
                           parseInt(_fullImage.style.width)  +
                           (2 * _imagePaddingPx);
        var extraHeight  = _popupImage.offsetHeight       -
                           parseInt(_fullImage.style.height) +
                           (2 * _imagePaddingPx);
        var clientHeight = dp.clientHeight - _popupImageBar.offsetHeight;
        
        var newWidth  = dp.clientWidth - extraWidth;
        var newHeight = Math.round((newWidth / _fullImageWidth) *
                                   _fullImageHeight);

        if(clientHeight < (newHeight + extraHeight))
        {
            newHeight = clientHeight - extraHeight;
            newWidth  = Math.round((newHeight / _fullImageHeight) *
                                   _fullImageWidth);
        }

        if(_bImageSizeFit == false)
        {
            newWidth = _fullImageWidth;
            newHeight = _fullImageHeight;
        }
        else
        {
            newWidth  = (newWidth  >= 0 ? newWidth  : 0);
            newHeight = (newHeight >= 0 ? newHeight : 0);
        }
        _fullImage.style.width  = newWidth  + "px";
        _fullImage.style.height = newHeight + "px";

        if(_bImageSizeFit == true)
        {
            _popupImageBarButtonSize.innerHTML = "Actual Size";
        }
        else
        {
            _popupImageBarButtonSize.innerHTML = "Fit";
        }

        if(navigator.userAgent.match(/MSIE 6/i) ||
           navigator.userAgent.match(/MSIE 7/i)    )
        {
            _popupImageTopBarTable.style.width =
                newWidth + (2 * _imageBorderPx) + "px";
        }

        CenterImage();
    }
}

////////////////////////
// ShowHideDiv object //
////////////////////////

function ShowHideDiv()
{
    // public methods

    this.Flip = Flip;

    // private methods

    // private properties

    // constructor

    {
        var html = "";

        html += "<style type='text/css'>";
        html += "div.showDetails {}";
        html += "div.details { display : none; }";
        html += "</style>";

        document.writeln(html);
    }

    // public methods

    function Flip(id)
    {
        document.getElementById(id + "Show").style.display = "none";
        document.getElementById(id).style.display = "inline-block";
    }
}

//////////////////////
// Thumbnail object //
//////////////////////

function Thumbnail()
{
    // public methods

    this.Last             = Last;
    this.SetHSpace        = SetHSpace;
    this.SetImageDir      = SetImageDir;
    this.SetMaxThumbWidth = SetMaxThumbWidth;
    this.Show             = Show;
    this.ShowImageLink    = ShowImageLink;
    this.SetVSpace        = SetVSpace;

    // public properties

    // private methods

    // private properties

    var _eImageDir     = "images";
    var _borderWidth;                // image border width (in pixels)
    var _padding;                    // image padding (in pixels)
    var _shadowWidth;                // image shadow (in pixels)
    var _maxThumbWidth = 150;
    var _hSpace        = 10;         // horizontal space between images for
                                    // simple thumbnails (in pixels)
    var _vSpace        = 10;         // vertial space between images for
                                    // simple thumbnails (in pixels)
    var _bLast         = false;

    // constructor

    {
        var theClass = "img.thumbnail";

        pi = new PopupImage("pi");

        // get border, padding and shadow information (units assumed to be px)
        _borderWidth = GetClassStyleElementValuePx(theClass, "borderWidth", 1);
        _padding     = GetClassStyleElementValuePx(theClass, "padding",     5);
        _shadowWidth = GetClassStyleElementValuePx(theClass, "marginRight", 5);
    }

    // public methods

    function Last()
    {
        _bLast = true;
    }

    function SetHSpace(hSpace)
    {
        _hSpace = hSpace;
    }

    function SetImageDir(imageDir)
    {
        _eImageDir = escape(imageDir);
        pi.SetImageDir(imageDir);
    }

    function SetMaxThumbWidth(maxThumbWidth)
    {
        _maxThumbWidth = maxThumbWidth;
    }

    function SetVSpace(vSpace)
    {
        _vSpace = vSpace;
    }

    function Show(thumb, tWidth, tHeight, image, iWidth, iHeight,
                  title, date, extraText,
                  thumb2, tWidth2, tHeight2, image2, iWidth2, iHeight2,
                  title2)
    {
        var html           = "";
        var thumbStyle     = "";
        var titleExists    = (typeof title  != "undefined");
        var title2Exists   = (typeof title2 != "undefined");
        var eThumb         = escape(thumb.stripX());
        var eImage         = escape(image.stripX());
        var eTitle;
        var eTitle2;
        var realThumbWidth = GetRealThumbWidth();

        if(titleExists)
        {
            eTitle = escape(title.stripX().stripBrackets());
        }
        else
        {
            eTitle = "";
        }

        pi.AddImageInfo(eThumb, tWidth, tHeight,
                        eImage, iWidth, iHeight,
                        eTitle, date);

        if(title2Exists)
        {
            eTitle2 = escape(title2.stripX().stripBrackets());
        }
        else
        {
            eTitle2 = eTitle;
        }

        var hSpaceLocal = (realThumbWidth - tWidth) / 2 + _hSpace;

        if(titleExists)
        {
            html += "<table style='width:100%'><tr>";
            html += "<td " +
                    "style='padding:4pt;text-align:right;vertical-align:top;" +
                    "width:" + realThumbWidth + "px'>";
        }

        html += "<img class='thumbnail' width='" + tWidth +
                "' height='" + tHeight + "' " +
                "onclick=\"pi.Show('" + eThumb + "', '" +
                eImage + "'," + iWidth + "," + iHeight + ",'" + eTitle + "','" +
                date + "')\" ";

        if(!titleExists)
        {
            thumbStyle += "margin-top:"    + _vSpace     + "px;" +
                          "margin-bottom:" + _vSpace     + "px;" +
                          "margin-left:"   + hSpaceLocal + "px;" +
                          "margin-right:"  + hSpaceLocal + "px;" +
                          "vertical-align:top";
        }

        html += "src='" + _eImageDir + "/" + eThumb + "' alt='' " +
                "title='Click to View Larger Image' " +
                "style='" + thumbStyle + "' />";

        if(titleExists)
        {
            html += "</td>";
            html += "<td " +
                    "style='padding:4pt;vertical-align:top;" +
                           "text-align:justify'>" +
                    "<strong>" + title.stripBrackets() + "</strong><br />";
            html += "<em>" + date + "</em>";
            html += "<br />";

            if(typeof extraText != "undefined")
            {
                html += extraText.stripBrackets();
            }

            html += "</td>";
        }

        if(typeof thumb2 != "undefined")
        {
            var eThumb2 = escape(thumb2.stripX());
            var eImage2 = escape(image2.stripX());

            pi.AddImageInfo(eThumb2, tWidth2, tHeight2,
                            eImage2, iWidth2, iHeight2,
                            eTitle2, date);

            if(titleExists)
            {
                html += "<td " +
                        "style='padding:4pt;text-align:left;" +
                               "vertical-align:top;" +
                        "width:" + realThumbWidth + "px'>";
            }

            html += "<img class='thumbnail' width='" + tWidth2 +
                    "' height='" + tHeight2 + "' " +
                    "onclick=\"pi.Show('" + eThumb2 + "', '" +
                    eImage2 + "'," + iWidth2 + "," + iHeight2 + ",'" + eTitle2 +
                    "','" + date + "')\" ";

            html += "src='" + _eImageDir + "/" + eThumb2 + "' alt='' " +
                    "title='Click to View Larger Image' " +
                    "style='" + thumbStyle + "' />";

            if(titleExists)
            {
                html += "</td>";
            }
        }

        if(titleExists)
        {
            html += "</tr></table>";
            if(!_bLast)
            {
                html += "<hr />";
            }
        }

        document.writeln(html);
    }

    function ShowImageLink(thumb, tWidth, tHeight, link, caption, title)
    {
        var html           = "";
        var captionExists  = (typeof caption  != "undefined");
        var titleExists    = (typeof title    != "undefined");
        var eThumb         = escape(thumb);
        var style          = "";
        var thumbStyle     = "";
        var realThumbWidth = GetRealThumbWidth();

        if(!captionExists)
        {
            caption = "";
        }

        if(!titleExists)
        {
            title = "";
        }

        var hSpaceLocal = (realThumbWidth - tWidth) / 2 + _hSpace;

        style += "margin-top:"    + _vSpace     + "px;" +
                 "margin-bottom:" + _vSpace     + "px;" +
                 "margin-left:"   + hSpaceLocal + "px;" +
                 "margin-right:"  + hSpaceLocal + "px;" +
                 "display:inline-table;"                +
                 "*display:inline;"; // hack for MSIE

        html += "<table style='" + style + "'>";
        html += "<tr>";
        html += "<td>";
        html += "<img class='thumbnail' width='" + tWidth +
                "' height='" + tHeight + "' " +
                "src='" + _eImageDir + "/" + eThumb + "' alt='' " +
                "title='" + title + "' " +
                "style='" + thumbStyle + "'" +
                "onclick='location.href=\"" + link + "\"' />";
        html += "</td>";
        html += "</tr>";
        html += "<tr>";
        html += "<td class='imageLinkCaption'>";
        html += caption;
        html += "</td>";
        html += "</tr>";
        html += "</table>";

        document.writeln(html);
    }

    // private methods

    function GetClassStyleElementValuePx(theClass, element, defaultValue)
    {
        var retVal = Number.NaN;

        if(document.styleSheets)
        {
            for(var s = 0; s < document.styleSheets.length; s++)
            {
                var theCss = [];

                if(document.styleSheets[s].cssRules)
                {
                    // standards compliant
                    theCss = document.styleSheets[s].cssRules;
                }
                else
                {
                    // IE
                    theCss = document.styleSheets[s].rules;
                }

                for(var i = 0; i < theCss.length; i++)
                {
                    if(theCss[i].selectorText.toLowerCase() ==
                       theClass.toLowerCase()                  )
                    {
                        retVal = parseInt(theCss[i].style[element]);
                        break;
                    }
                }
            }
        }

        if(isNaN(retVal))
        {
            retVal = defaultValue;
        }

        return retVal;
    }

    function GetRealThumbWidth()
    {
        var retVal = (    _maxThumbWidth) +
                     (2 * _borderWidth  ) +
                     (2 * _padding      ) +
                     (    _shadowWidth  );

        return retVal;
    }
}

//////////////////////
// Watermark object //
//////////////////////

function Watermark(ref, image, imageHover)
{
    // public methods

    this.SetWidthThreshold = SetWidthThreshold;

    // public properties

    // private methods

    // private properties

    var _widthThreshold     = 760;
    var _watermarkLeftPad   = 5;
    var _watermarkBottomPad = 5;
    var _watermark          = null;
    var _image              = null;
    var _imageHover         = null;
    var _updateId           = null;

    // constructor

    {
        if(GoodBrowser())
        {
            // set image variables
            _image = new Image();
            _image.src = image;
            if(imageHover != null)
            {
                _imageHover = new Image();
                _imageHover.src = imageHover;
            }

            // create the watermark and update
            CreateWatermark(ref, image, imageHover);

            // create globals
            _watermark = document.getElementById("watermark");

            // have it update every 10 ms until image loaded
            _updateId = setInterval(InitialFastUpdates, 10);
        }
    }

    // public methods

    function SetWidthThreshold(threshold)
    {
        _widthThreshold = threshold;
    }

    // private methods

    function CreateWatermark(ref, image, imageHover)
    {
        var html = "";

        html += "<style type='text/css'>";
        html += "div#watermark" +
                "{" +
                    "position          : fixed;"                   +
                    "z-index           : 10;"                      +
                    "background-image  : url(" + image + ");"      +
                    "background-repeat : no-repeat;"               +
                    "width             : " + _image.width  + "px;" +
                    "height            : " + _image.height + "px;" +
                    "cursor            : pointer;"                 +
                    "display           : none;"                    +
                "}";
        if(imageHover != null)
        {
            html += "div#watermark:hover" +
                    "{" +
                        "background-image  : url(" + imageHover + ");" +
                    "}";
        }
        html += "</style>";

        html += "<style type='text/css' media='print'>";
        html += "div#watermark" +
                "{" +
                    "visibility : hidden;" +
                "}";
        html += "</style>";

        html += "<div id='watermark' onclick='location.href=\"" + ref + "\"'>";
        html += "</div>";

        document.writeln(html);
    }

    function DisplayWatermark()
    {
        _watermark.style.left    = _watermarkLeftPad   + "px";
        _watermark.style.bottom  = _watermarkBottomPad + "px";
        _watermark.style.width   = _image.width        + "px";
        _watermark.style.height  = _image.height       + "px";
        _watermark.style.display = "block";
    }

    function GoodBrowser()
    {
        var bRetVal = true;

        // no good if screen width is too small
        if(screen.width <= _widthThreshold)
        {
            bRetVal = false;
        }

        // no good for these devices because they don't do position:fixed
        if(navigator.userAgent.match(/iPhone/i)  ||
           navigator.userAgent.match(/iPad/i)    ||
           navigator.userAgent.match(/iPod/i)    ||
           navigator.userAgent.match(/Android/i)    )
        {
            bRetVal = false;
        }

        // no good if less than IE 7
        var regExp = new RegExp("MSIE (\\d+\\.\\d+)");
        if(regExp.exec(navigator.userAgent))
        {
            var ieVersion = parseFloat(RegExp.$1);

            if(ieVersion < 7.0)
            {
                bRetVal = false;
            }
        }

        return bRetVal;
    }

    function InitialFastUpdates()
    {
        if(_image.complete == true)
        {
            clearInterval(_updateId);
        }

        DisplayWatermark();
    }
}