/*
** Photo Slider 1.0 08/08/07
**  Author: Jesse Janzer
**   jjanzer@lanthera.net http://jjanzer.subculture.org
**  Tutorial Site: http://opiefoto.com/articles/slider
**
** You may use this library for any purpose.
**
** If you find it useful feel free to give me credit and link to
**  the original tutorial site http://opiefoto.com/articles/slider
*/

var FOTO = { };
var SKEL = { };
SKEL.EFFECTS = { };

FOTO.Slider = {
    bucket: {}, //a hash containing our thumbnails & images
    imageCache: {}, //cache of the images so the preloaded images aren't overwritten in some browsers
    loadingURL: '/articles/assets/slider/spinner.gif',
    baseURL: '/Images/',
    thumbURL: 't_{ID}.jpg',
    mainURL: '{ID}.jpg',

    duration: 3000, //how long do we look at each image?

    data: {}, //contains things like current offset, paused, etc keyed off of the slider id

    //returns the URL for our thumbnails and large images
    getUrlFromId: function(key, id, isThumb) {

        //do we have this url in our bucket?
        if (this.bucket[key] != null && this.bucket[key][id] != null) {
            if (isThumb && this.bucket[key][id]['thumb'] != null) {
                return this.baseURL + this.bucket[key][id]['thumb'];
            } else if (!isThumb && this.bucket[key][id]['main'] != null) {
                return this.baseURL + this.bucket[key][id]['main'];
            }
        }

        //we don't have it stored, so generate it
        if (isThumb)
            return this.baseURL + id; // this.thumbURL.replace('{ID}', id);
        return this.baseURL + id;  //this.mainURL.replace('{ID}', id);
    },

    //returns the caption for the image
    getCaptionFromId: function(key, id) {
        if (this.bucket[key] != null && this.bucket[key][id] != null) {
            return this.bucket[key][id]['caption'];
        }
    },

    //ids is just an array
    importBucketFromIds: function(key, ids) {
        this.bucket[key] = new Object(); //replace any existing entries with this new set
        for (i in ids) {
            this.bucket[key][ids[i]] = new Object(); //there isn't any reason to pre-store the urls for this
            //this.bucket[i]['thumb'] = this.getUrlFromId(i,true);
            //this.bucket[i]['main'] = this.getUrlFromId(i,false);
        }
    },

    buildThumbBar: function(key, bar) {
        if (this.bucket[key] == null) {
            return false;
        }

        var slot = 0;

        for (i in this.bucket[key]) {
            var div = $(document.createElement('div'));
            div.attr('imageid', i);
            div.attr('slot', slot++);
            div.addClass('photoslider_thumb');

            var img = document.createElement('img');
            img.src = this.getUrlFromId(key, i, true);

            //attach the image to the div
            div.append(img);

            //attach the div to our thumbnail bar
            $(bar).append(div);

            //calc the width (needed for later)
            /*this.data[key]['thumbWidth'] =
            parseInt(div.css('width'))
            +parseInt(div.css('border-left-width'))
            +parseInt(div.css('border-right-width'))
            +parseInt(div.css('margin-left'))
            +parseInt(div.css('margin-right'))
            +parseInt(div.css('padding-left'))
            +parseInt(div.css('padding-right'));*/
        }

        //we need to add a clear since we have floating divs
        var clear = document.createElement('div');
        $(clear).addClass('photoslider_clear');

        //finally we need to force the width of the bar so that the divs don't wrap to the next line
        // we give it 1 extra slot just for buffer
        $(bar).css('width', ((slot + 1) * this.data[key]['thumbWidth']) + 'px')


        $(bar).append(clear);
    },

    //loads in the slideshow, replaces the existing one if set
    reload: function(key) {

        if (this.data[key] == null) {
            this.data[key] = new Object();
        }

        this.data[key]['thumbWidth'] = 122; //aca
        this.data[key]['paused'] = true;
        this.data[key]['currentSlot'] = 0;
        this.data[key]['currentId'] = null;

        var sliderDiv = $('#' + key);

        var sliderMain = $('#' + key + ' .photoslider_main').get(0);
        if (sliderMain != null) {
            $(sliderMain).remove();
        }

        sliderMain = $(document.createElement('div'));
        sliderMain.addClass('photoslider_main');

        //sliderMainImg = document.createElement('img');
        //sliderMain.append(sliderMainImg);

        sliderMainA = document.createElement('a');
        sliderMainImg = document.createElement('img');

        sliderMainA.appendChild(sliderMainImg);

        sliderMain.append(sliderMainA);

        //

        sliderDiv.append(sliderMain);

        var sliderCaption = $(document.createElement('div'));
        sliderCaption.addClass('photoslider_caption');

        sliderDiv.append(sliderCaption);

        var sliderNav = $('#' + key + ' .photoslider_nav').get(0);
        if (sliderNav != null) {
            //remove it
            $(sliderNav).remove();
        }

        sliderNav = $(document.createElement('div'));
        sliderNav.addClass('photoslider_nav');

        sliderDiv.append(sliderNav);

        thumbBar = $(document.createElement('div'));
        thumbBar.addClass('photoslider_thumbBar');

        //build the bar
        this.buildThumbBar(key, thumbBar);

        //now we need to attach our events
        $(thumbBar).children('.photoslider_thumb').each(function() {
            //what happens when we click on a thumbnail?
            $(this).click(function(ev) {
                FOTO.Slider.thumbClick(ev);
            });
        });

        //attach our thumb nail bar to our parent
        sliderNav.append(thumbBar);

        //build our play/stop buttons
        var sliderControl = $(document.createElement('div'));
        sliderControl.addClass('photoslider_control');

        var sliderPlay = $(document.createElement('div'));
        sliderPlay.addClass('photoslider_play');

        var sliderStop = $(document.createElement('div'));
        sliderStop.addClass('photoslider_stop');

        var clear = $(document.createElement('div'));
        clear.addClass('photoslider_clear');

        sliderControl.append(sliderPlay).append(sliderStop).append(clear);

        //bind our click events to the buttons
        $(sliderPlay).click(function() {
            if (FOTO.Slider.data[key]['paused']) {
                $(sliderPlay).addClass('slideshow_disabled');
                $(sliderStop).removeClass('slideshow_disabled');
                FOTO.Slider.play(key);
            }
        });

        $(sliderStop).click(function() {
            if (!FOTO.Slider.data[key]['paused']) {
                $(sliderStop).addClass('slideshow_disabled');
                $(sliderPlay).removeClass('slideshow_disabled');
            }
            FOTO.Slider.stop(key);
        });

        sliderDiv.append(sliderControl);


        //click our first element
        var firstThumb = $('#' + key + ' .photoslider_thumb[@slot=0]');
        firstThumb.click();
    },

    thumbClick: function(ev) {
        //find our main parent
        var thumb = null;


        if (ev.currentTarget) {
            thumb = $(ev.currentTarget);
        } else if (ev.srcElement) {
            //work around for IE's lack of currentTarget
            if ($(ev.srcElement).attr('src') == null) {
                //they clicked on the div
                thumb = $(ev.srcElement);
            } else {
                //they clicked on the img
                thumb = $(ev.srcElement).parent();
            }
        } else if (ev.target) {
            thumb = $(ev.target);
        }

        var id = thumb.attr('imageid');
        var bar = thumb.parent();
        var nav = bar.parent();
        var parent = nav.parent();
        var key = parent.attr('id');
        var slot = thumb.attr('slot');
        if (id == null) {
            id = 0;
        }
        if (slot == null) {
            slot = 0;
        }

        //window.alert('id '+id+' bar '+bar+' nav '+nav+' parent '+parent+' key '+key+' slot '+slot);

        if (id == this.data[key]['currentId']) {
            return false; //don't do anything since this is our current image
        }

        this.resetTimer(key);

        //now we have everything we need, let's load in the main image
        this.setMainImage(key, id);

        //if we already are animating stop
        if (this.data[key]['interval'])
            SKEL.EFFECTS.Slide.stopByIntervalId(this.data[key]['interval']);
        if (this.data[key]['intervalThumb'])
            SKEL.EFFECTS.Slide.stopByIntervalId(this.data[key]['intervalThumb']);

        //let's move our thumb into position
        if (this.data[key]['currentId'] != null) {
            //move the thumbnail back up   -   aca
            SKEL.EFFECTS.Slide.animate($('.photoslider_thumb[@imageid=' + this.data[key]['currentId'] + ']'), 'top', '0px', '0px', 500, SKEL.Transitions.quadOut);
            //NOTE: we don't want to clear this interval incase the user clicks really fast (unless we kept track of every animation)
        }

        this.data[key]['currentId'] = id;
        this.data[key]['currentSlot'] = slot;

        //animate our div down   -   aca
        this.data[key]['intervalThumb'] = SKEL.EFFECTS.Slide.animate(thumb, 'top', '0px', '0px', 250, SKEL.Transitions.quadOut);

        //where are we right now?
        var currentPos = this.findRelativePos(bar.get(0));
        var navWidth = parseInt($(nav).css('width'));
        var slots = Math.floor(navWidth / this.data[key]['thumbWidth']);

        //where do we need to be?
        //we want to position the clicked on div in the dead center

        //alternative method
        //var centerStart = (-this.data[key]['thumbWidth'] * slot) + ((this.data[key]['thumbWidth'] * (slots/2)) - (this.data[key]['thumbWidth']/2));

        var centerStart = (navWidth / 2) - ((+this.data[key]['thumbWidth'] * (slot)) + (this.data[key]['thumbWidth'] / 2));

        var barFrom = currentPos['x'] + 'px';
        var barTo = centerStart + 'px';

        //window.alert('thumb '+thumb+' key'+key+' from '+barFrom+' to '+barTo+ ' navWidth '+navWidth+' thumb '+this.data[key]['thumbWidth']+' slot '+slot+' center'+centerStart);

        //this.data[key]['interval'] = SKEL.EFFECTS.Slide.animate(bar, 'left', barFrom, barTo, 1000, SKEL.Transitions.backOut);   -- aca, movimiento slider   
        
    },

    //preloads the image for the main viewing area
    setMainImage: function(key, id) {
        var main = $('#' + key + ' .photoslider_main');
        var mainImg = $('#' + key + ' .photoslider_main img').get(0);

        //set the mainImg to the spinner
        //mainImg.src = this.loadingURL;

        //preload the image and on return set our image
        this.preload(this.getUrlFromId(key, id, false), FOTO.Slider.displayMainImage, { key: key, id: id });
    },

    displayMainImage: function(img) {
        var newSrc = ($(this).get())[0].src;

        var args = this.args;
        var key = args['key'];
        var id = args['id'];
        var main = $('#' + key + ' .photoslider_main');
        var mainImg = $('#' + key + ' .photoslider_main img').get(0);
        var caption = $('#' + key + ' .photoslider_caption');
        var captionTxt = FOTO.Slider.getCaptionFromId(key, id);


        var mainA = $('#' + key + ' .photoslider_main a').get(0);
        var URLTxt = FOTO.Slider.getURLFromId(key, id);
        mainA.href = URLTxt;
        

        if (captionTxt == null) {
            captionTxt = '&nbsp;'; //make it play nice in browsers like ie
        }

        caption.html(captionTxt);

        $(mainImg).fadeOut('slow', function() {
				$(this).attr('src', newSrc).fadeIn('slow');
			});
	

        //$(mainImg).attr('src', newSrc);
    },

    //returns the url for the image
    getURLFromId: function(key, id) {
        if (this.bucket[key] != null && this.bucket[key][id] != null) {
            return this.bucket[key][id]['url'];
        }
    },

    //preload an image and fire off a callback if needed
    preload: function(url, onLoadFunc, args) {
        var image = document.createElement('img');
        if (onLoadFunc) {
            image.onload = onLoadFunc;
        }

        if (args) {
            image.args = args;
        }

        image.src = url;
        this.imageCache[url] = image;
        return image;
    },

    enableSlideshow: function(key) {
        $('#' + key + ' .photoslider_control').css('display', 'block');
        this.data[key]['slideshow'] = true;
    },

    //loops through the images available and preloads them one at a time
    preloadImages: function(key) {
        //we've already started preloading "0" so start at "1"
        if (this.bucket[key] != null && this.bucket[key][1] != null) {
            this.preload(this.getUrlFromId(key, 1, false), FOTO.Slider.preloadImageChain, { key: key, slot: 1 });
        }
    },

    preloadImageChain: function() {
        var args = this.args;
        var key = args['key'];
        var slot = parseInt(args['slot']) + 1;
        if (FOTO.Slider.bucket[key] != null && FOTO.Slider.bucket[key][slot] != null) {
            FOTO.Slider.preload(FOTO.Slider.getUrlFromId(key, slot, false), FOTO.Slider.preloadImageChain, { key: key, slot: slot });
        }
    },

    //returns the absolute coords based on where it is on the page (works w/ scrolled content)
    findAbsolutePos: function(el) {
        var SL = 0, ST = 0;
        var is_div = /^div$/i.test(el.tagName);
        if (is_div && el.scrollLeft)
            SL = el.scrollLeft;
        if (is_div && el.scrollTop)
            ST = el.scrollTop;
        var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
        r.width = el.offsetWidth;
        r.height = el.offsetHeight;

        if (el.offsetParent) {
            var tmp = this.findAbsolutePos(el.offsetParent);
            r.x += tmp.x;
            r.y += tmp.y;
        }
        return r;
    },

    //this is just like the findAbsolutePos, but stops if a parent's css is "position:relative;"
    findRelativePos: function(el) {
        var SL = 0, ST = 0;
        var is_div = /^div$/i.test(el.tagName);
        if (is_div && el.scrollLeft)
            SL = el.scrollLeft;
        if (is_div && el.scrollTop)
            ST = el.scrollTop;
        var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
        r.width = el.offsetWidth;
        r.height = el.offsetHeight;

        if (el.offsetParent) {
            if ($(el.offsetParent).css('position') != 'relative') {
                //stop if we have a relative parent
                var tmp = this.findRelativePos(el.offsetParent);
                r.x += tmp.x;
                r.y += tmp.y;
            } else {
                r.x += 0;
                r.y += 0;
            }
        }
        return r;
    },

    cycleImage: function(key) {
        var slot = parseInt(parseInt(this.data[key]['currentSlot']) + 1); //force this to be a number

        var thumb = $('#' + key + ' .photoslider_thumb[@slot=' + slot + ']').get(0);
        if (thumb == null) {
            //perhaps we're at the end or don't have a valid slot, try slot 0
            thumb = $('#' + key + ' .photoslider_thumb[@slot=0]').get(0);
            if (thumb == null) {
                //there is no slot available, return
                this.data[key]['paused'] = true;
                return false;
            }
        }
        $(thumb).click();
    },

    play: function(key) {
        if (this.data[key]['paused']) {
            this.data[key]['intervalCycle'] = setInterval(function() { FOTO.Slider.cycleImage(key); }, FOTO.Slider.duration);
        }
        this.data[key]['paused'] = false;
    },

    stop: function(key) {
        this.data[key]['paused'] = true;
        if (this.data[key]['intervalCycle']) {
            clearInterval(this.data[key]['intervalCycle']);
        }
    },

    resetTimer: function(key) {
        if (!this.data[key]['paused'] && this.data[key]['intervalCycle']) {
            this.stop(key);
            this.play(key);
        }
    }

};


SKEL.Transitions = {

	/* Many of these functions come from Robert Penner and mootools
	**  http://www.robertpenner.com/easing/
	**  http://mootools.net
	**
	** For more methods check
	**  http://opiefoto.com/js/skel/transitions.js
	*/

	quadOut: function(t, b, c, d){
		return -c *(t/=d)*(t-2) + b;
	},

	backOut: function(t, b, c, d, s){
		if (!s) s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	}

};


SKEL.EFFECTS.Slide = {
    counter: 0,
    fps: 50,

    //handles the animation from an attribute to an attribute
    animate: function(element, cssAttribute, from, to, duration, transition) {

        if (element.css('display') != 'block') {
            element.skel_old_display = element.css('display');
        }        

        //if there isn't a default transition set one
        if (!transition) {
            transition = SKEL.Transitions.quadOut;
        }

        //cancel any current animation
        SKEL.EFFECTS.Slide.stop(element);

        var startTime = new Date().getTime();

        //IE doesn't support arguments, so make a function that explicitly calls with those arguments
        element.skel_animate_id = setInterval(function() {
            SKEL.EFFECTS.Slide.step(element, cssAttribute, from, to, duration, startTime, transition);
        }, (1000 / SKEL.EFFECTS.Slide.fps));

        return element.skel_animate_id;
    },

    //cancels any animation event
    stop: function(element) {
        //console.log(this,element,element.skel_animate_id);
        //console.log(element.skel_animate_id);
        if (element.skel_animate_id) {
            clearInterval(element.skel_animate_id);
            element.skel_animate_id = 0;
            if (element.skel_old_display) {
                element.css('display', element.skel_old_display);
            }
        }

    },

    //cancels any animation event
    stopByIntervalId: function(id) {
        if (id) {
            clearInterval(id);
        }
    },

    step: function(element, cssAttribute, from, to, duration, start, transition) {
        var curTime = new Date().getTime();

        if (cssAttribute == 'color' || cssAttribute == 'background-color') {
            from = this.hexToRgb(from);
            to = this.hexToRgb(to);
        } else {
            //what we use to finalize the unit
            var result = this.splitValue(from);
            var prefix = result.prefix;
            if (prefix == '-')
                prefix = '';
            var postfix = result.postfix;

            from = parseInt(from);
            to = parseInt(to);
        }

        //compute the new property
        var newValue = SKEL.EFFECTS.Slide.compute(curTime, from, to, duration, start, transition);

        var finished = false;

        if (curTime > (start + duration)) {
            finished = true;
        }
        if (cssAttribute == 'color' || cssAttribute == 'background-color') {
            newValue = this.rgbToHex(newValue);
        } else {
            newValue = prefix + Math.round(newValue) + postfix;
        }

        if (finished) {
            SKEL.EFFECTS.Slide.stop(element);
        }

        //window.alert('css: '+cssAttribute+' new:'+newValue+' element: '+element);
        element.css(cssAttribute, newValue);
    },

    //thanks to mootools and Robert Penner
    compute: function(time, from, to, duration, startTime, transitionFunc) {
        var deltaTime = time - startTime;
        if (time > (startTime + duration)) {
            //we're past our point, return max
            return to;
        } else {
            if (typeof (from) == 'object') {
                //if we have an object, compute all the transitions\
                var tmpObject = Array();
                from.forEach(function(value, index) {
                    newFrom = value;
                    newTo = to[index];
                    newValue = transitionFunc(deltaTime, newFrom, (newTo - newFrom), duration);
                    tmpObject[index] = Math.round(newValue);
                });
                return tmpObject;
            } else {
                return transitionFunc(deltaTime, from, (to - from), duration);
            }
        }
    },

    hexToRgb: function(str) {
        var hex = str.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
        if (hex) {
            if (hex[1] != '') {
                hex[1] = parseInt(hex[1], 16);
                hex[2] = parseInt(hex[2], 16);
                hex[3] = parseInt(hex[3], 16);
            }
        }

        return (hex) ? hex.slice(1) : false;
    },

    rgbToHex: function(rgb) {
        if (rgb.length < 3) return false;
        if (rgb[3] && (rgb[3] == 0) && !rgb) return 'transparent';
        var hex = [];
        for (var i = 0; i < 3; i++) {
            var bit = (rgb[i] - 0).toString(16);
            hex.push((bit.length == 1) ? '0' + bit : bit);
        }
        return '#' + hex.join('');
    },

    //returns prefix,postfix,value eg: #ff0000 {prefix: #, value: ff0000}, abc123efg {prefix: abc, value: 123, postfix: efg}
    splitValue: function(str) {
        result = {
            prefix: '',
            postfix: '',
            value: ''
        }
        if (str != '') {
            var res = str.match(/([^0-9]*)([0-9]+)([^0-9]*)/);
            //try{
            result = {
                prefix: res[1],
                postfix: res[3],
                value: res[2]
            };
        }
        return result;

    }

}
