MultiLinkPromo = new JS.Class({
    initialize: function(selector, options) {
        this._options  = options || {};

        this._wrapper  = Ojay(selector).at(0);
        this._main     = this._wrapper.children('.main-image');
        this.linkAreas = this._wrapper.children('.promo-area').map(function(area) {
            return new this.klass.LinkArea(area);
        },
        this);
    },

    setup: function() {
        this._wrapper.setStyle({
            height: this.getHeight() + 'px',
            width:  this.getWidth()  + 'px'
        });
        var areaWidth = Math.round(this.getWidth() / this.linkAreas.length);
        this.linkAreas.forEach(function(area, index) {
            var offset = index * areaWidth;
            if (offset > 0) offset += 1;

            area.setup({
                width: areaWidth,
                left:  offset
            });
        },
        this);
    },

    getHeight: function() {
        return this._height = this._options.height || this._main.getHeight();
    },

    getWidth: function() {
        return this._width = this._options.width || this._main.getWidth();
    },

    extend: {
        LinkArea: new JS.Class({
            include: JS.State,

            initialize: function(root, options) {
                this.setState('INACTIVE');

                this._root      = root;
                this._container = root.children('.links-area');
                this._title     = root.descendants('.title');
                this._links     = root.descendants('.links');

                var top = parseInt(this._root.getStyle('paddingTop').match(/^\d+/)[0], 10);

                this._minHeight = this._title.getHeight();
                this._maxHeight = this._container.getHeight();
            },

            setup: function(options) {
                this._options = options || {};

                this._root.setStyle({
                    position: 'absolute',
                    bottom:   0,
                    left:     this._options.left     + 'px',
                    width:    this._options.width    + 'px',
                    height:   this._root.getHeight() + 'px'
                });

                this._container.setStyle({
                    position: 'absolute',
                    bottom:   0,
                    left:     0,
                    width:    this._options.width + 'px',
                    height:   this._minHeight     + 'px'
                });

                this.setState('CLOSED');

                ['mouseenter', 'mouseleave'].forEach(function(trigger) {
                    YAHOO.util.Event.on(this._root.node, trigger, this.animate, {},
                    this);
                },
                this);
            },

            getWidth: function() {
                return this._root.getWidth();
            },

            isHovered: function() {
                return this._hovered;
            },

            /**
             * Sets the hover state based on the event type.
             * 
             * For some reason, the event object is sometimes undefined, so the
             * method includes a check which supresses errors of this kind.
             */
            _setHover: function(evnt) {
                if (evnt && typeof evnt.type == 'string')
                this._hovered = evnt.type == 'mouseover';
            },

            states: {
                OPEN: {
                    /**
                     * Animates the LinkArea from its open appearance to its closed one.
                     * A callback will fire when it finishes closing, to open the
                     * LinkArea again if the mouse pointer has been moved over it during
                     * the interval when it was animating.
                     */
                    animate: function(evnt) {
                        this._setHover(evnt);
                        this.setState('ANIMATING');
                        this._container.animate({
                            height: {
                                from: this._maxHeight,
                                to:   this._minHeight
                            }
                        },
                        this.klass.ANIM_TIME)
                        .wait(this.klass.WAIT_TIME)
                        ._(function() {
                            this.setState('CLOSED');
                            if (this.isHovered()) this.animate();
                        }.bind(this));
                    }
                },

                CLOSED: {
                    /**
                     * Animates the LinkArea from its closed appearance to its open one.
                     * A callback will fire when it finishes opening, to close the
                     * LinkArea again if the mouse pointer has been moved away during the
                     * interval when it was animating.
                     */
                    animate: function(evnt) {
                        this._setHover(evnt);
                        this.setState('ANIMATING');
                        this._container.animate({
                            height: {
                                from: this._minHeight,
                                to:   this._maxHeight
                            }
                        },
                        this.klass.ANIM_TIME)
                        .wait(this.klass.WAIT_TIME)
                        ._(function() {
                            this.setState('OPEN');
                            if (!this.isHovered()) this.animate();
                        }.bind(this));
                    }
                },

                INACTIVE: {},

                ANIMATING: {
                    /**
                     * While the LinkArea is animating, mouse(enter|leave) events should
                     * not cause it to animate further; however, it does need to keep
                     * track of whether or not the area is hovered (and thus whether to
                     * change state again when the animation is completed).
                     */
                    animate: function(evnt) {
                        this._setHover(evnt);
                    }
                }
            },

            extend: {
                ANIM_TIME: 0.5,
                WAIT_TIME: 0.1
            }
        })
    }
});

