// $Id: slideshow.js,v 1.10 2007/12/10 21:57:44 cvsuser Exp $
// ---------------------------------------------------------------------
// slideshow.js
// A slideshow widget.
// 
// Requires dom.js and animator.js.
// ---------------------------------------------------------------------

/*@cc_on @*/     // Who doesn't love IE?

function dnSlideshow (id, config, slides) {
    if (!dnSlideshow.registry) dnSlideshow.registry = { };
    dnSlideshow.registry[id] = this;
    
    this.id = id;
    this.slides = slides;
    this.config = config;
    this.curSlide = 0;
    this.curAnimator = null;
    this.curTimer = null;
    this.state = "paused";
    
    if (!config.delay) config.delay = 4;
    if (!config.transition) config.transition = "dissolve";
    if (!config.preloadWindowSize) config.preloadWindowSize = 3;
    if (!config.bgColor) config.bgColor = "#000000";
    if (config.bezel == null) config.bezel = true;
    if (config.bezelImage) config.bezelSrc = config.bezelImage;
    if (!config.allwaysAnimate) config.allwaysAnimate = false;
    
    this.viewport = $(id);
    this.viewport.style.position = "relative";
    this.viewport.style.overflow = "hidden";
    this.viewport.style.padding = "0px";
    this.viewport.style.width = config.width + "px";
    this.viewport.style.height = config.height + "px";
    this.viewport.style.backgroundColor = config.bgColor;
    
    while (this.viewport.firstChild) {
        this.viewport.removeChild(this.viewport.firstChild);
    }
    
    this.slideSetup(0);
    this.slides[0].slide.style.display = "block";
    this.updatePreloadWindow();
    this.updateCaption();
    
    if (config.bezel) {
        dnAddEvent(this.viewport, "mouseover", function (e) {
            dnSlideshow.registry[id].showBezel(e);
        });
        dnAddEvent(this.viewport, "mouseout", function (e) {
            dnSlideshow.registry[id].hideBezel(e);
        });
    }
};

// ---------------------------------------------------------------------

dnSlideshow.prototype.slideSetup = function (i) {
    var slideId = "dnSlideshow:" + this.id + ":slide:" + i;
    var imgId = "dnSlideshow:" + this.id + ":slide:image:" + i;
    
    // Set up slide container div.
    var slide = this.slides[i].slide = document.createElement("div");
    slide.id = slideId;
    slide.style.position = "absolute";
    slide.style.margin = "0px";
    slide.style.padding = "0px";
    slide.style.width = this.config.width;
    slide.style.height = this.config.height;
    slide.style.display = "none";
    slide.style.opacity = 0.9999;  // Fix for FF anti-aliasing bug.
    
    // Set up the image element.
    var img = this.slides[i].img = document.createElement("img");
    dnImageCompleteWatch(img);
    img.id = imgId;
    img.src = this.slides[i].src;
    if (this.slides[i].alt) img.alt = this.slides[i].alt;
    if (this.slides[i].title) img.title = this.slides[i].title;
    img.style.display = "block";
    img.style.position = "absolute";
    img.style.margin = "0px";
    img.style.border = "none";
    img.galleryimg = "no";  // Turn off IE6's annoying image toolbar.

    // Scale the image so that it fits in the viewport.
    var imgWidth = this.slides[i].width;
    var imgHeight = this.slides[i].height;
    var scaledWidth = Math.round(imgWidth * this.config.height / imgHeight);
    var scaledHeight = Math.round(imgHeight * this.config.width / imgWidth);
    if (imgWidth > this.config.width || imgHeight > this.config.height) {
        if (scaledHeight > this.config.height) {
            imgWidth = scaledWidth;
            imgHeight = this.config.height;
        }
        else {
            imgWidth = this.config.width;
            imgHeight = scaledHeight;
        }
    }
    img.style.width = imgWidth + "px";
    img.style.height = imgHeight + "px";
    
    // Center the image and create the matte.
    if (imgWidth < this.config.width) {
        var left = Math.round((this.config.width - imgWidth) / 2);
        var right = this.config.width - (left + imgWidth);
        var matteLeft = slide.appendChild(document.createElement("div"));
        matteLeft.style.display = "block";
        matteLeft.style.position = "absolute";
        matteLeft.style.left = "0px";
        matteLeft.style.width = left + "px";
        matteLeft.style.height = this.config.height + "px";
        matteLeft.style.backgroundColor = this.config.bgColor;
        var matteRight = slide.appendChild(document.createElement("div"));
        matteRight.style.display = "block";
        matteRight.style.position = "absolute";
        matteRight.style.left = (left + imgWidth) + "px";
        matteRight.style.width = right + "px";
        matteRight.style.height = this.config.height + "px";
        matteRight.style.backgroundColor = this.config.bgColor;
        img.style.left = left + "px";
    }
    if (imgHeight < this.config.height) {
        var top = Math.round((this.config.height - imgHeight) / 2);
        var bottom = this.config.height - (top + imgHeight);
        var matteTop = slide.appendChild(document.createElement("div"));
        matteTop.style.display = "block";
        matteTop.style.position = "absolute";
        matteTop.style.top = "0px";
        matteTop.style.height = top + "px";
        matteTop.style.width = this.config.width + "px";
        matteTop.style.backgroundColor = this.config.bgColor;
        var matteBottom = slide.appendChild(document.createElement("div"));
        matteBottom.style.display = "block";
        matteBottom.style.position = "absolute";
        matteBottom.style.top = (top + imgHeight) + "px";
        matteBottom.style.height = bottom + "px";
        matteBottom.style.width = this.config.width + "px";
        matteBottom.style.backgroundColor = this.config.bgColor;
        img.style.top = top + "px";
    }
    
    slide.appendChild(img);
    this.viewport.appendChild(slide);
    
    if (this.slides[i].href) {
        var a = slide.appendChild(document.createElement("a"));
        a.appendChild(slide.removeChild(img));
        a.href = this.slides[i].href;
        if (this.slides[i].target) a.target = this.slides[i].target;
    }
};

// ---------------------------------------------------------------------

dnSlideshow.prototype.updatePreloadWindow = function (direction) {
    var windowSize = this.config.preloadWindowSize;
    var numSlides = this.slides.length;
    
    for (var i = 0; i < windowSize && i + this.curSlide < numSlides; i++) {
        var s = (i + this.curSlide - 1 + numSlides) % numSlides;
        if (!this.slides[s].slide) this.slideSetup(s);
    }
};

// ---------------------------------------------------------------------

dnSlideshow.prototype.start = function () {
    this.state = "play";
    this.scheduleTransition();
};

dnSlideshow.prototype.play = function () {
    if (this.state != "paused") return;
    this.state = "play";
    if (!this.transitionDirection) this.doTransition(1);
};

dnSlideshow.prototype.pause = function () {
    this.state = "paused";
    if (this.curTimer) clearTimeout(this.curTimer);
    this.curTimer = null;
};

dnSlideshow.prototype.next = function () { this.jump(1); };
dnSlideshow.prototype.previous = function () { this.jump(-1); };

dnSlideshow.prototype.jump = function (direction) {
    this.state = "paused";
    if (this.curTimer) clearTimeout(this.curTimer);
    
    var numSlides = this.slides.length;
    var nextSlide = (numSlides + this.curSlide + direction) % numSlides;
    
    if (this.transitionDirection) {
        this.curAnimator.pause();
        this.curAnimator.callback(this.curAnimator,
            this.curAnimator.lastStep, this.curAnimator.lastStep);
        this.curAnimator = null;
        return;
    }
    
    if (this.config.allwaysAnimate) {
        this.doTransition(direction);
    }
    else {
        for (var i = this.slides.length - 1; i >= 0; i--) {
            var slide = this.slides[i].slide;
            if (!slide) continue;
            
            if (i == prevSlide)
                slide.style.display = "block";
            else
                slide.style.display = "none";
        }
    }

    this.curSlide = nextSlide;
    this.updatePreloadWindow();
    this.updateCaption();
};

dnSlideshow.prototype.updateCaption = function () {
    var captionId = this.config.captionId;
    if (!captionId) return;
    var caption = this.slides[this.curSlide].caption;
    if (!caption) caption = "";
    
    var captionElem = $(captionId);
    if (!captionElem) return;
    captionElem.innerHTML = caption;
};

// ---------------------------------------------------------------------

dnSlideshow.prototype.scheduleTransition = function (direction) {
    if (!direction) direction = 1;
    var delay = this.slides[this.curSlide].delay;
    if (!delay) delay = this.config.delay;
    delay = Math.round(delay * 1000);

    var id = this.id;
    this.curTimer = setTimeout(function () {
        dnSlideshow.registry[id].doTransition(direction);
    }, delay);
};

// ---------------------------------------------------------------------

dnSlideshow.prototype.doTransition = function (direction) {
    this.curTimer = null;
    if (this.state != "play" && !this.config.allwaysAnimate) return;
    
    var numSlides = this.slides.length;
    var nextSlide = (this.curSlide + direction + numSlides) % numSlides;
    
    // Make sure the next image has finished loading.
    if (!dnImageComplete(this.slides[nextSlide].img)) {
        var id = this.id;
        this.curTimer = setTimeout(function () {
            dnSlideshow.registry[id].doTransition(direction);
        }, 300);
        return;
    }
    
    this.transitionDirection = direction;
    
    var transition = this.slides[this.curSlide].transition;
    if (!transition) transition = this.config.transition;
    var attTransition = "__" + transition + "Transition";
    
    if (!this[attTransition])
        this[attTransition] = dnSlideshow.transitions[transition];
    this[attTransition](this.curSlide, nextSlide, direction);
    
    this.curSlide = nextSlide;
    this.updatePreloadWindow();
    this.updateCaption();
};

// ---------------------------------------------------------------------
// A cleanup function to be run on the last step of a transition animation.

dnSlideshow.transitionCleanup = function (id) {
    var slideshow = dnSlideshow.registry[id];
    slideshow.transitionDirection = 0;
    slideshow.curAnimator = null;
    if (slideshow.state == "play") slideshow.scheduleTransition();
};

// ---------------------------------------------------------------------
// Storage for the transition functions. Note that these are attached to
// the dnSlideshow object before execution, which is why the this keyword
// will refer to the right dnSlideshow object.

dnSlideshow.transitions = { };

dnSlideshow.transitions.dissolve = function (a, b, direction) {
    var slideA = this.slides[a].slide.id;
    var slideB = this.slides[b].slide.id;
    
    $(slideA).style.zIndex = 2;
    $(slideB).style.zIndex = 1;
    $(slideB).style.display = "block";
    
    var id = this.id;
    this.curAnimator = new dnAnimator(slideA, function (anim, step, last) {
        if (step == last) {
            $(slideA).style.display = "none";
            $(slideA).style.opacity = 0.9999;
            $(slideA).style.filter = "alpha(opacity=100)";
            $(slideA).style.zIndex = 0;
            $(slideB).style.zIndex = 0;
            dnSlideshow.transitionCleanup(id);
        }
    });
    
    this.curAnimator.registerCssProperty("opacity", 0.9999, 0);
    this.curAnimator.animate(1000);
};

dnSlideshow.transitions.slide = function (a, b, direction) {
    var slideA = this.slides[a].slide.id;
    var slideB = this.slides[b].slide.id;
    
    $(slideA).style.zIndex = 1;
    $(slideB).style.zIndex = 2;
    
    var left = direction * this.config.width;
    $(slideB).style.left = left + "px";
    $(slideB).style.display = "block";
    
    var id = this.id;
    this.curAnimator = new dnAnimator(null, function (anim, step, last) {
        if (step == last) {
            $(slideA).style.display = "none";
            $(slideA).style.left = "0px";
            $(slideB).style.left = "0px";
            $(slideA).style.zIndex = 0;
            $(slideB).style.zIndex = 0;
            dnSlideshow.transitionCleanup(id);
        }
    });
    
    var floatProg = dnAnimator.progression["float"];
    var aAnim = new dnAnimator(slideA);
    aAnim.registerCssProperty("left", 0, -1 * left, "px", floatProg);
    var bAnim = new dnAnimator(slideB);
    bAnim.registerCssProperty("left", left, 0, "px", floatProg);
    
    this.curAnimator.addChildAnimator(aAnim);
    this.curAnimator.addChildAnimator(bAnim);
    this.curAnimator.animate(1000);
};

// ---------------------------------------------------------------------

dnSlideshow.prototype.showBezel = function (e) {
    if (!this.bezel) {
        var width = 334;
        var height = 57;
        if (this.config.width < 450) {
            var tmpWidth = width;
            width = Math.round(this.config.width / 2);
            height = Math.round(width * height / tmpWidth);
        }

        // IE 6 can't handle transparent PNGs unless we do this.
        /*@if (@_jscript_version > 5.6) @*/
        this.bezel = document.createElement("img");
        this.bezel.src = dnSlideshow.largeBezel;
        /*@else
        this.bezel = document.createElement("div");
        this.bezel.style.position = "absolute";
        this.bezel.style.zIndex = 100;
        this.bezel.style.filter = "Alpha(opacity=80); progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.config.bezelSrc + "', sizingMethod='scale')";
        @end @*/
        
        // IE 7 can't handle data URLs.
        /*@if (@_jscript_version > 5.6)
        this.bezel.src = this.config.bezelSrc;
        @end @*/
        
        this.bezel.id = "dnSlideshow:" + this.id + ":bezel";
        this.bezel.style.position = "absolute";
        this.bezel.style.top = "80%";
        this.bezel.style.left = Math.round((this.config.width - width) / 2) + "px";
        this.bezel.style.width = width + "px";
        this.bezel.style.height = height + "px";
        this.bezel.style.cursor = "pointer";
        this.bezel.style.zIndex = 100;
        this.bezel.style.display = "none";
        
        var slideshowId = this.id;
        dnAddEvent(this.bezel, "click", function (e) {
            var x = e.layerX ? e.layerX : e.offsetX;
            if (x == null) return;
            
            var s = dnSlideshow.registry[slideshowId];
            if (x < 0.3 * width)
                s.previous();
            else if (x > 0.6 * width)
                s.next();
            else {
                if (s.state == "play")
                    s.pause();
                else
                    s.play();
            }
        });
        
        this.viewport.appendChild(this.bezel);
    }
    
    // Making IE 6 animate opacity *and* using alphaImageLoader is just
    // too much. Let's not even try.
    /*@if (@_jscript_version > 5.6) @*/
    if (!this.bezelAnimator) {
        var id = this.bezel.id;
        this.bezelAnimator = new dnAnimator(id, function (anim, step, last) {
            var bezel = $(id);
            if (step == 0)
                bezel.style.display = "none";
            else
                bezel.style.display = "block";
        });
        
        this.bezelAnimator.registerCssProperty("opacity", 0, 0.75);
        this.bezelAnimator.animate(300);
        return;
    }
    
    this.bezelAnimator.reverse();
    
    /*@else
    this.bezel.style.display = "block";
    @end @*/
};

dnSlideshow.prototype.hideBezel = function (e) {
    if (!this.bezel) return;
    
    /*@if (@_jscript_version > 5.6) @*/
    this.bezelAnimator.reverse();
    
    /*@else
    this.bezel.style.display = "none";
    @end @*/
};

// ---------------------------------------------------------------------

dnSlideshow.largeBezel = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAU4AAAA5CAMAAABu3TKWAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA9lBMVEUAAAD///8UCgoSCQkRBwcRCgUOCgcPCAcOCgcNCAUMBwQNBQMNCAUNCQUOCAUOCAYOCQUOCQYPBwUPCAUPCQUPCgcQCwgRDAkSDQoTDgsWEQ4ZFBEaFRIdGBUeGRYjHxwpJCIqJSMrJiQvKigwKyk1MS89OTY+OjdCPzxFQT9GQkBNSUdPS0lQTEpWU1FXVFJhXVtkYF5qZ2VzcG50cW98eXiGg4KOjIqPjYuXlZShn56ioJ+rqqmzsbC1s7K8u7q9vLvGxcTJyMfOzc3V1NTW1dXc3Nvj4+Lp6Ojt7Ozx8fH19fX29vb4+Pj5+fn7+/v9/f3///+vwS1xAAAACnRSTlMAARodS2u5vuj+Z8wUwAAAAyxJREFUeNrt3GdX4kAUBuBQZbOoodhR3FXsvXfFAnZ5//+f2YSlhUyy4NzMxXXup5zMgfPm8SZOwpkYhlORWCKZyuj6ZKWSiVjEaFV0SJPI1lC0gRmJawyKiv9tUK1J5Vk/07UDVdnne0RfN+munxEjphXoKmYkNAJdJYykRqCrpOE7ex/1bHzv6sUjZfiPWdpRpGoFjRoaiLJ8OCdn7ZoZwLwzTrBJZ8vZmB1jDNAH5y7suq1v5kXjEwcrIcVdOZgQ7W6muHWC7dobY84GfiuP0ArwSU5RbTxgMyTOTTxsBAyr4AyMQM+5eGUPhscJXC0ycwZEoOYsnLwjZE68nxSYOX0jEHPuPdaPI1xO4HGPmdMvAinn6h2ghBO4W2XmFEcg5Jy/AJRxAhfzzJyiCGSc00cvUMqJl6NpZk5vBBnObMeunSqgmBOo7rgGs8o5uyJkibpzqQwwcALlJdbu9ESg4Cye1cDEidpZUXRTopCzFYGGc+rwGWDjBJ4Pp1i70xVBmnOrArByApUtZs52BEnO0jXAzglcl5g5mxEkOasYCE5Uf3FzokrAWTh+GwDOt+MCd3c2IkhfOxcu2TkvF9ivnc0IBBOl9XtWzvt13nmnKwLFvHN8/4mN82l/nHka74pAc1c0d/rBwvlxOsd9V+SOQPUIpHTDwHlTYn4E4okgyTnS3rldUcxZ2eZ+QOeKMCLLmXPv7bzbDJ+z896yUTnFnJ4IObnuzJvu/cXzmiLO2nnRM5ZX252eCOm87Mludo8sl5VwlpfFwwo5vRHSGXLO5nPkUDm7nhpzcIoihMJp/8rxKstpBR3Lq/c3DdWc4gjhcNZ/gwuvO0W/uCnm9IlAwinspDVnNjZK3J7O95XWAj8XNqd/BEuCs1Vm4z/qd698szuDy+jla3xATZlowvrB75buV6Evzvb8tVcSkj4YgFYMOPjPc/5sbQ0THnPuK3kO9/HBf3anJTilTdPM/NeVTgvO+bTVA+dgrbvOfu0/Q0qvK6KspF71RlkJvSaTsmJ6xTBh2SuG9Xp2uorqty0QVly/C4RSM6LfVEN33Yy23/yj36MkN3tvvUfpD3Z8klZvF7BGAAAAAElFTkSuQmCC";

// ---------------------------------------------------------------------
