var ProductGallery = new JS.Class('ProductGallery', {
    initialize: function(thumbs, container, options) {
        thumbs    = Ojay(thumbs);
        container = Ojay(container);
        options   = options || {};
        
        this._current = 0;
        this._imageContainer = Ojay(Ojay.HTML.div({
            className: 'main-images',
            style: {
                overflow: 'hidden',
                position: 'relative'
            }
        }));
        container.insert(this._imageContainer, options.position || 'top');
        
        if (thumbs.length < 2) thumbs.hide();
        
        this._thumbs = thumbs.map(function(thumb, index) {
            var fullsizeLink   = thumb.siblings('a.fullsize'),
                fullsizeData   = fullsizeLink.children('span').node.innerHTML.parseJSON(),
                normalData     = thumb.children('span').node.innerHTML.parseJSON();
            
            var image = new this.klass.Image(thumb, this, {
                zoomedImage:  fullsizeLink.node.href,
                zoomWidth:    fullsizeData.width,
                zoomHeight:   fullsizeData.height,
                normalWidth:  normalData.width,
                normalHeight: normalData.height,
                href:         thumb.node.href,
                description:  thumb.children('img').node.alt
            });
            
            this._imageContainer.insert(image.getHTML(), 'bottom');
            
            if (index === this._current) {
                image.loadImage(null, {animate: false}).getThumbnail().addClass('selected');
            }
            
            if (thumbs.length > 1) {
                image.getThumbnail().on('click', function(link, evnt) {
                    var current = this._thumbs[this._current],
                        next    = this._thumbs[index];
                    
                    evnt.stopDefault();
                    
                    if (index === this._current || current.inState('ANIMATING')) return;
                    
                    link.addClass('selected');
                    current.getThumbnail().removeClass('selected');
                    next.show(current);
                    
                    this._current = index;
                }, this);
            }
            
            return image;
        }, this);
    },
    
    getHTML: function() {
        return this._imageContainer;
    },
    
    extend: {
        Image: new JS.Class('ProductGallery.Image', {
            include: JS.State,
            
            initialize: function(thumb, gallery, options) {
                this._options      = options || {};
                
                this._gallery      = gallery;
                
                this._normalWidth  = this._options.normalWidth;
                this._normalHeight = this._options.normalHeight;
                this._zoomWidth    = this._options.zoomWidth;
                this._zoomHeight   = this._options.zoomHeight;
                
                this._zoomX        = ((this._zoomWidth  - this._normalWidth)  / 2).round();
                this._zoomY        = ((this._zoomHeight - this._normalHeight) / 2).round();
                
                this._thumbnail    = thumb;
                this._href         = this._options.href;
                this._desc         = this._options.description;
                
                this._zoomIcon     = Ojay(Ojay.HTML.span({className: 'zoom-icon'}));
                
                this._container    = Ojay(Ojay.HTML.div({
                    className: 'image',
                    style: {
                        width:    this._normalWidth  + 'px',
                        height:   this._normalHeight + 'px',
                        position: 'absolute',
                        top:      0,
                        left:     0,
                        overflow: 'hidden'
                    }
                }, this._zoomIcon)).hide();
                
                this._container.on('mouseover', function(c) {
                    c.addClass('hover');
                });
                
                this._container.on('mouseout', function(c) {
                    c.removeClass('hover');
                });
                
                this.setState('CREATED');
            },
            
            getHeight: function() {
                return this._normalHeight;
            },
            
            getHTML: function() {
                return this._container;
            },
            
            getThumbnail: function() {
                return this._thumbnail;
            },
            
            states: {
                CREATED: {
                    loadImage: function(current, options) {
                        this._image = Ojay(Ojay.HTML.img({
                            className: 'img-medium',
                            alt:       this._desc,
                            style: {
                                width:    this._normalWidth  + 'px',
                                height:   this._normalHeight + 'px',
                                top:      0,
                                left:     0
                            }
                        }));
                        
                        this._image.on('load', function(img) {
                            this._container.insert(img);
                            this.setState('READY');
                            this.show(current, options);
                        }, this);
                        
                        this._image.set({
                            src: this._href
                        });
                        
                        this._container.on('click', function(el, evnt) {
                            if (!this._ddBeingDragged) return this.zoom();
                        }, this);
                        
                        return this;
                    },
                    
                    show: function(current, options) {
                        this.loadImage(current, options);
                    }
                },
                
                READY: {
                    show: function(current, options) {
                        var chain   = new JS.MethodChain();
                            options = options || {};
                        
                        if (current) chain.hide();
                        
                        chain._(this._container);
                        
                        if (options.animate === false) {
                            chain._(this._gallery.getHTML()).setStyle({height: this.getHeight() + 'px'});
                            chain._(this._container).setStyle({opacity: 1}).show();
                        } else {
                            var currentHeight = current.getHeight(),
                                newHeight     = this.getHeight();
                            
                            if (currentHeight != newHeight) {                                
                                chain._(this._gallery.getHTML()).animate({
                                    height: {
                                        from: current.getHeight(),
                                        to:   this.getHeight()
                                    }
                                }, 0.1);
                            }
                            
                            if (YAHOO.env.ua.ie == 6) chain._(this._zoomIcon).hide();
                            
                            chain._(this._container).setStyle({opacity: 0}).show().animate({
                                opacity: {
                                    from: 0,
                                    to:   1
                                }
                            }, 0.3);
                            
                            if (YAHOO.env.ua.ie == 6) chain._(this._zoomIcon).show();
                        }
                        
                        return chain.fire(current);
                    },
                    
                    hide: function(options) {
                        var chain   = new JS.MethodChain();
                            options = options || {};
                        
                        if (options.animate === false) {
                            chain.setStyle({opacity: 0}).hide();
                        } else {
                            if (YAHOO.env.ua.ie == 6) chain._(this._zoomIcon).hide();
                            
                            chain._(this._container).animate({
                                opacity: {
                                    from: 1,
                                    to:   0
                                }
                            }, 0.3).hide();
                            
                            if (YAHOO.env.ua.ie == 6) chain._(this._zoomIcon).show();
                        }
                        
                        return chain.fire(this._container);
                    },
                    
                    zoom: function() {
                        var self  = this,
                            zoomAnimation, zoomPosition,
                            showZoomed, setupDragging;
                        
                        zoomAnimation = {
                            width:  {from: this._normalWidth,  to: this._zoomWidth },
                            height: {from: this._normalHeight, to: this._zoomHeight},
                            left:   {from: 0,                  to: -this._zoomX    },
                            top:    {from: 0,                  to: -this._zoomY    }
                        };
                        
                        zoomPosition = {
                            left: -this._zoomX + 'px',
                            top:  -this._zoomY + 'px'
                        };
                        
                        showZoomed = function() {
                            if (!self._zoomedImageLoaded) {
                                self._zoomedImage.on('load', showZoomed);
                                return;
                            }
                            
                            self._zoomedImage.setStyle(zoomPosition)
                            ._(self._image).hide()
                            ._(self._container).addClass('zoomed')
                            ._(self._zoomedImage).show()
                            ._(setupDragging)
                            ._(self).setState('ZOOMED');
                        };
                        
                        setupDragging = function() {
                            if (!self._dd) {
                                self._dd = new YAHOO.util.DD(self._zoomedImage.node);
                                self._dd.setXConstraint(self._zoomX, self._zoomX);
                                self._dd.setYConstraint(self._zoomY, self._zoomY);
                                
                                self._ddBeingDragged = false;
                                
                                self._container.on('mousedown', function() {
                                    self._ddBeingDragged = false;
                                }, self);
                                
                                self._dd.on('mouseDownEvent', function() {
                                    self._ddBeingDragged = false;
                                }, self, true);
                                
                                self._dd.on('startDragEvent', function() {
                                    self._ddBeingDragged = true;
                                }, self, true);
                            }
                            
                            self._dd.unlock();
                        };
                        
                        if (!this._zoomedImage) this._loadZoomedImage();
                        
                        this.setState('ANIMATING');
                        
                        return this._image.animate(zoomAnimation, 0.5)._(showZoomed)._(this);
                    },
                    
                    _loadZoomedImage: function() {
                        this._zoomedImageLoaded = false;
                        this._zoomedImage       = Ojay(Ojay.HTML.img({
                            className: 'img-zoom',
                            alt:       this._desc
                        })).hide();
                        
                        this._zoomedImage.on('load', function() {
                            this._zoomedImageLoaded = true;
                            this._container.insert(this._zoomedImage, 'bottom');
                        }, this);
                        
                        this._zoomedImage.set({
                            src: this._options.zoomedImage
                        });
                    }
                },
                
                ZOOMED: {
                    show: function(options) {
                        return this.zoom().show();
                    },
                    
                    hide: function(options) {
                        return this.zoom().hide();
                    },
                    
                    zoom: function() {
                        this._dd.lock();
                        
                        this.setState('ANIMATING');
                        
                        var currentLeft = parseInt(this._zoomedImage.getStyle('left'), 10) || 0,
                            currentTop  = parseInt(this._zoomedImage.getStyle('top'), 10)  || 0;
                        
                        this._image.setStyle({
                            left: currentLeft + 'px',
                            top:  currentTop  + 'px'
                        });
                        
                        return this._zoomedImage.hide()
                        ._(this._image).show().animate({
                            width:  {from: this._zoomWidth,  to: this._normalWidth },
                            height: {from: this._zoomHeight, to: this._normalHeight},
                            left:   {from: currentLeft,      to: 0                 },
                            top:    {from: currentTop,       to: 0                 }
                        }, 0.3)
                        ._(this._container).removeClass('zoomed')
                        ._(function() {
                            this.setState('READY');
                        }.bind(this))._(this);
                    }
                },
                
                ANIMATING: {}
            }
        })
    }
});

