Lightbox = new JS.Class('Lightbox', {
    include: [Ojay.Observable, JS.State],
    
    initialize: function(thumbnails) {
        thumbnails = Ojay(thumbnails);
        
        this._createItems(thumbnails);
        this._createNavigator(thumbnails);
        this._makeOverlay();
        
        this.setState('CLOSED');
    },
    
    getItem: function(key) {
        return this._images[key];
    },
    
    getCurrentItem: function() {
        return this._current;
    },
    
    _createItems: function(thumbnails) {
        var gallery = this;
        
        this._container = Ojay(Ojay.HTML.div({className: 'lightbox-images'}));
        
        this._images = thumbnails.reduce(function(images, thumb, i) {
            var item = new gallery.klass.Item(gallery, thumb);
            
            item.on('load', function() { gallery._container.insert(item.getHTML()); });
            if (i === 0) {
                item.on('load', function() { item.show(); });
                gallery._current = item;
            }
            
            item.load();
            
            thumb.on('click', function(el, evnt) {
                evnt.stopDefault();
                gallery.showItem(item);
            });
            
            images[item.key()] = item;
            return images;
        }, {});
    },
    
    _createNavigator: function(thumbnails) {
        this._thumbnails = new this.klass.Thumbnails(this, thumbnails);
    },
    
    _makeOverlay: function() {
        this._close = Ojay(Ojay.HTML.span({className: 'close'}, 'Close'));
        
        this._close.on('click', function() {
            this._overlay.hide('fade')
            ._(this._mask).hide('fade')
            ._(function() {
                this.setState('CLOSED');
            }.bind(this));
        }, this);
        
        this._mask = new Ojay.PageMask({
            color: '#000',
            opacity: this.klass.MASK_OPACITY
        });
        
        this._overlay = new Ojay.ContentOverlay({
            width:   770,
            height:  500,
            top:     40,
            content: this._close
        });
        
        this._overlay
            .insert(this._thumbnails.getHTML(), 'bottom')
            .insert(this._container, 'bottom')
            .positionInFront(this._mask);
        
        this._thumbpager = new Ojay.Paginator(this._thumbnails.getHTML(), {
            direction: 'horizontal',
            width:     '755px',
            height:    '140px'
        });
    },
    
    states: {
        READY: {
            showItem: function(item) {
                this.setState('SWITCHING');
                
                var self = this, __show__ = function() {
                    self.notifyObservers('itemchange', self._current.key(), item.key());
                    
                    self._current.hide()
                    ._(item).show()
                    ._(self._overlay).fitToContent()
                    ._(function() {
                        self._current = item;
                        self.setState('READY');
                    });
                };
                
                if (item.isLoaded()) {
                    __show__();
                } else {
                    item.on('load', __show__);
                    item.load();
                }
            }
        },
        
        SWITCHING: {},
        
        CLOSED: {
            showItem: function(item) {
                this.notifyObservers('itemchange', this._current.key(), item.key());
                
                this._current.hide({animate: false})
                ._(item).show({animate: false})
                ._(this._mask).show('fade')
                ._(this._overlay).fitToContent().center().show('fade')
                ._(function() {
                    if (!this._thumbPagerSetup) {
                        this._thumbpager.setup();
                        var ctrl = this._thumbpager.addControls('after');
                        ctrl.getHTML().node.id = 'imageTilePaginator';
                        this._thumbPagerSetup = true;
                    }
                    
                    this._current = item;
                    this.setState('READY');
                }.bind(this));
            }
        }
    },
    
    extend: {
        Item: new JS.Class('Lightbox.Item', {
            include: [Ojay.Observable, JS.State],
            
            initialize: function(gallery, thumb) {
                this.setState('UNLOADED');
                
                this._gallery = gallery;
                this._thumb   = thumb;
                this._link    = thumb.node.href;
                this._alt     = thumb.children('img').node.alt;
            },
            
            key: function() {
                return this._link;
            },
            
            states: {
                UNLOADED: {
                    load: function() {
                        this._container = Ojay(Ojay.HTML.div({className: this.klass.CONTAINER_CLASSNAME}));
                        this._image     = Ojay(Ojay.HTML.img({alt: this._alt})).setStyle({
                            display: 'block',
                            opacity: 0
                        }).hide();
                        
                        this._image.on('load', function() {
                            this.setState('HIDDEN');
                            this.notifyObservers('load');
                        }, this);
                        
                        this._image.set({src: this._link});
                    },
                    
                    show: function(options) {
                        this.on('load', this.show.partial(options), this);
                        return (new JS.MethodChain()).fire(this);
                    },
                    
                    hide: function(options) {
                        this.on('load', this.hide.partial(options), this);
                        return (new JS.MethodChain()).fire(this);
                    }
                },
                
                HIDDEN: {
                    show: function(options) {
                        options = options || {};
                        
                        if (options.animate === false) {
                            this.setState('SHOWN');
                            return this._image.show().setStyle({opacity: 1});
                        }
                        
                        return this._image.show().animate({
                            opacity: {
                                to: 1
                            }
                        }, this.klass.FADE_TIME)
                        ._(function() { this.setState('SHOWN'); }.bind(this));
                    }
                },
                
                SHOWN: {
                    hide: function(options) {
                        options = options || {};
                        
                        if (options.animate === false) {
                            this.setState('HIDDEN');
                            return this._image.setStyle({opacity: 0}).hide();
                        }
                        
                        return this._image.animate({
                            opacity: {
                                to: 0
                            }
                        }, this.klass.FADE_TIME).hide()
                        ._(function() { this.setState('HIDDEN') }.bind(this));
                    }
                }
            },
            
            getHTML: function() {
                if (this.isLoaded()) return this._image;
                
                this.load();
                
                return this._image;
            },
            
            isLoaded: function() {
                return !this.inState('UNLOADED');
            },
            
            extend: {
                MASK_OPACITY:        0.8,
                FADE_TIME:           0.3,
                CONTAINER_CLASSNAME: 'lightbox-image'
            }
        }),
        
        Thumbnails: new JS.Class('Lightbox.Thumbnails', {
            initialize: function(gallery, thumbnails) {
                var self = this;
                
                this._gallery   = gallery;
                this._container = Ojay(Ojay.HTML.div({className: 'lightbox-thumbnails'}));
                this._thumbs    = thumbnails.reduce(function(thumbs, thumb) {
                    var key   = thumb.node.href,
                        img   = thumb.children('img').node,
                        html  = Ojay(Ojay.HTML.div({className: 'imgWrapper'})),
                        image = Ojay(Ojay.HTML.img({alt: img.alt, src: img.src})),
                        item  = self._gallery.getItem(key);
                    
                    image.on('click', function() {
                        if (gallery.getCurrentItem() !== item) gallery.showItem(item);
                    });
                    
                    image.setStyle({
                        'display': 'block',
                        'float':   'left'
                    });
                    
                    html.insert(image);
                    self._container.insert(html);
                    
                    thumbs[key] = html;
                    return thumbs;
                }, {});
                
                this._gallery.on('itemchange', this.setCurrent, this);
            },
            
            setCurrent: function(gallery, oldKey, newKey) {
                var currentThumb = this._thumbs[oldKey],
                    newThumb     = this._thumbs[newKey];
                
                currentThumb.removeClass('selected');
                newThumb.addClass('selected');
            },
            
            getHTML: function() {
                return this._container;
            }
        })
    }
});

