var Slideshow = function(container, args) {

    var delaySeconds    = args.delay || 4;
    var totalframes     = 0;
    var currentframe    = 0;
    var fadeDuration    = args.fadeDuration || 2;
    var items           = null;
    var images          = null;
    var imagesLength    = 0;
    var childrenConfig  = args.childrenToAnimate; // Note: if child fade is happening concurrently with parent fade, smoothness of transition suffers in browsers like IE6 (causes image flickering, etc...)
    var childitems      = [];
    var pause           = args.pauseBeforeNext;
    var onEnd           = args.onEnd;

    function preload(callback) {
        images = $$("#"+container+' li img');
        imagesLength = images.length;
        var next = function() {
          if(--imagesLength == 0) {
            images.invoke('show');
            callback();
          }
        };

        images.each(function($img) {
          var imgSrc = $img.readAttribute('src');

          $img.writeAttribute('src', '').hide();
          $img.observe('load', function(event) {
            next();
          }).observe('error', function(event) {
            next();
          });
          $img.writeAttribute('src', imgSrc);
        });
    }

    function init() {

        items = $(container).select('li');
        
        items.each(function(node, idx) {
            node.hide(); // Hide All
            // get child items, if any
            if (childrenConfig && (!generic.env.isIE || (generic.env.isIE && generic.env.isIE6))) {
            //if (childrenConfig && !generic.env.isIE) {
                var citems = getChildren(node,idx);
                if (citems) {
                    childitems[idx] = citems;
                    //console.log("frame "+idx+" had childitems = ",childitems[idx].nodes);
                }
            }
            
        });
        
        totalframes = items.length - 1;

        // Show first
        show(0);
        
        // Start Timer if more than 1 slide found for transition
        if (items.length > 1) {
            new PeriodicalExecuter(next, delaySeconds);
        }

        if(typeof onEnd === "function") {
          onEnd();
        }

    }
    
    function next() {
        Effect.Fade(items[currentframe], { duration: fadeDuration }); // hide current slide
        var frame = (currentframe == totalframes) ? 0 : currentframe+1;
        // show next slide
        if (pause) {
            show.delay(pause, frame);
        } else {
            show(frame);
        }
        currentframe = frame;
    }

    function show(frameidx) {
            var frameToShow = items[frameidx];
            Effect.Appear(frameToShow, { duration: fadeDuration });
            currentframe = frameidx;
        
            // set up timing for show/hide child
            var citems = childitems[frameidx];
            if (citems && citems.nodes) {
                var delayShow = childrenConfig.delayShow || 0;
                var delayHide = childrenConfig.delayHide || 0;
                if (!delayShow || isNaN(delayShow)) {
                    showChildren(citems);
                } else {
                    showChildren.delay(delayShow, citems);
                }
                if (delayHide && typeof delayHide === 'number' && items.length > 1) { // if no hide delay number, element gets hidden whenever parent does
                    // hide delay based on counting backwards from parent delay
                    delayHide = (delaySeconds - delayHide);
                    hideChildren.delay(delayHide, citems);
                }
            }
    }

//, from: 0, to: 1 }

    function hideChildren(citems) {
        //console.log("hiding children, citems = ",citems); 
        var duration = (childrenConfig.fadeDuration ? childrenConfig.fadeDuration : fadeDuration);
        citems.nodes.each(function(node) {
            Effect.Fade(node, { duration: duration });
        });
    }
    
    function showChildren(citems) {
        //console.log("showing children, citems = ",citems);
        var duration = (childrenConfig.fadeDuration ? childrenConfig.fadeDuration : fadeDuration);
        citems.nodes.each(function(node) {
            Effect.Appear(node, { duration: duration });
        });
    }
    
    function getChildren(containerNode, parentidx) {
        var childnodes = null;
        var citems = {};
        childnodes = containerNode.select("." + childrenConfig.className);
        if (childnodes) {
            citems.nodes = childnodes;
            citems.idx = parentidx;
            childnodes.invoke("hide");
        }
        return citems;
    }

    preload(init);
};
