function slideShow (picsObj)
{
    this.mState = 0;
    this.mNewImage = null;
    this.mFirstThumbnailIndex = 0;
    this.mSlotList = 0;
    
    this.show = function (tagRef, picIndex)
    {
        var img = document.getElementById ("idImg");
        var url = picsObj.mPicsPath + picsObj.mPicArray [picIndex].ur;
        
        function onFadeOutComplete ()
        {
            this.pleaseWait (true);
            this.mState++;
            this.displayNewImage ();
            this.printCaption (picsObj.mPicArray [picIndex].tx);
        }                    
        
        function toggleNavSquare (navSqrElem)
        {
            if (YAHOO.util.Dom.getStyle (navSqrElem, "backgroundColor") == "yellow")
                YAHOO.util.Dom.setStyle (navSqrElem, "backgroundColor", "aqua"); //mark nav menu
            else
                YAHOO.util.Dom.setStyle (navSqrElem, "backgroundColor", "yellow"); //mark nav menu
        }
        
        if ((url != null) && (img != null))
        {
            var attrib = {opacity: {to: 0.0}};
            var anim = new YAHOO.util.Anim ("idImg", attrib, 0.25); //fade image to transparent
            this.mState = 0;
            this.mNewImage = null;
            anim.onComplete.subscribe (onFadeOutComplete, this, true);
            this.loadNewImage (url); //begin async-loading new image
            anim.animate (); //begin fadeout of current image
            if (tagRef)
                toggleNavSquare (tagRef);
            pageTracker._trackPageview (url); //Google Analytics tracking
        }
    } //show
    
    this.loadNewImage = function (url) //asynchronously load a new image
    {
        function onLoadComplete ()
        {
            this.mState++;
            this.displayNewImage ();
        }
        
        this.mNewImage = document.createElement ("img");
        this.mNewImage.id = "idImg";
        YAHOO.util.Event.addListener (this.mNewImage, "load", onLoadComplete, this, true);
        this.mNewImage.src = url; //begin async loading
    }
    
    this.displayNewImage = function ()  //add new image to DOM
    {
        if (this.mState == 2)
        {
            var attrib = {opacity: { to: 1 }};
            var anim = null;
            var imgDiv = document.getElementById ("idImageDiv");
            var img = document.getElementById ("idImg");
            
            try
            {
                YAHOO.util.Dom.setStyle (this.mNewImage, "opacity", 0); //set to total transparent
            }
            catch (e)
            {
                this.mNewImage.style.filter = "alpha(opacity=0)"; //IE only
            }
            imgDiv.removeChild (img);
            imgDiv.appendChild (this.mNewImage);
            anim = new YAHOO.util.Anim ("idImg", attrib, 0.25);
            this.pleaseWait (false);
            anim.animate (); //begin fadein of new image
        }
    }
    
    this.pleaseWait = function (wait)
    {
        var waitDiv = document.getElementById ("idWait");
        if (wait)
        {
            if (waitDiv.firstChild)
                waitDiv.removeChild (waitDiv.firstChild);
            waitDiv.appendChild (document.createTextNode ("loading photo"));
        }
        else
        {
            if (waitDiv.firstChild)
                waitDiv.removeChild (waitDiv.firstChild);
        }
    }//pleaseWait
    
    this.printCaption = function (text)
    {
        var cap = document.getElementById ("idCaption");
        if (cap)
        {
            if (cap.firstChild)
                cap.removeChild (cap.firstChild);
            cap.appendChild (document.createTextNode (text));
        }
    }//printCaption


    this.initThumbnail = function ()
    {
        //mouse has clicked on a nav arrow
        function clickNavEvent (event, slideShowObj)
        {
            if (this.id == "idPrevPage")
            {
                var newFirstIndex = slideShowObj.mFirstThumbnailIndex - slideShowObj.mSlotList.length;
                //check if new index is within bound
                if (newFirstIndex >= 0)
                    slideShowObj.displayThumbnail (newFirstIndex);
            }
            else if (this.id == "idNextPage")
            {
                var newFirstIndex = slideShowObj.mFirstThumbnailIndex + slideShowObj.mSlotList.length;
                //check if new index is within bound
                if (newFirstIndex < picsObj.mPicArray.length)
                    slideShowObj.displayThumbnail (newFirstIndex);
            }
        }

        //get a list of elements that are slots for display thumbnails
        this.mSlotList = YAHOO.util.Dom.getElementsByClassName ("sqrPics", "img", "idTinyPics");;
        var ids = ["idPrevPage","idNextPage"];
        YAHOO.util.Event.addListener (ids, "click", clickNavEvent, this);
    }
    
    
    this.displayThumbnail = function (firstPicIndex)
    {
        var picIndex = firstPicIndex; //index of photo in slot #1

        //mouse has clicked on a thumbnail
        function clickSlotEvent (event, slideShowObj)
        {
            //get the index number of the photo
            var picIndex = this.getAttribute("picIndex");
            //compose url of the big photo
            var url = picsObj.mPicsPath + picsObj.mPicArray [picIndex].ur;
            slideShowObj.show (null, picIndex);
        }
        
        function load (elem)
        {
            if (picIndex < picsObj.mPicArray.length)
            {
                //calculate thumbnail's url
                var url = picsObj.mPicsPath + picsObj.mPicArray [picIndex].ur;
                var lastSlash = url.lastIndexOf ("/");
                var url2 = url.slice (0, lastSlash) + "/tiny/" + url.slice(lastSlash);
                elem.setAttribute ("src", url2);
                
                //set the index number of the photo
                elem.setAttribute ("picIndex", picIndex);
                //remove then set a handler for the mouse-click event
                YAHOO.util.Dom.setStyle (elem, "display", "inline");
                YAHOO.util.Event.purgeElement (elem);
                YAHOO.util.Event.addListener (elem, "click", clickSlotEvent, this);
            }
            else
            {
                YAHOO.util.Dom.setStyle (elem, "display", "none");
                elem.setAttribute ("src", ""); //do not display anything
                //remove all listener on that element
                YAHOO.util.Event.purgeElement (elem);
            }
            picIndex++;
        }

        function displayPageNumber (slotList)
        {
            var prev = YAHOO.util.Dom.get ("idPrevPage");
            var next = YAHOO.util.Dom.get ("idNextPage");
            var elem = YAHOO.util.Dom.get ("idPageNumber");
            var text = Math.ceil(firstPicIndex/15)+ 1 + " / " + Math.ceil(picsObj.mPicArray.length/15);

            if (elem.firstChild)
                elem.removeChild (elem.firstChild);
            elem.appendChild (document.createTextNode (text));
            
            YAHOO.util.Dom.setStyle (prev, "visibility", (firstPicIndex>0) ? "visible" : "hidden");
            YAHOO.util.Dom.setStyle (next, "visibility",
                ((firstPicIndex+slotList.length) < picsObj.mPicArray.length) ? "visible" : "hidden");
        }
        
        this.mFirstThumbnailIndex = firstPicIndex;
        //run load() on each slot to display thumbnails
        YAHOO.util.Dom.batch (this.mSlotList, load, this, true);
        displayPageNumber (this.mSlotList);
    } //displayThumbnail
} //model
