// WB's Fading Slideshow, v 2
// Copyright (c) 2010 Broomfield Associates

// Object to maintain a fading image set
// See wbfade.txt for how to use, more parameter details and some implementation notes
function Fader(containerdiv, imgclass, imglist, delay, delta, speed, rand) {

    this.fadedelay = delay;         // Delay between images
    this.fadedelta = delta;         // Fade increment (range >0 - <1.0)
    this.fadespeed = speed;         // Speed of fade increment in milliseconds
    this.fadediv = containerdiv;    // div to contain images         

    this.fadepics = new Array();    // To contain the slideshow images for fading
    this.fadeval = 0.0;             // Current opacity setting
    this.fadecurrent = 0;           // Image currently being faded up
    this.fadeprevious = 0;          // Image being covered up
    this.fademax = 0;               // Number of images in the fadepics array

    this.fadetimer = 0;             // Non-zero if fader loop running
    this.fadeevent = ""             // Non-blank when event requests interrupt to loop
    
    this.ctrlss = "";               // div to contain controls
    this.ctrlstop = "";             // Image for stop control
    this.ctrlstart = "";            // Image for start control

    // Locate the container and get its children
    this.fadediv = document.getElementById(containerdiv);
    if(typeof(this.fadediv) == "undefined") return;
    fch = this.fadediv.childNodes;

    // Find the first (and only) child with specified class
    for(i = 0; i < fch.length; i++) {
        if(fch[i].className == imgclass) break;
    };
    if(i == fch.length) return;
    this.fadepics[0] = fch[i];

    // Parse image names and preload the images with same width and height as first
    if(typeof(imglist) == "undefined") return;
    imgarray = imglist.split(";");
    this.fademax = 1;
    for(i = 0; i < imgarray.length; i++) {
        if(imgarray[i].length == 0) continue;
        imgnew = new Image(this.fadepics[0].width, this.fadepics[0].height);
        imgnew.src = imgarray[i];
        imgnew.className = imgclass;
        this.fadepics[this.fademax++] = imgnew;
    };

    // Assuming that we still have a set of images to fade,
    // Select the first image (alternatively, select a random image) with full opacity
    // Replace the initially provided image with the selected one
    // Append the next image in sequence with zero opacity
    // The container div from now on should have two and only two images as children
    if(this.fademax > 1) {
        this.fadecurrent = 0;
        if(rand) this.fadecurrent = Math.floor(Math.random() * this.fademax);
        fadeopacity(this.fadepics[this.fadecurrent], 1.0);
        this.fadediv.replaceChild(this.fadepics[this.fadecurrent], this.fadepics[0]);
        this.fadeprevious = this.fadecurrent;
        if(++this.fadecurrent >= this.fademax) this.fadecurrent = 0;
        fadeopacity(this.fadepics[this.fadecurrent], 0.0);
        this.fadediv.appendChild(this.fadepics[this.fadecurrent]);
        this.fadeval = 0.0;
        fadestart(this, true);
    };

    // Pause the show on the next image 
    this.Stop = function() {
        if(this.fadetimer != 0) {
            this.fadeevent = "stop";
            if(this.fadeval == 0) faderestart(this); 
        };
    }
    // Restart the show at the current image
    this.Start = function() {
        if(this.fadetimer == 0) {
            fadestart(this, false);
        } else {
            this.fadeevent = "";
            faderestart(this);
        };
    }
    // Move the show on to the current image + 1
    this.Increment = function() {
        if(this.fadetimer == 0) {
            fadeopacity(this.fadepics[this.fadecurrent], 1.0);
            fadenext(this);
        } else {
            this.fadeevent = "next";
            faderestart(this);
        }
    }
    // Move the show back to the current image - 1
    this.Decrement = function() {
        if(this.fadetimer == 0) {
            fadeprev(this);
            fadenext(this);
        } else {
            this.fadeevent = "previous";
            faderestart(this);
        }
    }

}


// Set given elements as previous/next controls for the fadeobject
function setPreviousControl(elem, img, wd, ht, fadeobj) {
    element = document.getElementById(elem);
    imgobj = new Image(wd, ht);
    imgobj.src = img; imgobj.title = "Previous Image";
    element.appendChild(imgobj);
    element['onclick'] = function(){ fadeobj.Decrement.call(fadeobj); };    
}
function setNextControl(elem, img, wd, ht, fadeobj) {
    element = document.getElementById(elem);
    imgobj = new Image(wd, ht);
    imgobj.src = img; imgobj.title = "Next Image";
    element.appendChild(imgobj);
    element['onclick'] = function(){ fadeobj.Increment.call(fadeobj); };    
}

// Set given element as a stop/start toggle control for the fadeobject
function setStopStartControl(elem, img1, img2, wd, ht, fadeobj) {
    fadeobj.ctrlss = document.getElementById(elem);
    fadeobj.ctrlstop = new Image(wd, ht);
    fadeobj.ctrlstop.src = img1; fadeobj.ctrlstop.title = "Stop Slide Show";
    fadeobj.ctrlss.appendChild(fadeobj.ctrlstop);
    fadeobj.ctrlstart = new Image(wd, ht);
    fadeobj.ctrlstart.src = img2; fadeobj.ctrlstart.title = "Start Slide Show";
    fadeobj.ctrlss['onclick'] = function(){ fadeobj.Stop.call(fadeobj); };    
}
// Switch stop/start image
function switchss(fadeobj) {
    if(fadeobj.ctrlss == "") return;
    if(fadeobj.fadetimer == 0) {
        fadeobj.ctrlss.replaceChild(fadeobj.ctrlstart, fadeobj.ctrlss.childNodes[0]);
        fadeobj.ctrlss['onclick'] = function(){ fadeobj.Start.call(fadeobj); };
    } else {
        fadeobj.ctrlss.replaceChild(fadeobj.ctrlstop, fadeobj.ctrlss.childNodes[0]);
        fadeobj.ctrlss['onclick'] = function(){ fadeobj.Stop.call(fadeobj); };
    };
}    


// Stop loop temporarily and restart immediately to speed up event handling
function faderestart(fadeobj) {
    clearTimeout(fadeobj.fadetimer);
    fadeobj.fadetimer = 0;
    fadestart(fadeobj, false);
}

// Start the fading sequence, with optional fadedelay - only call when fadetimer is stopped
function fadestart(fadeobj, delay) {
    if(delay) {
        fadeobj.fadetimer = setTimeout(function(){fadeloop(fadeobj)}, fadeobj.fadedelay);
        switchss(fadeobj);
    } else {
        fadeloop(fadeobj);
    };
}
    
// Main fader loop - re-entered repeatedly on timeouts
function fadeloop(fadeobj) {

    // Handle asynchronous events
    switch(fadeobj.fadeevent) {

    // Only stop when faded to next image or just about to
    case "stop":
        if(fadeobj.fadeval == 0 || fadeobj.fadeval == 1.0) {
            if(fadeobj.fadeval == 1.0) fadenext(fadeobj);
            fadeobj.fadetimer = 0;
            switchss(fadeobj);
            fadeobj.fadeevent = "";
            return;
        };
        break;

    // Next image is already there, just make visible
    case "next":
        fadeopacity(fadeobj.fadepics[fadeobj.fadecurrent], 1.0);
        fadeobj.fadeval = 1.0;
        fadeobj.fadeevent = "";
        break;

    // Select the previous image, or the one currently being faded
    case "previous":
        if(fadeobj.fadeval != 0.0) {
            fadeopacity(fadeobj.fadepics[fadeobj.fadecurrent], 0.0);
            fadeobj.fadeval = 0.0;
            fadestart(fadeobj, true);
            fadeobj.fadeevent = "";
            return;
        } else {
            fadeprev(fadeobj);
            fadeobj.fadeevent = "";
        };
        break;
    };

    // Continue to fade or move on to next image
    if(fadeobj.fadeval < 1.0) {
        fadeobj.fadeval += fadeobj.fadedelta;
        if(fadeobj.fadeval > 1.0) fadeobj.fadeval = 1.0;
        fadeopacity(fadeobj.fadepics[fadeobj.fadecurrent], fadeobj.fadeval);
        fadeobj.fadetimer = setTimeout(function(){fadeloop(fadeobj)}, fadeobj.fadespeed);
    } else {
        fadenext(fadeobj);
        fadeobj.fadetimer = setTimeout(function(){fadeloop(fadeobj)}, fadeobj.fadedelay);
    };
    switchss(fadeobj);

}


// Remove hidden image and bring in next
function fadenext(fadeobj) {
    fadeobj.fadediv.removeChild(fadeobj.fadepics[fadeobj.fadeprevious]);
    fadeobj.fadeprevious = fadeobj.fadecurrent;
    if(++fadeobj.fadecurrent >= fadeobj.fademax) fadeobj.fadecurrent = 0;
    fadeopacity(fadeobj.fadepics[fadeobj.fadecurrent], 0.0);
    fadeobj.fadediv.appendChild(fadeobj.fadepics[fadeobj.fadecurrent]);
    fadeobj.fadeval = 0;
}


// When loop stopped, "previous" is visible and "current" transparent, replace the latter with image before "previous"
function fadeprev(fadeobj) {
    fadeobj.temp = fadeobj.fadecurrent;
    fadeobj.fadecurrent = fadeobj.fadeprevious - 1;
    if(fadeobj.fadecurrent < 0) fadeobj.fadecurrent = fadeobj.fademax - 1;
    fadeopacity(fadeobj.fadepics[fadeobj.fadecurrent], 1.0);
    fadeobj.fadediv.replaceChild(fadeobj.fadepics[fadeobj.fadecurrent], fadeobj.fadepics[fadeobj.temp]);
    fadeobj.fadeval = 1.0;
}


// Set opacity of elem to value op
// Takes account of IE v CSS "standard"
function fadeopacity(elem, op) {
    elem.style.opacity = op; opn = 100.0 * op;
    elem.style.filter = 'alpha(opacity=' + opn + ')';
}
