/*
Script: MooFlickr.js
    Ajax image gallery which uses Flickr API

    License:
        MIT-style license.

    Authors:
        Amitay Horwitz <amitayh@gmail.com>
*/

var MooFlickr = new Class({
    
    Implements: [Options, Events],

    options: {
        loadFirstGallery: true,
        loadFirstImage: true,
        selectors: {
            galleries: '.galleries',
            imageDisplay: '.image',
            carousel: '.scrollArea',
            carouselPrev: '.scrollPrev',
            carouselNext: '.scrollNext'
        },
        galleryPicker: {},
        carousel: {},
        request: {
            url: 'MooFlickr.php',
            method: 'get'
        }
    },
    
    initialize: function(container, options) {
        $extend(this.options.request, {
            onFailure: $empty
        });
        this.setOptions(options);
        this.container = $(container);
        this.imageDisplay = new MooFlickr.ImageDisplay(
            this.getElement('imageDisplay')
        );
        this.initGalleryPicker();
        this.initCarousel();
    },
    
    getElement: function(selector) {
        return this.container.getElement(this.options.selectors[selector]);
    },
    
    initGalleryPicker: function() {
        this.galleryPicker = new MooFlickr.GalleryPicker(
            this.getElement('galleries')
        );
        this.galleryPicker.addEvent('select', function(gallery) {
            this.imageDisplay.unload();
            this.loadGallery(gallery.id);
        }.bind(this));
    },
    
    initCarousel: function() {
        this.carousel = new MooFlickr.Carousel(
            this.getElement('carousel'),
            this.options.carousel
        );
        this.getElement('carouselPrev')
            .addEvent('click', function(e) {
                this.carousel.prev();
            }.bind(this));
        this.getElement('carouselNext')
            .addEvent('click', function(e) {
                this.carousel.next();
            }.bind(this));
        this.carousel.addEvent('itemImageLoaded', function(item) {
            item.imgEl.addEvent('click', function() {
               this.loadImage(item);
            }.bind(this));
        }.bind(this));
    },
    
    loadImage: function(item) {
        if (this._currentItem && this._currentItem == item) { return; }
        this.carousel.select(item);
        this.imageDisplay.load(item);
        this._currentItem = item;
    },
    
    loadUserGalleries: function(user_id) {
        this.galleryPicker.empty();
        this.reset();
        var params = new Hash({action: 'getPhotosetList', user_id: user_id});
        new Request.JSON(
            $extend(this.options.request, {
                onSuccess: function(response) {
                    var firstItem = null;
                    if (response) {
                        response.each(function(gallery) {
                            if (!firstItem) { firstItem = gallery; }
                            this.galleryPicker.add(gallery);
                        }, this);
                        if (this.options.loadFirstGallery) {
                            this.galleryPicker.select(firstItem.id);
                        }
                    }
                }.bind(this)
            })
        ).send(params.toQueryString());
    },
    
    loadGallery: function(gallery_id) {
        this.reset();
        var params = new Hash({action: 'getPhotosetPhotos', photoset_id: gallery_id});
        new Request.JSON(
            $extend(this.options.request, {
                onSuccess: function(response) {
                    var firstItem = null;
                    if (response && response.photo) {
                        response.photo.each(function(image) {
                            var item = this.carousel.add(image);
                            if (!firstItem) { firstItem = item; }
                            if (item.isVisible()) {
                                item.load();
                            }
                        }, this);
                    }
                    if (this.options.loadFirstImage && firstItem) {
                        this.loadImage(firstItem);
                    }
                }.bind(this)
            })
        ).send(params.toQueryString());
    },
    
    reset: function() {
        this.imageDisplay.unload();
        this.carousel.empty();
    }
    
});

MooFlickr.GalleryPicker = new Class({
    
    Implements: [Options, Events],
    
    options: {
        templates: {
            title: '{title} ({photos} תמונות)'
        }
    },
    
    galleries: {},
    
    initialize: function(container, options) {
        this.setOptions(options);
        this.container = $(container);
        this._select = new Element('select').inject(this.container);
        var that = this;
        this._select.addEvent('change', function() {
            that.select(this.value);
        });
    },
    
    empty: function() {
        this.galleries = {};
        this._select.empty();
        return this;
    },
    
    add: function(gallery) {
        this.galleries[gallery.id] = gallery;
        var option = new Element('option', {
                value: gallery.id,
                text: this.options.templates.title.substitute(gallery)
        });
        option.inject(this._select);
    },
    
    select: function(gallery) {
        this.fireEvent('select', this.galleries[gallery]);
    }
    
});

MooFlickr.ImageDisplay = new Class({
    
    Implements: [Options, Events],
    
    options: {
        fx: {
            property: 'opacity',
            duration: 500,
            link: 'cancel'
        }
    },
    
    initialize: function(container, options) {
        this.setOptions(options);
        this.container = $(container);
    },
    
    load: function(item) {
        var that = this;
        var canShow = false, img;
        function show() {
            if (canShow) {
                that.img = img;
                img.setStyles({
                    'margin-top': -(img.height / 2 + 5).toInt() + 'px',
                    'margin-right': -(img.width / 2 + 5).toInt() + 'px'
                });
                img.retrieve('fx').set(0);
                img.inject(that.container);
                img.retrieve('fx').start(1);
            } else {
                canShow = true;
            }
        }
        if (this.img) {
            this.unload().chain(function() {
                this.img.destroy();
                show();
            }.bind(this));
        } else {
            show();
        }
        var img = new Asset.image(item.getImageUrl(), {
            onload: function() {
                that.fireEvent('load');
                show();
            }
        });
        img.store('fx', new Fx.Tween(img, this.options.fx));
    },
    
    unload: function() {
        if (this.img) {
            return this.img.retrieve('fx').start(0);
        }
    }
    
});

MooFlickr.Image = new Class({
    
    initialize: function(image) {
        this.image = image;
        return this;
    },
    
    getImageUrl: function(size) {
        if (this.image) {
            size = size || MooFlickr.Image.Size.medium;
            var pattern = 'http://farm{farm}.static.flickr.com/{server}/{id}_{secret}{size}.jpg';
            return pattern.substitute($extend(this.image, {size: size}));
        }
        return null;
    }
    
});

MooFlickr.Image.Size = {square: '_s', thumb: '_t', small: '_m', medium: '', large:  '_b'};

MooFlickr.Carousel = new Class({
    
    Implements: [Options, Events],

    options: {
        width: 86,
        style: 'horizonal',
        bindKeyboard: true,
        bindMousewheel: true,
        visible: 6,
        step: 5,
        cycle: true,
        fx: {
            link: 'cancel',
            duration: 500,
            transition: Fx.Transitions.Cubic.easeInOut
        },
        styles: {
            normal: {'border-color': '#555'},
            selected: {'border-color': '#fff'}
        }
    },
    
    initialize: function(container, options) {
        this.setOptions(options);
        this.container = $(container);
        this.scroller = new Element('ul').inject(this.container);
        if (this.options.bindKeyboard) {
            $(document).addEvent('keydown', function(e) {
                var actions = {left: 'next', right: 'prev'};
                if (actions[e.key]) {
                    e.stop();
                    this[actions[e.key]]();
                }
            }.bind(this));
        }
        if (this.options.bindMousewheel) {
            this.container.addEvent('mousewheel', function(e) {
                e.stop();
                this[(e.wheel < 0 ? 'next' : 'prev')](1, false);
            }.bind(this));
        }
        this.fx = new Fx.Tween(this.scroller, $extend(
            this.options.fx,
            {property: 'margin-' + (this.options.style == 'horizonal' ? 'right' : 'top')}
        ));
        this.items = [];
        this.reset();
    },
    
    reset: function() {
        this.scroller.setStyles({
            width: (this.items.length * this.options.width) + 'px'
        });
    },
    
    start: function(index) {
        if (index != this.index) {
            this.index = index;
            this.loadVisible();
            this.fireEvent('scrollStart', index);
            var that = this;
            this.fx.start(-(this.index * this.options.width)).chain(function() {
                that.fireEvent('scrollEnd', index);
            });
        }
    },
    
    next: function(step, cycle) {
        step = step || this.options.step;
        cycle = $defined(cycle) ? cycle : this.options.cycle;
        var index = this.index;
        if (index + step >= this.items.length) {
            if (cycle) {
                index = 0;
            }
        } else {
            index += step;
        }
        this.start(index);
        return this;
    },
    
    prev: function(step, cycle) {
        step = step || this.options.step;
        cycle = $defined(cycle) ? cycle : this.options.cycle;
        var index = this.index;
        index -= step;
        if (index < 0) {
            if (this.index == 0 && cycle) {
                index = (Math.ceil(this.items.length / step) - 1) * step;
            } else {
                index = 0;
            }
        }
        this.start(index);
        return this;
    },
    
    add: function(image) {
        var item = new MooFlickr.Carousel.Item(this, image);
        item.addEvent('load', function() {
            this.fireEvent('itemImageLoaded', item);
        }.bind(this));
        this.items.push(item);
        this.reset();
        $(item).inject(this.scroller);
        return item;
    },
    
    empty: function() {
        delete this._currentItem;
        this.index = 0;
        this.items = [];
        this.fx.set(0);
        this.scroller.empty();
        this.reset();
        return this;
    },
    
    select: function(item) {
        if (this._currentItem) {
            this._currentItem.Fx.start(this.options.styles.normal);
        }
        item.Fx.start(this.options.styles.selected);
        this._currentItem = item;
    },
    
    loadVisible: function() {
        for (var i = this.index, l = i + this.options.visible; i < l; i++) {
            var item = this.items[i];
            if (item) {
                item.load();
            }
        }
    }
    
});

MooFlickr.Carousel.Item = new Class({
    
    Implements: [Events, Options, MooFlickr.Image],
    
    options: {
        fx: {
            link: 'cancel',
            duration: 300
        }
    },
    
    initialize: function(carousel, image, options) {
        this.setOptions(options);
        this.carousel = carousel;
        this.image = image;
        this.liEl = new Element('li');
        this.Fx = new Fx.Morph(this.liEl, this.options.fx);
        this.loaded = false;
        this.loading = false;
        return this;
    },
    
    load: function(image) {
        if (!this.loading && !this.loaded) {
            this.loading = true;
            var that = this;
            this.imgEl = new Asset.image(this.getImageUrl(MooFlickr.Image.Size.square), {
                onload: function() {
                    this.loading = false;
                    that.loaded = true;
                    that.fireEvent('load');
                    this.fade('hide').inject(that.liEl).fade('in');
                }
            });
        }
    },
    
    isVisible: function() {
        var start = this.carousel.index;
        var end = start + this.carousel.options.visible - 1;
        return new Number(this.getIndex()).inRange(start, end);
    },
    
    getIndex: function() {
        return this.carousel.items.indexOf(this);
    },
    
    toElement: function() {
        return this.liEl;
    }
    
});

Number.implement({
    inRange: function(start, end) {
        return (this >= start && this <= end);
    }
});

String.implement({
    linebreaks: function() {
        return '<p>' + this.trim().replace(/\n{2,}/g, '</p><p>').replace(/\n/g, '<br />') + '</p>';
    },
    htmlentities: function() {
        var str = this;
        str = str.replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
        return str;
    }
});

//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License.

MooTools.More={version:"1.2.2.1"};Fx.Slide=new Class({Extends:Fx,options:{mode:"vertical"},initialize:function(b,a){this.addEvent("complete",function(){this.open=(this.wrapper["offset"+this.layout.capitalize()]!=0);
if(this.open&&Browser.Engine.webkit419){this.element.dispose().inject(this.wrapper);}},true);this.element=this.subject=$(b);this.parent(a);var c=this.element.retrieve("wrapper");
this.wrapper=c||new Element("div",{styles:$extend(this.element.getStyles("margin","position"),{overflow:"hidden"})}).wraps(this.element);this.element.store("wrapper",this.wrapper).setStyle("margin",0);
this.now=[];this.open=true;},vertical:function(){this.margin="margin-top";this.layout="height";this.offset=this.element.offsetHeight;},horizontal:function(){this.margin="margin-left";
this.layout="width";this.offset=this.element.offsetWidth;},set:function(a){this.element.setStyle(this.margin,a[0]);this.wrapper.setStyle(this.layout,a[1]);
return this;},compute:function(c,b,a){return[0,1].map(function(d){return Fx.compute(c[d],b[d],a);});},start:function(b,e){if(!this.check(b,e)){return this;
}this[e||this.options.mode]();var d=this.element.getStyle(this.margin).toInt();var c=this.wrapper.getStyle(this.layout).toInt();var a=[[d,c],[0,this.offset]];
var g=[[d,c],[-this.offset,0]];var f;switch(b){case"in":f=a;break;case"out":f=g;break;case"toggle":f=(c==0)?a:g;}return this.parent(f[0],f[1]);},slideIn:function(a){return this.start("in",a);
},slideOut:function(a){return this.start("out",a);},hide:function(a){this[a||this.options.mode]();this.open=false;return this.set([-this.offset,0]);},show:function(a){this[a||this.options.mode]();
this.open=true;return this.set([0,this.offset]);},toggle:function(a){return this.start("toggle",a);}});Element.Properties.slide={set:function(b){var a=this.retrieve("slide");
if(a){a.cancel();}return this.eliminate("slide").store("slide:options",$extend({link:"cancel"},b));},get:function(a){if(a||!this.retrieve("slide")){if(a||!this.retrieve("slide:options")){this.set("slide",a);
}this.store("slide",new Fx.Slide(this,this.retrieve("slide:options")));}return this.retrieve("slide");}};Element.implement({slide:function(d,e){d=d||"toggle";
var b=this.get("slide"),a;switch(d){case"hide":b.hide(e);break;case"show":b.show(e);break;case"toggle":var c=this.retrieve("slide:flag",b.open);b[c?"slideOut":"slideIn"](e);
this.store("slide:flag",!c);a=true;break;default:b.start(d,e);}if(!a){this.eliminate("slide:flag");}return this;}});var Asset={javascript:function(f,d){d=$extend({onload:$empty,document:document,check:$lambda(true)},d);
var b=new Element("script",{src:f,type:"text/javascript"});var e=d.onload.bind(b),a=d.check,g=d.document;delete d.onload;delete d.check;delete d.document;
b.addEvents({load:e,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){e();}}}).set(d);if(Browser.Engine.webkit419){var c=(function(){if(!$try(a)){return;
}$clear(c);e();}).periodical(50);}return b.inject(g.head);},css:function(b,a){return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:b},a)).inject(document.head);
},image:function(c,b){b=$merge({onload:$empty,onabort:$empty,onerror:$empty},b);var d=new Image();var a=$(d)||new Element("img");["load","abort","error"].each(function(e){var f="on"+e;
var g=b[f];delete b[f];d[f]=function(){if(!d){return;}if(!a.parentNode){a.width=d.width;a.height=d.height;}d=d.onload=d.onabort=d.onerror=null;g.delay(1,a,a);
a.fireEvent(e,a,1);};});d.src=a.src=c;if(d&&d.complete){d.onload.delay(1);}return a.set(b);},images:function(d,c){c=$merge({onComplete:$empty,onProgress:$empty},c);
d=$splat(d);var a=[];var b=0;return new Elements(d.map(function(e){return Asset.image(e,{onload:function(){c.onProgress.call(this,b,d.indexOf(e));b++;if(b==d.length){c.onComplete();
}}});}));}};