/**
Script: Slideshow.js
    Slideshow - A javascript class for Mootools to stream and animate the presentation of images on your website.

License:
    MIT-style license.

Copyright:
    Copyright (c) 2008 [Aeron Glemann](http://www.electricprism.com/aeron/).

Dependencies:
    Mootools 1.2 Core: Fx.Morph, Fx.Tween, Selectors, Element.Dimensions.
    Mootools 1.2 More: Assets.
*/

Slideshow = new Class({
    Implements: [Chain, Events, Options],
    
    options: {/*
        onComplete: $empty,
        onEnd: $empty,
        onStart: $empty,*/
        captions: false,
        center: true,
        classes: [],
        controller: false,
        delay: 3000,
        duration: 750,
        fast: false,
        height: false,
        href: '',
        hu: '',
        linked: false,
        loader: {'animate': ['css/loader-#.png', 12]},
        loop: true,
        match: /\?slide=(\d+)$/,
        overlap: true,
        paused: false,
        properties: ['href', 'rel', 'rev', 'title'],
        random: false,
        trueimgonly: false,
        replace: [/(\.[^\.]+)$/, 't$1'],
        resize: 'width',
        slide: 0,
        curslide: 0,
        thumbnails: false,
        titles: true,
        transition: function(p){return -(Math.cos(Math.PI * p) - 1) / 2;},
        width: false,
        thumbsize: 100,
        extracontrol: false,
        hidecontrols: false,
        thumbclass: 'thumbnails',
        canedit: false,
        canshare: false,
        thumbpos: {},
        thumbfade: false
    },
    
    isPaused: function(){
        return this.paused;
    },
    
    getCurSlide: function(){
        return this.curslide;
    },
    
    getNextTrueImg: function(curIndex){
        for(var i = curIndex+1; i < this.data.trueimg.length; ++i) {
            if(this.data.trueimg[i]) {
                return i;
            }
        }
        for(var i = 0; i < curIndex+1; ++i) {
            if(this.data.trueimg[i]) {
                return i;
            }
        }
        return 0;
    },
    
    getPrevTrueImg: function(curIndex){
        for(var i = curIndex-1; i >= 0; --i) {
            if(this.data.trueimg[i]) {
                return i;
            }
        }
        for(var i = this.data.trueimg.length-1; i >= curIndex; --i) {
            if(this.data.trueimg[i]) {
                return i;
            }
        }
        return 0;
    },

    showController: function() {
        var ctrlClass = 'controller';
        if(this.options.extracontrol)
            ctrlClass = 'controller-extra3';
        this.slideshow.retrieve(ctrlClass).fireEvent('show');

        if (this.options.thumbnails && this.options.thumbfade && this.slideshow.retrieve('thumbnails'))
            this.slideshow.retrieve('thumbnails').fireEvent('show');
        if(this.options.thumbfade && this.hideTimer == null) {
            this.hideTimer = (function(){
                this.hideTimer = null;
                if(this.slideshow && this.slideshow.retrieve(ctrlClass)) {
                    this.slideshow.retrieve(ctrlClass).fireEvent('hide');
                    if (this.options && this.options.thumbnails && this.options.thumbfade && this.slideshow && this.slideshow.retrieve('thumbnails'))
                        this.slideshow.retrieve('thumbnails').fireEvent('hide');
                }
            }).delay(3000, this);
                
        }
    },

/**
Constructor: initialize
    Creates an instance of the Slideshow class.
    
Arguments:
    element - (element) The wrapper element.
    data - (array or object) The images and optional thumbnails, captions and links for the show.
    options - (object) The options below.
    
Syntax:
    var myShow = new Slideshow(element, data, options);
*/

    initialize: function(el, data, options){    
        this.setOptions(options);
        this.startup = true;
        this.slideshow = $(el);
        if (!this.slideshow) 
            return;
        this.slideshow.set('styles', {'display': 'block', 'position': 'relative', 'z-index': this.options.thumbfade?15:0});
        var match = window.location.href.match(this.options.match);
        this.slide = (this.options.match && match) ? match[1].toInt() : this.options.slide;
        this.curslide = this.slide;
        this.counter = this.delay = this.transition = 0;
        this.direction = 'left';
        this.paused = false;
        this.shouldpause = false;
        this.fakepaused = false;
        this.dirFuncDone = false;
        this.hideTimer = null;
        this.lastMove = {x:-1, y:-1};
        if (!this.options.overlap)
            this.options.duration *= 2;
        var anchor = this.slideshow.getElement('a') || new Element('a');
        if (!this.options.href)
            this.options.href = anchor.get('href') || '';
        if (this.options.hu.length && !this.options.hu.test(/\/$/)) 
            this.options.hu += '/';
        if (this.options.fast === true)
            this.options.fast = 2;
            
        // styles
        
        var keys = ['slideshow', 'first', 'prev', 'play', 'pause', 'next', 'last', 'images', 'captions', 'controller', 'controller-extra3', 'thumbnails', 'thumbnails-extra', 'hidden', 'visible', 'inactive', 'active', 'loader', 'download', 'rename', 'trash', 'share'];
        var values = keys.map(function(key, i){
            return this.options.classes[i] || key;
        }, this);
        this.classes = values.associate(keys);
        this.classes.get = function(){
            var str = '.' + this.slideshow;
            for (var i = 0, l = arguments.length; i < l; i++)
                str += ('-' + this[arguments[i]]);
            return str;
        }.bind(this.classes);
            
        // data    
            
        if (!data){
            this.options.hu = '';
            data = {};
            var thumbnails = this.slideshow.getElements(this.classes.get(this.options.thumbclass) + ' img');
            this.slideshow.getElements(this.classes.get('images') + ' img').each(function(img, i){
                var src = img.get('src');
                var caption = $pick(img.get('alt'), img.get('title'), '');
                var parent = img.getParent();
                var properties = (parent.get('tag') == 'a') ? parent.getProperties : {};
                var href = img.getParent().get('href') || '';
                var thumbnail = (thumbnails[i]) ? thumbnails[i].get('src') : '';
                data[src] = {'caption': caption, 'href': href, 'thumbnail': thumbnail};
            });
        }
        var loaded = this.load(data);
        if (!loaded)
            return; 
        
        // events
        
        this.events = $H({'keydown': [], 'keyup': [], 'mousemove': [], 'mouseout': []});
        var keyup = function(e){
            if(!CE.CEU.$('CEUDialog_hide_div') && !CE.CEU.$('cerenamefield')) {
                switch(e.key){
                    case 'left': 
                        this.prev(e.shift); break;
                    case 'right': 
                        this.next(e.shift); break;
                    case 'p': 
                        this.pause(); break;
                }
            }
        }.bind(this);        
        this.events.keyup.push(keyup);
        document.addEvent('keyup', keyup);

        // required elements
            
        var el = this.slideshow.getElement(this.classes.get('images'));
        var images = (el) ? el.empty() : new Element('div', {'class': this.classes.get('images').substr(1)}).inject(this.slideshow);
        var div = images.getSize();
        this.height = this.options.height || div.y;        
        this.width = this.options.width || div.x;
        images.set({'styles': {'display': 'block', 'height': this.height, 'overflow': 'hidden', 'position': 'relative', 'width': this.width}});
        this.slideshow.store('images', images);

        this.fullimg = null;

        this.a = this.image = this.slideshow.getElement('img') || new Element('img');
        if (Browser.Engine.trident && Browser.Engine.version > 4)
            this.a.style.msInterpolationMode = 'bicubic';
        this.a.set('styles', {'display': 'none', 'position': 'absolute', 'zIndex': 1});
        this.b = this.a.clone();
        [this.a, this.b].each(function(img){
            anchor.clone().cloneEvents(anchor).grab(img).inject(images);
        });
        
        // optional elements
        
        if (this.options.captions)
             this._captions();
        if (this.options.controller)
            this._controller();
        if (this.options.loader)
             this._loader();


        this._preload();

        if (this.options.thumbnails)
            this._thumbnails.delay(500, this);
    },
    
/**
Public method: go
    Jump directly to a slide in the show.

Arguments:
    n - (integer) The index number of the image to jump to, 0 being the first image in the show.
    
Syntax:
    myShow.go(n);    
*/

    go: function(n, direction){
        if (!this.options.trueimgonly && ((this.slide - 1 + this.data.images.length) % this.data.images.length == n || $time() < this.transition))
            return;        
        $clear(this.timer);
        this.delay = 0;        
        this.direction = (direction) ? direction : ((n < this.slide) ? 'right' : 'left');
        this.slide = n;
        this.curslide = n;
        if (this.preloader) 
            this.preloader = this.preloader.destroy();
        this._preload(this.options.fast == 2 || (this.options.fast == 1 && this.paused));
        
        if(this.options.trueimgonly && !this.data.trueimg[this.curslide]) {
            var ctrlClass = 'controller';
            if(this.options.extracontrol)
                ctrlClass = 'controller-extra3';
            if(this.slideshow.retrieve(ctrlClass))
                this.slideshow.retrieve(ctrlClass).fireEvent('hide');
        }
    },

/**
Public methods: download, rename, trash, share
    Available if extracontrol specified
*/

    download: function(){
        var co = this.data.extraactions[this.curslide];
        if(co)
            co.onAction(co, 'download'); 
    },

    rename: function(){
        var co = this.data.extraactions[this.curslide];
        if(co)
            co.onAction(co, 'rename'); 
    },

    trash: function(){
        var co = this.data.extraactions[this.curslide];
        if(co)
            co.onAction(co, 'trash'); 
    },

    share: function(){
        var co = this.data.extraactions[this.curslide];
        if(co)
            co.onAction(co, 'share'); 
    },

/**
Public method: first
    Goes to the first image in the show.

Syntax:
    myShow.first();    
*/

    first: function(){
        this.prev(true); 
    },

/**
Public method: prev
    Goes to the previous image in the show.

Syntax:
    myShow.prev();    
*/

    prev: function(first){
        var n = 0;
        if (!first){
            if (this.options.random){
                
                // if it's a random show get the previous slide from the showed array

                if (this.showed.i < 2)
                    return;
                this.showed.i -= 2;
                n = this.showed.array[this.showed.i];
            }
            else if(this.options.trueimgonly){
                n = this.getPrevTrueImg(this.curslide);
            }
            else
                n = (this.slide - 2 + this.data.images.length) % this.data.images.length;                                    
        }
        if(first && this.options.trueimgonly) {
            n = this.getNextTrueImg(-1);
        }
        this.go(n, 'right');
    },

/**
Public method: pause
    Toggles play / pause state of the show.

Arguments:
    p - (undefined, 1 or 0) Call pause with no arguments to toggle the pause state. Call pause(1) to force pause, or pause(0) to force play.

Syntax:
    myShow.pause(p);    
*/

    pause: function(p, faked){
        if(faked && !this.fakepaused)
            return; // slideshow stopped
        
        if ($chk(p))
            this.paused = (p) ? false : true;
        if (this.paused){
            this.paused = false;
            this.fakepaused = false;
            this.delay = this.transition = 0;
            this.timer = this._preload.delay(100, this);
            [this.a, this.b].each(function(img){
                ['morph', 'tween'].each(function(p){
                    //if (this.retrieve(p)) this.get(p).resume();
                }, img);
            });
            if (this.options.controller)
                this.slideshow.getElement('.' + this.classes.pause).removeClass(this.classes.play);
        } 
        else {
            this.paused = true;
            this.delay = Number.MAX_VALUE;
            this.transition = 0;
            $clear(this.timer);
            [this.a, this.b].each(function(img){
                ['morph', 'tween'].each(function(p){
                    //if (this.retrieve(p)) this.get(p).pause();
                }, img);
            });
            if (this.options.controller && !this.fakepaused) {
                var ctpause = this.slideshow.getElement('.' + this.classes.pause);
                if(ctpause)
                    ctpause.addClass(this.classes.play);
            }
        }
    },
    
/**
Public method: next
    Goes to the next image in the show.

Syntax:
    myShow.next();    
*/

    next: function(last){
        var n = this.slide;
        if(last) {
            if(this.options.trueimgonly) {
                n = this.getPrevTrueImg(this.data.images.length);
            } else {
                n = this.data.images.length - 1;
            }
        }
        this.go(n, 'left');
    },

/**
Public method: last
    Goes to the last image in the show.

Syntax:
    myShow.last();    
*/

    last: function(){
        this.next(true); 
    },

/**
Public method: load
    Loads a new data set into the show: will stop the current show, rewind and rebuild thumbnails if applicable.

Arguments:
    data - (array or object) The images and optional thumbnails, captions and links for the show.

Syntax:
    myShow.load(data);
*/

    load: function(data){
        this.firstrun = true;
        this.showed = {'array': [], 'i': 0};
        if ($type(data) == 'array'){
            this.options.captions = false;            
            data = new Array(data.length).associate(data.map(function(image, i){ return image + '?' + i })); 
        }
        this.data = {'images': [], 'captions': [], 'hrefs': [], 'thumbnails': [], 'extraactions': [], 'hasshare': [], 'hasdownload': [], 'hasedit': [], 'hasrename': [], 'dirfuncs': [], 'extraicons': [], 'fullres': [], 'trueimg': [], 'thumbnailFolder': [], 'thumbnailShare': []};
        for (var image in data){
            var obj = data[image] || {};
            var caption = (obj.caption) ? obj.caption.trim() : '';
            var href = (obj.href) ? obj.href.trim() : ((this.options.linked) ? this.options.hu + image : this.options.href);
            var thumbnail = (obj.thumbnail) ? obj.thumbnail.trim() : image.replace(this.options.replace[0], this.options.replace[1]);
            var extraAction = (obj.extraaction) ? obj.extraaction : null;
            this.data.images.push(image);
            this.data.captions.push(caption);
            this.data.hrefs.push(href);
            this.data.thumbnails.push(thumbnail);
            this.data.extraactions.push(extraAction);
            this.data.hasshare.push(obj.hasshare);
            this.data.hasdownload.push(obj.hasdownload);
            this.data.hasedit.push(obj.hasedit);
            this.data.hasrename.push(obj.hasrename);
            this.data.dirfuncs.push(obj.dirfunc);
            this.data.extraicons.push(obj.extraicon);
            this.data.fullres.push(obj.fullres);
            this.data.trueimg.push(obj.trueimg);
            this.data.thumbnailFolder.push(obj.thumbnailFolder);
            this.data.thumbnailShare.push(obj.thumbnailShare);
        }
        if(this.options.random) {
            this.slide = $random(0, this.data.images.length - 1);
        } else if(this.options.trueimgonly) {
            this.slide = this.getNextTrueImg(this.options.slide-1);
        }
        
        // only run when data is loaded dynamically into an existing slideshow instance
        
        if (this.options.thumbnails && this.slideshow.retrieve('thumbnails'))
            this._thumbnails();
        if (this.slideshow.retrieve('images')){
            [this.a, this.b].each(function(img){
                ['morph', 'tween'].each(function(p){
                    if (this.retrieve(p)) this.get(p).cancel();
                }, img);
            });
            this.slide = this.transition = 0;
            this.curslide = 0;
            this.go(0);        
        }
        return this.data.images.length;
    },
    
/**
Public method: destroy
    Destroys a Slideshow instance.

Arguments:
    p - (string) The images and optional thumbnails, captions and links for the show.

Syntax:
    myShow.destroy(p);
*/

    destroy: function(p){
        this.events.each(function(array, e){
            array.each(function(fn){ document.removeEvent(e, fn); });
        });
        this.pause(1);
        if (this.options.loader && this.slideshow.retrieve('loader'))
            $clear(this.slideshow.retrieve('loader').retrieve('timer'));        
        if (this.options.thumbnails && this.slideshow.retrieve('thumbnails'))
            $clear(this.slideshow.retrieve('thumbnails').retrieve('timer'));
        this.slideshow.uid = Native.UID++;
        if (p)
            this.slideshow[p]();
    },
    
/**
Private method: preload
    Preloads the next slide in the show, once loaded triggers the show, updates captions, thumbnails, etc.
*/

    _preload: function(fast){
        if (!this.preloader)
             this.preloader = new Asset.image(this.options.hu + this.data.images[this.slide], {'onload': function(){
                this.store('loaded', true);
            }});    
        if (this.preloader.retrieve('loaded') && $time() > this.delay && $time() > this.transition){
            if (this.stopped){
                if (this.options.captions)
                    this.slideshow.retrieve('captions').get('morph').cancel().start(this.classes.get('captions', 'hidden'));
                this.pause(1);
                if (this.end)
                    this.fireEvent('end');
                this.stopped = this.end = false;
                return;                
            }                    
            this.image = (this.counter % 2) ? this.b : this.a;
            this.image.set('styles', {'display': 'block', 'height': 'auto', 'visibility': 'hidden', 'width': 'auto', 'zIndex': this.counter});
            ['src', 'height', 'width'].each(function(prop){
                this.image.set(prop, this.preloader.get(prop));
            }, this);
            this._resize(this.image);
            this._center(this.image);
            var anchor = this.image.getParent();
            
            if (anchor && this.data.hrefs[this.slide]) {
                anchor.set('href', this.data.hrefs[this.slide]);            
            } else if (anchor && this.data.dirfuncs[this.slide]) {
                anchor.set('events', {'click': (function(f) {
                                                    if(!this.dirFuncDone) {
                                                        this.dirFuncDone = true;
                                                        f(this.data.extraactions[this.curslide]);
                                                    }
                                               }).pass(this.data.dirfuncs[this.slide],this) });
                anchor.style.cursor = 'pointer';
            } else if (anchor) {
                anchor.erase('href');
                anchor.erase('events');
                anchor.style.cursor = 'auto';
            }

            var text = (this.data.captions[this.slide])
                ? this.data.captions[this.slide].replace(/<.+?>/gm, '').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, "'") 
                : '';
            this.image.set('alt', text);        
            if (anchor && this.options.titles)
                anchor.set('title', text);
            if (this.options.loader)
                this.slideshow.retrieve('loader').fireEvent('hide');
            if (this.options.captions)
                this.slideshow.retrieve('captions').fireEvent('update', fast);                
            this._show(fast);
            this._loaded();
            if (this.options.thumbnails)
                if(this.slideshow.retrieve('thumbnails'))
                    this.slideshow.retrieve('thumbnails').fireEvent('update', fast);
                else (function(fast) {
                    if(this.slideshow.retrieve('thumbnails'))
                        this.slideshow.retrieve('thumbnails').fireEvent('update', fast);
                }).delay(650, this, fast);
        } 
        else {
            if ($time() > this.delay && this.options.loader)
                this.slideshow.retrieve('loader').fireEvent('show');
            this.timer = (this.paused && this.preloader.retrieve('loaded')) ? null : this._preload.delay(100, this, fast); 
        }
    },
    
/**
Private method: show
    Does the slideshow effect.
*/

    _show: function(fast){
        if (!this.image.retrieve('morph')){
            var options = (this.options.overlap) ? {'duration': this.options.duration, 'link': 'cancel'} : {'duration': this.options.duration / 2, 'link': 'chain'};
            $$(this.a, this.b).set('morph', $merge(options, {'onStart': this._start.bind(this), 'onComplete': this._complete.bind(this), 'transition': this.options.transition}));
        }
        var hidden = this.classes.get('images', ((this.direction == 'left') ? 'next' : 'prev'));
        var visible = this.classes.get('images', 'visible');
        var img = (this.counter % 2) ? this.a : this.b;
        if (fast){
            img.get('morph').cancel().set(hidden);
            this.image.get('morph').cancel().set(visible);             
            if(this.data.fullres[this.slide])
                this.fullimg = new Asset.image(this.data.fullres[this.slide], {'onload': function(){this._fullimg_loaded();}.bind(this)});
            else
                this.fullimg = null;
        } 
        else {
            if (this.options.overlap){
                img.get('morph').set(visible);
                this.image.get('morph').set(hidden).start(visible);
            } 
            else    {
                var fn = function(hidden, visible){
                    if(this.startup) {
                        this.image.get('morph').start(visible);
                        this.startup = false;
                    } else {
                        var fullFn = function() {
                            if(this.data.fullres[this.curslide])
                                this.fullimg = new Asset.image(this.data.fullres[this.curslide], {'onload': function(){this._fullimg_loaded();}.bind(this)});
                            else
                                this.fullimg = null;
                        }.bind(this);
                        if(this.image.src.indexOf('blank.gif') != -1) {
                            this.image.get('morph').set(hidden);
                        } else {
                            this.image.get('morph').set(hidden).start(visible).chain(fullFn);
                        }
                        if(this.shouldpause) {
                            this.shouldpause = false;
                            if(!this.paused) {
                                this.fakepaused = true;
                                this.pause();
                            }
                        }
                    }
                }.pass([hidden, visible], this);
                hidden = this.classes.get('images', ((this.direction == 'left') ? 'prev' : 'next'));
                
                if(img.src.indexOf('blank.gif') != -1) {
                    img.get('morph').set(hidden);
                    fn(hidden, visible);
                } else {
                    img.get('morph').set(visible).start(hidden).chain(fn);
                }
            }
        }
    },
    
    _fullimg_loaded: function(){
        if(this.fullimg && this.data.fullres[this.curslide] && this.fullimg.src.indexOf(this.data.fullres[this.curslide]) != -1) {
            this.image.src = this.fullimg.src;
            this.fullimg = null;
        }
    },
    
/**
Private method: loaded
    Run after the current image has been loaded, sets up the next image to be shown.
*/

    _loaded: function(){
        this.curslide = this.slide;
        
        var controllerCaption = document.getElementById('slideshowfilename');
        if(controllerCaption) {
            controllerCaption.innerHTML = '';
            var tn = document.createTextNode(this.data.captions[this.slide]);
            controllerCaption.appendChild(tn);
        }
        
        var slideFlv = CE.CEU.$('slide_flv');
        if(slideFlv) {
            CE.rac(slideFlv);
            slideFlv.parentNode.removeChild(slideFlv);
        }
        var slideExtra = CE.CEU.$('slideshow_extra_div');
        if(slideExtra) {
            CE.rac(slideExtra);
            slideExtra.parentNode.removeChild(slideExtra);
        }
        var extraDiv = document.getElementById('slideshow_extra_div');
        if(extraDiv) {
            this.slideshow.retrieve('images').removeChild(extraDiv);
        }
        if(this.data.extraactions && this.data.extraactions[this.slide]) {
            if(this.data.extraactions[this.slide].onDisplay) {
                var startPaused = (this.firstrun && this.options.paused);
                var isRunning   = (!this.paused && (!this.firstrun || !this.options.paused));
                this.data.extraactions[this.slide].onDisplay(this.slideshow.retrieve('images'), this.data.extraactions[this.slide].file, isRunning?this:null, this.data.extraicons[this.slide], startPaused);
                if(isRunning)
                    this.shouldpause = true;
            } else if(this.data.dirfuncs[this.slide] && !this.dirFuncDone && !this.firstrun) {
                this.dirFuncDone = true;
                this.data.dirfuncs[this.slide](this.data.extraactions[this.slide]);
            }
        }
        
        this.counter++;
        this.delay = (this.paused) ? Number.MAX_VALUE : $time() + this.options.duration + this.options.delay;
        this.direction = 'left';
        this.transition = (this.options.fast == 2 || (this.options.fast == 1 && this.paused)) ? 0 : $time() + this.options.duration;            
        if (this.slide + 1 == this.data.images.length && !this.options.loop && !this.options.random)
            this.stopped = this.end = true;
        if (this.options.trueimgonly){
            var lastTrueImg = this.data.images.length - 1;
            for(var i = this.data.trueimg.length-1; i >= 0; --i) {
                if(this.data.trueimg[i]) {
                    lastTrueImg = i;
                    break;
                }
            }
            if (this.slide == lastTrueImg && !this.options.loop)
                this.stopped = this.end = true;
            
            this.slide = this.getNextTrueImg(this.slide);
        }
        else if (this.options.random){
            this.showed.i++;
            if (this.showed.i >= this.showed.array.length){
                var n = this.slide;
                if (this.showed.array.getLast() != n) this.showed.array.push(n);
                while (this.slide == n)
                    this.slide = $random(0, this.data.images.length - 1);                
            }
            else
                this.slide = this.showed.array[this.showed.i];
        }
        else
            this.slide = (this.slide + 1) % this.data.images.length;
        if (this.image.getStyle('visibility') != 'visible')
            (function(){ this.image.setStyle('visibility', 'visible'); }).delay(1, this);            
        if (this.preloader) 
            this.preloader = this.preloader.destroy();
        this._preload();
        
        (function() {
            if(this.shouldpause) {
                this.shouldpause = false;
                if(!this.paused) {
                    this.fakepaused = true;
                    this.pause();
                }
            }
        }).delay(1000, this);
    },

/**
Private method: center
    Center an image.
*/

    _center: function(img){
        if (this.options.center){
            var size = img.getSize();
            img.set('styles', {'left': (size.x - this.width) / -2, 'top': (size.y - this.height) / -2});
        }
    },

/**
Private method: resize
    Resizes an image.
*/

    _resize: function(img){
        if (this.options.resize){
            var h = this.preloader.get('height'), w = this.preloader.get('width');
            var dh = this.height / h, dw = this.width / w, d;
            if (this.options.resize == 'length')
                d = (dh > dw) ? dw : dh;
            else
                d = (dh > dw) ? dh : dw;
            
            if(h == 48 && w == 48) {
                d /= 2;
            }
            
            if(img && img.src && img.src.indexOf('blank.gif') != -1) {
                d *= 0.001;
            }
            
            img.set('styles', {height: Math.ceil(h * d), width: Math.ceil(w * d)});
        }    
    },

/**
Private method: start
    Callback on start of slide change.
*/

    _start: function(){        
        this.fireEvent('start');
    },

/**
Private method: complete
    Callback on start of slide change.
*/

    _complete: function(){
        if (this.firstrun && this.options.paused){
            this.firstrun = false;
            this.pause(1);
        }
        this.fireEvent('complete');
    },

/**
Private method: captions
    Builds the optional caption element, adds interactivity.
    This method can safely be removed if the captions option is not enabled.
*/

    _captions: function(){
         if (this.options.captions === true) 
             this.options.captions = {};
        var el = this.slideshow.getElement(this.classes.get('captions'));
        var captions = (el) ? el.empty() : new Element('div', {'class': this.classes.get('captions').substr(1)}).inject(this.slideshow);
        captions.set({
            'events': {
                'update': function(fast){    
                    var captions = this.slideshow.retrieve('captions');
                    var empty = (this.data.captions[this.slide] === '');
                    if (fast){
                        var p = (empty) ? 'hidden' : 'visible';
                        captions.set('html', this.data.captions[this.slide]).get('morph').cancel().set(this.classes.get('captions', p));
                    }
                    else {
                        var fn = (empty) ? $empty : function(n){
                            this.slideshow.retrieve('captions').set('html', this.data.captions[n]).morph(this.classes.get('captions', 'visible'))
                        }.pass(this.slide, this);        
                        captions.get('morph').cancel().start(this.classes.get('captions', 'hidden')).chain(fn);
                    }
                }.bind(this)
            },
            'morph': $merge(this.options.captions, {'link': 'chain'})
        });
        this.slideshow.store('captions', captions);
    },

/**
Private method: controller
    Builds the optional controller element, adds interactivity.
    This method can safely be removed if the controller option is not enabled.
*/

    _controller: function(){
        var ctrlClass = 'controller';
        if(this.options.extracontrol)
            ctrlClass = 'controller-extra3';
         if (this.options.controller === true)
             this.options.controller = {};
        var el = this.slideshow.getElement(this.classes.get(ctrlClass));
        var controller = (el) ? el.empty() : new Element('div', {'class': this.classes.get(ctrlClass).substr(1)}).inject(this.slideshow);
        if(this.options.hidecontrols) {
            controller.style.width = '0px';
            controller.style.height = '0px';
        }
        var ul = new Element('ul').inject(controller);
        var controls = {'first': CE.STRTAB.lookup("slideshow.first.key"),
                        'prev':  CE.STRTAB.lookup("slideshow.prev.key"),
                        'pause': CE.STRTAB.lookup("slideshow.pause.key"),
                        'next':  CE.STRTAB.lookup("slideshow.next.key"),
                        'last':  CE.STRTAB.lookup("slideshow.last.key")};
        /*
        if(this.options.extracontrol){
            controls['download'] = '';
            controls['rename'] = '';
            controls['trash'] = '';
            controls['share'] = '';
        }
        */
        
        $H(controls).each(function(accesskey, action){
            var li = new Element('li', {
                'class': (action == 'pause' && this.options.paused) ? this.classes.play + ' ' + this.classes[action] : this.classes[action]
            }).inject(ul);
            var a = this.slideshow.retrieve(action, new Element('a', {
                'title': ((action == 'pause') ? CE.STRTAB.lookup("slideshow.start") : '') + CE.STRTAB.lookup("slideshow."+action) + ((accesskey.length>0)?' [' + accesskey + ']':'')
            }).inject(li));
            a.set('events', {
                'click': function(action){
                    if(action == 'pause' && this.fakepaused) {
                        this.fakepaused = false;
                        var ctpause = this.slideshow.getElement('.' + this.classes.pause);
                        if(ctpause)
                            ctpause.addClass(this.classes.play);
                    } else {
                        this[action]();
                    }
                }.pass(action, this),
                'mouseenter': function(active){this.addClass(active);}.pass(this.classes.active, a),
                'mouseleave': function(active){this.removeClass(active);}.pass(this.classes.active, a)
            });
        }, this);
        /*
        if(this.options.extracontrol) {
            var filenameDisp = new Element('div', {'id': 'slideshowfilename', 'class': 'slideshowfilename'}).inject(controller);
        }
        */
        controller.set({
            'events': {
                'hide': function(hidden, thumbfade, slideshow){  
                    if (!this.retrieve('hidden')) {
                        this.store('hidden', true).morph(hidden);
                        if(thumbfade)
                            slideshow.setStyle('z-index',15);
                    }
                }.pass([this.classes.get(ctrlClass,'hidden'),this.options.thumbfade,this.slideshow], controller),
                'show': function(visible, thumbfade, slideshow, that){
                    if (this.retrieve('hidden')) {
                        if(!that.options.trueimgonly || that.data.trueimg[that.curslide])
                            this.store('hidden', false).morph(visible);
                        if(thumbfade)
                            slideshow.setStyle('z-index',0);
                    }
                }.pass([this.classes.get(ctrlClass,'visible'),this.options.thumbfade,this.slideshow,this], controller)
            },
            'morph': $merge(this.options.controller, {'link': 'cancel'})
        }).store('hidden', false);
        var keydown = function(e){
            if(!CE.CEU.$('CEUDialog_hide_div') && !CE.CEU.$('cerenamefield')) {
                if (['left', 'right', 'p'].contains(e.key)){
                    var controller = this.slideshow.retrieve(ctrlClass);
                    if (controller.retrieve('hidden'))
                        controller.get('morph').set(this.classes.get(ctrlClass, 'visible'));             
                    switch(e.key){
                        case 'left': 
                            this.slideshow.retrieve((e.shift) ? 'first' : 'prev').fireEvent('mouseenter'); break;
                        case 'right':
                            this.slideshow.retrieve((e.shift) ? 'last' : 'next').fireEvent('mouseenter'); break;
                        default:
                            this.slideshow.retrieve('pause').fireEvent('mouseenter'); break;
                    }
                }
            }
        }.bind(this);
        this.events.keydown.push(keydown);
        var keyup = function(e){
            if(!CE.CEU.$('CEUDialog_hide_div') && !CE.CEU.$('cerenamefield')) {
                if (['left', 'right', 'p'].contains(e.key)){
                    var controller = this.slideshow.retrieve(ctrlClass);
                    if (controller.retrieve('hidden'))
                        controller.store('hidden', false).fireEvent('hide'); 
                    switch(e.key){
                        case 'left': 
                            this.slideshow.retrieve((e.shift) ? 'first' : 'prev').fireEvent('mouseleave'); break;
                        case 'right': 
                            this.slideshow.retrieve((e.shift) ? 'last' : 'next').fireEvent('mouseleave'); break;
                        default:
                            this.slideshow.retrieve('pause').fireEvent('mouseleave'); break;
                    }
                }
            }
        }.bind(this);
        this.events.keyup.push(keyup);
        var mousemove = function(e){
            if(!document.getElementById('CEUDialog_hide_div')) {
                var lastMoveX = this.lastMove.x;
                var lastMoveY = this.lastMove.y;
                this.lastMove.x = e.page.x;
                this.lastMove.y = e.page.y;
                if((lastMoveX == -1 && lastMoveY == -1) || (e.page.x == lastMoveX && e.page.y == lastMoveY))
                    return;
                if(this.options.thumbfade && this.hideTimer) {
                    $clear(this.hideTimer);
                    this.hideTimer = null;
                }
                var img    = (this.counter % 2) ? this.a : this.b;
                var images = this.slideshow.retrieve('images').getCoordinates();
                var edgeLeft   = images.left;
                var edgeRight  = images.right;
                var edgeTop    = images.top;
                var edgeBottom = images.bottom;
                if(img && !this.options.thumbfade && (!this.data.extraactions[this.curslide] || !this.data.extraactions[this.curslide].onDisplay)) {
                    edgeLeft   += img.offsetLeft;
                    edgeRight  -= img.offsetLeft;
                    edgeTop    += img.offsetTop;
                    edgeBottom -= img.offsetTop;
                }
                var botExtra = 0;
                if(img && img.src.indexOf('blank.gif') != -1)
                    botExtra = 49;
                
                if (e.page.x > edgeLeft && e.page.x < edgeRight && e.page.y > edgeTop && e.page.y < (edgeBottom-botExtra)) {
                    if(this.data.hasshare[this.curslide] && this.data.hasdownload[this.curslide] && this.slideshow.retrieve('share')) {
                        this.slideshow.retrieve('download').style.left = '52px';
                        this.slideshow.retrieve('rename').style.left = '89px';
                        this.slideshow.retrieve('trash').style.left = '126px';
                        this.slideshow.retrieve('share').style.left = '163px';
                        this.slideshow.retrieve('share').style.display = 'block';
                    } else if(this.data.hasdownload[this.curslide] && this.slideshow.retrieve('share')) {
                        this.slideshow.retrieve('download').style.left = '68px';
                        this.slideshow.retrieve('rename').style.left = '108px';
                        this.slideshow.retrieve('trash').style.left = '145px';
                        this.slideshow.retrieve('share').style.display = 'none';
                    } else if(this.slideshow.retrieve('share')) {
                        this.slideshow.retrieve('download').style.display = 'none';
                        this.slideshow.retrieve('rename').style.left = '68px';
                        this.slideshow.retrieve('trash').style.left = '108px';
                        this.slideshow.retrieve('share').style.left = '145px';
                        this.slideshow.retrieve('share').style.display = 'block';
                    }
                    this.slideshow.retrieve(ctrlClass).fireEvent('show');
                    if (this.options.thumbnails && this.options.thumbfade && this.slideshow.retrieve('thumbnails'))
                        this.slideshow.retrieve('thumbnails').fireEvent('show');
                    if(this.options.thumbfade && this.hideTimer == null) {
                        this.hideTimer = (function(){
                            this.hideTimer = null;
                            if(this.slideshow && this.slideshow.retrieve(ctrlClass)) {
                                this.slideshow.retrieve(ctrlClass).fireEvent('hide');
                                if (this.options && this.options.thumbnails && this.options.thumbfade && this.slideshow && this.slideshow.retrieve('thumbnails'))
                                    this.slideshow.retrieve('thumbnails').fireEvent('hide');
                            }
                        }).delay(3000, this);
                            
                    }
                } else {
                    this.slideshow.retrieve(ctrlClass).fireEvent('hide');
                    if (this.options.thumbnails && this.options.thumbfade && this.slideshow.retrieve('thumbnails'))
                        this.slideshow.retrieve('thumbnails').fireEvent('hide');
                }
            }
        }.bind(this);
        this.events.mousemove.push(mousemove);
        /*
        var mouseout = function(e){
            this.slideshow.retrieve(ctrlClass).fireEvent('hide');
            if (this.options.thumbnails && this.options.thumbfade && this.slideshow.retrieve('thumbnails'))
                this.slideshow.retrieve('thumbnails').fireEvent('hide');
        }.bind(this);*/
        this.events.mouseout.push(mousemove);
        document.addEvents({'keydown': keydown, 'keyup': keyup, 'mousemove': mousemove, 'mouseout' : mousemove});
        this.slideshow.retrieve(ctrlClass, controller).fireEvent('hide');
    },

/**
Private method: loader
    Builds the optional loader element, adds interactivity.
    This method can safely be removed if the loader option is not enabled.
*/

    _loader: function(){
         if (this.options.loader === true) 
             this.options.loader = {};
        var loader = new Element('div', {
            'class': this.classes.get('loader').substr(1),                
            'morph': $merge(this.options.loader, {'link': 'cancel'})
        }).store('hidden', false).store('i', 1).inject(this.slideshow.retrieve('images'));
        if (this.options.loader.animate){
            for (var i = 0; i < this.options.loader.animate[1]; i++)
                img = new Asset.image(this.options.loader.animate[0].replace(/#/, i));
            if (Browser.Engine.trident4 && this.options.loader.animate[0].contains('png'))
                loader.setStyle('backgroundImage', 'none');                    
        }
        loader.set('events', {
            'animate': function(){  
                var loader = this.slideshow.retrieve('loader');                
                var i = (loader.retrieve('i').toInt() + 1) % this.options.loader.animate[1];
                loader.store('i', i);
                var img = this.options.loader.animate[0].replace(/#/, i);
                if (Browser.Engine.trident4 && this.options.loader.animate[0].contains('png'))
                    loader.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + img + '", sizingMethod="scale")';
                else 
                    loader.setStyle('backgroundImage', 'url(' + img + ')');
            }.bind(this),
            'hide': function(){  
                var loader = this.slideshow.retrieve('loader');
                if (!loader.retrieve('hidden')){
                    loader.store('hidden', true).morph(this.classes.get('loader', 'hidden'));
                    if (this.options.loader.animate)
                        $clear(loader.retrieve('timer'));                    
                }
            }.bind(this),
            'show': function(){  
                var loader = this.slideshow.retrieve('loader');
                if (loader.retrieve('hidden')){
                    loader.store('hidden', false).morph(this.classes.get('loader', 'visible'));
                    if (this.options.loader.animate)
                        loader.store('timer', function(){this.fireEvent('animate');}.periodical(50, loader));
                }
            }.bind(this)
        });
        this.slideshow.retrieve('loader', loader).fireEvent('hide');
    },
    
/**
Private method: thumbnails
    Builds the optional thumbnails element, adds interactivity.
    This method can safely be removed if the thumbnails option is not enabled.
*/

    _thumbnails: function(){
         if (this.options.thumbnails === true) 
             this.options.thumbnails = {}; 
        var el = this.slideshow.getElement(this.classes.get(this.options.thumbclass));
        var thumbnails = (el) ? el.empty() : new Element('div', {'class': this.classes.get(this.options.thumbclass).substr(1)}).inject(this.slideshow);
        thumbnails.setStyle('overflow', 'hidden');
        thumbnails.setStyles(this.options.thumbpos);
        if(this.options.thumbfade)
            thumbnails.store('hidden', true).get('morph').set(this.classes.get(this.options.thumbclass,'hidden'));  // start hidden
        var ul = new Element('ul', {'tween': {'link': 'cancel'}}).inject(thumbnails);
        var weakTrash = ((CE.CEUI.isSharedFoldersListing() && !CE.CEUI.isSlideAlbListing()) || CE.CEUI.g_isSlideAlb);
        this.data.thumbnails.each(function(thumbnail, i){
            var li = new Element('li', {
                'events': {
                    'mouseenter': function(ul, i){
                        if(this.options.thumbclass == 'thumbnails-extra') {
                            var li = ul.getElements('li')[i];
                            var actionsDiv = li.getElement('div');
                            if(actionsDiv) {
                                actionsDiv.style.display = 'block';
                            }
                        }
                    }.bind(this).pass([ul, i]),
                    'mouseleave': function(ul, i){
                        if(this.options.thumbclass == 'thumbnails-extra') {
                            var li = ul.getElements('li')[i];
                            var actionsDiv = li.getElement('div');
                            if(actionsDiv) {
                                actionsDiv.style.display = 'none';
                            }
                        }
                    }.bind(this).pass([ul, i])
                }
            }).inject(ul);
            var a = new Element('a', {'class':'main',
                'events': {
                    'click': function(i){
                        var isPlaying = this.fakepaused ? true : !this.paused;
                        if(this.fakepaused)
                            this.fakepaused = false;
                        if(!this.paused)
                            this.pause();
                        [this.a, this.b].each(function(img){
                            if (img.retrieve('morph')) img.get('morph').cancel();
                        });
                        
                        this.go(i); 

                        if(isPlaying)
                            this.pause();
                        return false; 
                    }.pass(i, this),
                    'loaded': function(a){
                        var img = a.getElement('img');
                        if(img && (!img.className || img.className.indexOf('folderpage') == -1)) {
                            if(this.options.thumbclass != 'thumbnails-extra') {
                                var h = img.height, w = img.width;
                                var dh = this.options.thumbsize / h, dw = this.options.thumbsize / w, d;
                                d = (dh > dw) ? dw : dh;
                                img.height = Math.ceil(h * d);
                                img.width = Math.ceil(w * d);
                            } else {
                                var h = img.height, w = img.width;
                                if(h == 48 && w == 48) {
                                    img.style.left = '16px';
                                    img.style.top  = '16px';
                                } else if(h == 54 && w == 54) {
                                    img.style.left = '13px';
                                    img.style.top  = '13px';
                                } else {
                                    var dh = 78 / h, dw = 78 / w, d;
                                    d = (dh > dw) ? dw : dh;
                                    img.height = Math.ceil(h * d);
                                    img.width = Math.ceil(w * d);
                                    if(h == w) {
                                        img.style.left = '1px';
                                        img.style.top  = '1px';
                                    } else {
                                        img.style.left = (40 - Math.ceil((w*d)/2)) + 'px';
                                        img.style.top  = (40 - Math.ceil((h*d)/2)) + 'px';
                                    }
                                }
                            }
                        }

                        this.data.thumbnails.pop();
                        if (!this.data.thumbnails.length){
                            var div = thumbnails.getCoordinates();
                            var props = thumbnails.retrieve('props');            
                            var limit = 0, pos = props[1], size = props[2];        
                            thumbnails.getElements('li').each(function(li){            
                                var li = li.getCoordinates();        
                                if (li[pos] > limit) limit = li[pos];
                            }, this);            
                            thumbnails.store('limit', div[size] + div[props[0]] - limit);
                        }
                    }.bind(this)
                },
                'href': this.options.hu + this.data.images[i],
                'morph': $merge(this.options.thumbnails, {'link': 'cancel'})
            }).inject(li);
            if(this.options.extracontrol) {
                var actionsDiv = new Element('div', {'class': 'itemactions-md'}).inject(li);
                
                var iconOffset = 2;
                if(this.data.hasdownload[i]) {
                    var aDl = new Element('a', {'title':CE.STRTAB.lookup("slideshow.download"), 'class':'slactionlink',
                        'events': {
                            'click': function(i){
                                if(this.data.extraactions[i])
                                    this.data.extraactions[i].onAction(this.data.extraactions[i], 'download'); 
                                return false; 
                            }.pass(i, this)
                        }
                    }).inject(actionsDiv);
                    var iconDl = new Element('img', {'src':CE.STRTAB.lookup("slideshow.dir")+'action-icon-download.png', 'style':'left:'+iconOffset+'px;', 'width':'16', 'height':'16'}).inject(aDl);
                    iconOffset += 20;
                }
                
                if(this.options.canedit && this.data.hasedit[i]) {
                    var hint   = CE.CEUI.g_isSlideAlb ? 'view.hint.removeslide' : 'slideshow.remove';
                    var aTrash = new Element('a', {'title':CE.STRTAB.lookup(hint), 'class':'slactionlink',
                        'events': {
                            'click': function(i){
                                if(this.data.extraactions[i])
                                    this.data.extraactions[i].onAction(this.data.extraactions[i], 'trash'); 
                                return false; 
                            }.pass(i, this)
                        }
                    }).inject(actionsDiv);
                    var iconFn    = weakTrash ? 'action-icon-trashshare.png' : 'action-icon-trash.png';
                    var iconTrash = new Element('img', {'src':CE.STRTAB.lookup("slideshow.dir")+iconFn, 'style':'left:'+iconOffset+'px;', 'width':'16', 'height':'16'}).inject(aTrash);
                    iconOffset += 20;
                }

                if(this.options.canshare && this.data.hasshare[i]) {
                    var aShare = new Element('a', {'title':CE.STRTAB.lookup("slideshow.share"), 'class':'slactionlink',
                        'events': {
                            'click': function(i){
                                if(this.data.extraactions[i])
                                    this.data.extraactions[i].onAction(this.data.extraactions[i], 'share'); 
                                return false; 
                            }.pass(i, this)
                        }
                    }).inject(actionsDiv);
                    var iconShare = new Element('img', {'src':CE.STRTAB.lookup("slideshow.dir")+'action-icon-share.png', 'style':'left:'+iconOffset+'px;', 'width':'16', 'height':'16'}).inject(aShare);
                    iconOffset += 20;
                }
                
                var labelDiv = new Element('div', {'class': 'label'}).inject(li);
                var tn  = document.createTextNode(this.data.captions[i]);
                var spn = labelDiv.appendChild(CE.dce('span'));
                spn.appendChild(tn);
                if(this.options.canedit && this.data.hasrename[i]) {
                    var renEvent = {onEvent:CE.CEUI.onRenameStart, 'file':this.data.extraactions[i].file, 'el':labelDiv};
                    CE.CEU.attachEvent(spn, 'click', renEvent);
                    if(CE.CEUI.g_newfolder == this.data.extraactions[i].file.name) {
                        renEvent.onEvent(renEvent); // trigger rename of new folder
                        CE.CEUI.g_newfolder = null;
                    }
                }
            }
            if (this.data.captions[i] && this.options.titles)
                a.set('title', this.data.captions[i].replace(/<.+?>/gm, '').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, "'"));
            var imgStyle = '';
            if(thumbnail.substr(thumbnail.length-6) == "?fixed")
                imgStyle = 'left:16px; top:16px;';
            if(this.data.thumbnailFolder[i]) {
                var img3 = new Element('img', {'class':'folderpage3', 'src':this.options.hu + thumbnail}).inject(a);
                var img2 = new Element('img', {'class':'folderpage2', 'src':this.options.hu + thumbnail}).inject(a);
                var img1 = new Asset.image(this.options.hu + thumbnail, { 'class': 'folderpage1',
                    'onload': function(){this.fireEvent('loaded',a);}.bind(a) 
                }).inject(a);
            } else {
                var img = new Asset.image(this.options.hu + thumbnail, {
                    'style':  imgStyle,
                    'onload': function(){this.fireEvent('loaded',a);}.bind(a) 
                }).inject(a);
            }
            if(this.data.thumbnailShare[i]) {
                var shareIco = new Element('img', {'class':'shareicon', 'src':this.data.thumbnailShare[i]}).inject(a);
            }
        }, this);
        thumbnails.set('events', {

            'hide': function(hidden){
                //CE.CEDBG.println('Slideshow:Thumbnails:Hide');
                if (!this.retrieve('hidden'))
                    this.store('hidden', true).morph(hidden);
            }.pass(this.classes.get(this.options.thumbclass,'hidden'), thumbnails),
            
            'show': function(visible){
                //CE.CEDBG.println('Slideshow:Thumbnails:Show');
                if (this.retrieve('hidden'))
                    this.store('hidden', false).morph(visible);
            }.pass(this.classes.get(this.options.thumbclass,'visible'), thumbnails),

            'scroll': function(n, fast){
                var div = this.getCoordinates();
                var ule = this.getElement('ul');
                if(!ule)
                    return;
                var ul = ule.getPosition();
                var props = this.retrieve('props');
                var axis = props[3], delta, pos = props[0], size = props[2], value;                
                var tween = ule.get('tween', {'property': pos});    
                if ($chk(n)){
                    var li = this.getElements('li')[n].getCoordinates();
                    delta = div[pos] + (div[size] / 2) - (li[size] / 2) - li[pos]    
                    value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
                    if (fast)    
                        tween.set(value);
                    else                         
                        tween.start(value);
                }
                else{
                    var area = div[props[2]] / 3, page = this.retrieve('page'), velocity = -0.2;            
                    if (page[axis] < (div[pos] + area))
                        delta = (page[axis] - div[pos] - area) * velocity;
                    else if (page[axis] > (div[pos] + div[size] - area))
                        delta = (page[axis] - div[pos] - div[size] + area) * velocity;            
                    if (delta){            
                        value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
                        tween.set(value);
                    }
                }                
            }.bind(thumbnails),
            'update': function(fast){
                var thumbnails = this.slideshow.retrieve('thumbnails');
                var inactcls   = 'inactive';
                var i = 0;
                thumbnails.getElements('a').each(function(a){
                    if(a.className.indexOf('slactionlink') == -1) {
                        if (i == this.curslide){
                            if (!a.retrieve('active', false)){
                                a.store('active', true);
                                var active = this.classes.get(this.options.thumbclass, 'active');                            
                                if (fast) a.get('morph').set(active);
                                else a.morph(active);
                            }
                        } 
                        else {
                            if (a.retrieve('active', true)){
                                a.store('active', false);
                                var inactive = this.classes.get(this.options.thumbclass, inactcls);                        
                                if (fast) a.get('morph').set(inactive);
                                else a.morph(inactive);
                            }
                        }
                        ++i;
                    }
                }, this);
                if (!thumbnails.retrieve('mouseover'))
                    thumbnails.fireEvent('scroll', [this.curslide, fast]);
            }.bind(this)
        }).store('hidden', false);
        var div = thumbnails.getCoordinates();
        thumbnails.store('props', (div.height > div.width) ? ['top', 'bottom', 'height', 'y'] : ['left', 'right', 'width', 'x']);
        var mousemove = function(e){
            if(!document.getElementById('CEUDialog_hide_div')) {
                var div = this.getCoordinates();
                if (e.client.x > div.left && e.client.x < div.right && e.client.y > div.top && e.client.y < div.bottom){
                    this.store('page', e.client);
                    if (!this.retrieve('mouseover')){
                        this.store('mouseover', true);
                        this.store('timer', function(){this.fireEvent('scroll');}.periodical(50, this));
                    }
                }
                else {
                    if (this.retrieve('mouseover')){
                        this.store('mouseover', false);                
                        $clear(this.retrieve('timer'));
                    }
                }
            }
        }.bind(thumbnails);
        this.events.mousemove.push(mousemove);
        document.addEvent('mousemove', mousemove);
        this.slideshow.store('thumbnails', thumbnails);
        if(this.options.thumbfade)
            this.slideshow.retrieve('thumbnails').fireEvent('hide');

        (function() {
            if(this && this.slideshow) {
                var thumbnails = this.slideshow.retrieve('thumbnails');
                var curLimit   = thumbnails ? thumbnails.retrieve('limit') : 0;
                
                if(thumbnails && (!curLimit || curLimit == 0)) {
                    var div = thumbnails.getCoordinates();
                    var props = thumbnails.retrieve('props');            
                    var limit = 0, pos = props[1], size = props[2];        
                    thumbnails.getElements('li').each(function(li){            
                        var li = li.getCoordinates();        
                        if (li[pos] > limit) limit = li[pos];
                    }, this);            
                    thumbnails.store('limit', div[size] + div[props[0]] - limit);
                }
            }
        }).delay(3000, this);
    }
});
