$.extend(Function.prototype, {
    use: function() {
		var method = this, args = Array.prototype.slice.call(arguments), object = args.shift();
		return function() {
			return method.apply(object, args.concat(Array.prototype.slice.call(arguments)));
		}
    },
    useEL: function() {
        var method = this, args = Array.prototype.slice.call(arguments), object = args.shift();
        return function(event) {
            return method.apply(object, [event || window.event].concat(Array.prototype.slice.call(arguments)));
        }
    }
});

$.extend($.Event.prototype, {
    stop: function() {
        this.stopPropagation();
        this.preventDefault();
    }
});

/**
 * Controller
 * Manages the entire application (for the most part)
 */
var Controller = function() {
    this.els = {
        wishForm: $(Controller.selectors.wishForm),
        updateForm: $(Controller.selectors.updateForm),
        shareForm: $(Controller.selectors.shareForm),
        intro: $(Controller.selectors.intro),
        introClose: $(Controller.selectors.introClose),
        wishBtn: $(Controller.selectors.wishBtn),
        updateBtn: $(Controller.selectors.updateBtn)
    };

    this.getWishes();
    this.startTimer();
    this.wishForm = new Form(this.els.wishForm, true);
    this.updateForm = new Form(this.els.updateForm, false, true);
    this.stage = new Stage();
    this.wishes = [];
    
    this.stage.load();
    
    $(document).bind('error', this.alertError.useEL(this));
    
    $(document).bind('form:show', this.stopTimer.useEL(this));
    $(document).bind('form:hide', this.startTimer.useEL(this));
    
    $(document).bind('wish:add', function(event, event2, data) {
        var data = data[0];
        event.data = {
            id: 9999999,
            i: 0,
            force: true,
            image: data['data[Wish][image]'],
            message: data['data[Wish][message]'],
            to_name: data['data[Wish][to_name]'],
            from_name: data['data[Wish][from_name]']
        }
        this.addWish(event); 
        this.wishForm.hide();
    }.useEL(this));

    this.els.introClose.bind('click', this.hideIntro.useEL(this));
    this.els.wishBtn.bind('click', this.showWishForm.useEL(this));
    this.els.updateBtn.bind('click', this.showUpdateForm.useEL(this));
};
$.extend(Controller.prototype, {
    hideIntro: function(event) {
        event.stop();
        this.wishForm.hide();
        if($.support.opacity) {
            this.els.intro.fadeOut(800);
        } else {
            this.els.intro.hide();
        }
    },
    showWishForm: function(event) {
        event.stop();
        this.hideIntro(event);
        this.wishForm.show();
    },
    showUpdateForm: function(event) {
        event.stop();
        this.hideIntro(event);
        this.updateForm.show();
    },
    getWishes: function() {
        var self = this;
        $.getJSON('/wishes/get_random', '', function(data, status) {
            switch(status) {
                case 'success':
                    var i = 1;
                    $(data).each(function() {
                        this.Wish.i = i;
                        self.addWish({data: this.Wish})
                        i++;
                    });
                break;
            }
        });
    },
    startTimer: function() {
        if(this.interval || !!this.interval) { return; }
        var iteration = 0;
        this.interval = setInterval(function() {
            this.getWishes();
            iteration++;
            if(!(iteration % 2)) {
                this.removeWishes(13);
            } else {
                this.removeWishes(7);
            }
        }.use(this), 10000);
    },
    stopTimer: function() {
        clearInterval(this.interval);
        this.interval = false;
    },
    removeWishes: function(num) {
        for(num--; num >= 0; num--) {
            this.wishes[num].hide(function() { this.wishes.shift(); }.use(this));
        }
    },
    addWish: function(event) {
        var wish = event.data;
        this.wishes.push(
            new Wish(wish.id, wish.image, wish.message, wish.to_name, wish.from_name, wish.i, wish.force)
        );
    },
    alertError: function(event, event2, message) {
        new ErrorHandler(message);
    }
});
$.extend(Controller, {
    selectors: {
        wishForm: '#wishForm',
        shareForm: '#shareForm',
        updateForm: '#updateBox',
        intro: '#intro',
        introClose: '#intro .close',
        wishBtn: '#intro .wishForm, #sendToFriend',
        updateBtn: '.btn.link.updates',
        wishClose: '#wishForm .close'
    },
    init: function() {
        Controller.instance = new Controller();
    }
});


var ErrorHandler = function(msg) {
    this.message = msg;

    this.els = {
        overlay: $(ErrorHandler.selectors.overlay),
        container: $(ErrorHandler.selectors.container)
    }
    $.extend(this.els, {
        header: this.els.container.find(ErrorHandler.selectors.header).text(this.message.header),
        message: this.els.container.find(ErrorHandler.selectors.message).text(this.message.message),
        close: this.els.container.find(ErrorHandler.selectors.closeBtn).text(this.message.confirm)
    });
    
    this.els.close.bind('click', this.hide.useEL(this));
    
    this.show();
};
$.extend(ErrorHandler.prototype, {
    setPosition: function() {
        var leftCenter = Math.round(($(window).width()/2)-(this.els.container.width()/2));
        var topCenter = Math.round(($(window).height()/2)-(this.els.container.height()/2));
        
        this.els.container.css({ 'top': topCenter+'px', 'left': leftCenter+'px' });
    },
    show: function() {
        this.setPosition();
        
        this.els.overlay.show().css({'opacity': 0}).animate({ 'opacity': 0.6 }, 500);
   
        if($.support.opacity) {
            this.els.container.fadeIn(500);
        } else {
            this.els.container.show();
        }
    },
    hide: function(event) {
        if(event) { event.stop(); }
        
        this.els.overlay.animate({ 'css': 0 }, 500, function() {
            this.els.overlay.hide();
        }.use(this));
        
        if($.support.opacity) {
            this.els.container.fadeOut(500);
        } else {
            this.els.container.hide();
        }
    }
});
$.extend(ErrorHandler, {
    selectors: {
        overlay: '#overlay',
        container: '#errorBox',
        header: 'h2',
        message: 'p',
        closeBtn: '.btn'
    }
});


/**
 * Generic Form Class
 * Controls positioning, hiding and showing forms.
 */
var Form = function(element, ajax, center) {
    this.center = center;
    
    this.els = {
        container: $(element)
    };
    
    $.extend(this.els, {
        form: this.els.container.find(Form.selectors.form),
        closeBtn: this.els.container.find(Form.selectors.closeBtn),
        iconSelector: this.els.container.find(Form.selectors.iconSelector)
    });
    
    if(ajax) {
        this.els.form.bind('submit', this.submit.useEL(this));
    }
    
    this.els.closeBtn.bind('click', this.hide.useEL(this));
    
    if(this.els.iconSelector.length) {
        this.iconSelector = new IconSelector();
    }
        
    this.attachEvents();
};
$.extend(Form.prototype, {
    show: function(event) {
        if(event) { event.stop(); }
        
        if(this.center) {
            this.setPosition();
        }
        
        $(document).trigger('form:show');

        if($.support.opacity) {
            this.els.container.fadeIn(1000);
        } else {
            this.els.container.show();
        }
    },
    hide: function(event) {
        if(event) { event.stop(); }
        $(document).trigger('form:hide');
        if($.support.opacity) {
            this.els.container.fadeOut(500);
        } else {
            this.els.container.hide();
        }
    },
    setPosition: function() {
        var topPos = Math.round(($(window).height()/2)-($(this.els.container).height()/2));
        var leftPos = Math.round(($(window).width()/2)-($(this.els.container).width()/2));
        
        this.els.container.css({ top: topPos+'px', left: leftPos+'px' });
    },
    submit: function(event) {
        event.stop();
        
        $.ajax({
            url: this.els.form.attr('action'),
            data: this.els.form.serialize(),
            type: 'post',
            success: function(data) {
                var data = {};
                $(this.els.form.serializeArray()).each(function() {
                    data[this.name] = this.value;
                });
                
                this.els.form.find('input[type!="submit"],textarea').attr('value', '').blur();
                
                var action = this.els.form.attr('action').split('/');
                action = action[action.length-1];
                $(document).trigger('wish:'+action, [[data]]);
                
                this.els.form.children('input[type="text"],textarea').attr('value', '');
                
                if(pageTracker) {
                    pageTracker._trackPageview(this.els.form.attr('action')+'/submit');
                }
            }.use(this),
            error: function(data) {
                $(document).trigger('error', [Form.strings.submitError]);
            }
        });
    },
    attachEvents: function() {
        this.els.form.find('input, textarea').focus(function() {
            $(this).siblings('label').fadeOut(200);
        }).blur(function() {
            if(/^\s*$/.test($(this).attr('value'))) {
                $(this).siblings('label').fadeIn(300);
            }
        }).each(function() {
            if($(this).attr('value') != '') {
                $(this).siblings('label').hide();
            }
        });
        this.els.form.find('label').click(function(event) {
            event.stop();
            $(this).next('input, textarea').focus();
        });
    }
});
$.extend(Form, {
    selectors: {
        form: 'form',
        closeBtn: '.close',
        iconSelector: '#iconSelector'
    },
    strings: {
        submitError: {
            header: 'Error sending wish',
            message: 'Please fill in all form fields and make sure they are correct.',
            confirm: 'Double Check'
        }
    }
});

/**
 * Icon Selector
 */
var IconSelector = function(el) {
    this.els = {
        container: $(el),
        input: $(IconSelector.selectors.input)
    };
    $.extend(this.els, {
        preview: this.els.container.find(IconSelector.selectors.preview),
        list: this.els.container.find(IconSelector.selectors.list)
    });
    
    this.setRandom();
    
    this.els.preview.bind('click', this.preload.useEL(this));
};
$.extend(IconSelector.prototype, {
    preload: function(event) {
        var event = (event) ? event : null;
        if(event) { event.stop(); }
        if(this.els.list.find('a').length) { this.showSelector(event); return; }
        var loader = new Preloader();
        $(loader).bind('complete', function() {
            var self = this;
            $(IconSelector.icons).each(function() {
                self.els.list.append('<a href="#" style="background-image: url('+this+');">'+this+'</a>');
            });
            this.els.list.find('a').bind('click', this.selectIcon.useEL(this));
            this.showSelector(event);
        }.useEL(this));
        loader.load(IconSelector.icons);
    },
    showSelector: function(event) {
        if(event) { event.stop(); }
        if($.support.opacity) {
            this.els.preview.fadeOut(500);
            this.els.list.fadeIn(500);
        } else {
            this.els.preview.hide();
            this.els.list.show();
        }
    },
    hideSelector: function(event) {
        if(event) { event.stop(); }
        if($.support.opacity) {
            this.els.list.fadeOut(500);
            this.els.preview.fadeIn(500);
        } else {
            this.els.list.hide();
            this.els.preview.show();
        }
    },
    selectIcon: function(event) {
        if(event) { event.stop(); }
        this.setIcon($(event.target).text());
        this.hideSelector();
    },
    setIcon: function(src) {
        this.els.preview.html('<img src="'+src+'" alt="" />');
        this.els.input.attr('value', src);
    },
    setRandom: function() {
        var length = IconSelector.icons.length;
        this.key = Math.floor(Math.random()*length);

        var loader = new Preloader();
        
        $(loader).bind('complete', function() {
            this.setIcon(IconSelector.icons[this.key]);
        }.useEL(this));
        
        loader.load(IconSelector.icons[this.key]);
    }
});
$.extend(IconSelector, {
    icons: [
        '/images/iconRainbow.gif',
        '/images/iconAngelGirl.gif',
        '/images/iconBagpipe.gif',
        '/images/iconBeer1.gif',
        '/images/iconBeer2.gif',
        '/images/iconBeer3.gif',
        '/images/iconCloud.gif',
        '/images/iconCornedBeef.gif',
        '/images/iconDevilgirl.gif',
        '/images/iconFlag.gif',
        '/images/iconGreenheart.gif',
        '/images/iconGuy.gif',
        '/images/iconHat.gif',
        '/images/iconHeart.gif',
        '/images/iconHorseshoe.gif',
        '/images/iconIreland.gif',
        '/images/iconKilt.gif',
        '/images/iconLightning.gif',
        '/images/iconStick.gif',
        '/images/iconSun.gif',
        '/images/iconUnicorn.gif'
    ],
    selectors: {
        preview: '.preview',
        input: '#wishImage',
        list: '.iconList'
    }
});

/**
 * Image Preloader
 * Accepts a single or array of image source strings, preloads them and fires events.
 */
var Preloader = function(overlay) {
    this.cache = [];
    this.loading = false;
    
    if(overlay) {
        this.els = {
            overlay: $(Preloader.selectors.overlay),
            container: $(Preloader.selectors.loadingBox)
        };
        
        $(document).bind('stage:ready', this.hide.useEL(this));
        
        this.show();
    }
};
$.extend(Preloader.prototype, {
   _load: function(source) {
       //if($.inArray(source, this.cache)) {
       //    $(this).trigger('loaded');
       //    return;
       //}
       
       var image = new Image();
       
       image.onload = function() {
           this.cache.push(image.src);
           $(this).trigger('loaded');
       }.use(this);
       
       image.onerror = function() {
           $(document).trigger('error', {image: source});
       }.use(this);
       
       this.loading = true;
       
       $(this).trigger('loading', {image: source});
       
       image.src = source;
   },
   load: function(sources) {
       var sources = $.makeArray(sources);
              
       var preCacheLength = this.cache.length;
       var l = sources.length;
              
       $(this).bind('loaded', function(event) {
           if(sources.length+preCacheLength == this.cache.length) {
               $(this).trigger('complete');
           }
       }.useEL(this));
       
       $(this).bind('error', function(event) {
           $(document).trigger('error', {message: Preloader.strings.error})
       }.useEL(this));
       
       while(l--) {
           this._load(sources[l]);
       }
   },
   setPosition: function() {
       var leftCenter = Math.round(($(window).width()/2)-(this.els.container.width()/2));
       var topCenter = Math.round(($(window).height()/2)-(this.els.container.height()/2));
       
       this.els.container.css({ 'top': topCenter+'px', 'left': leftCenter+'px' });
   },
   show: function() {
       this.els.overlay.show();
       this.setPosition();
       this.els.container.show();
   },
   hide: function() {
       setTimeout(function() {
           this.els.overlay.fadeOut(2000)
           if($.support.opacity) {
               this.els.container.fadeOut(2000)
           } else {
               this.els.container.hide()
           }
       }.use(this), Preloader.minTimeout);
   }
});
$.extend(Preloader, {
    strings: {
        error: 'Error loading images. Please reload this page to try again.'
    },
    selectors: {
        overlay: '#overlay',
        loadingBox: '#loadingBox' 
    },
    minTimeout: 1000,
    init: function() {
        Preloader.instance = new Preloader(true);
    }
});

/**
 * Wish
 * Each instance of a wish from the database
 * @param id        {number}    Used to differentiate elements by HTML ID attribute.
 * @param icon      {string}
 * @param message   {string}
 * @param toName    {string}
 * @param fromName  {string}
 * @param loadNum   {number}    Used to determine how long until the icon will fade in.
 */
var Wish = function(id, icon, message, toName, fromName, loadNum, force) {
    var now = new Date();
    this.origID = id;
    this.id = id+now.valueOf();
    this.container = $(Wish.selectors.container);
    this.icon = icon;
    this.message = message;
    this.names = { to: toName, from: fromName };
    this.loadNum = loadNum;
    this.forceCenter = force;
    
    this.load();
};
$.extend(Wish.prototype, {
    load: function() {
        var p = new Preloader();
        
        $(p).bind('complete', this.show.useEL(this));
        
        p.load(this.icon);
    },
    show: function() {
        var image = new Image();
        image.src = this.icon;
        $(image).attr('id', 'wish'+this.id)
        
        var location = (!this.forceCenter) ? Controller.instance.stage.getRandomLocation(image.width) : Controller.instance.stage.getCenter(image.width);
        
        setTimeout(function() {
            this.container.append(image);
            
            if($.support.opacity) {
                this.el = $('#wish'+this.id).css({ top: location.top+'px', left: location.left+'px', opacity: 0 }).animate({ top: location.top+20+'px', opacity: 1 }, 1000, 'easeOutSine', function() {
                    if(this.forceCenter) {
                        this.toggleInfoWindow();
                    }
                }.use(this));
            } else {
                this.el = $('#wish'+this.id).css({ top: location.top+'px', left: location.left+'px' }).hide().animate({ top: location.top+20+'px' }, 1000, 'easeOutSine').show();
                if(this.forceCenter) {
                    this.toggleInfoWindow();
                }
            }
            
            this.el.bind('click', this.toggleInfoWindow.useEL(this))
                   .bind('mouseover', this.dummy.useEL(this))
                   .bind('mouseout', this.dummy.useEL(this));
        }.use(this), this.loadNum*1000);
        
    },
    hide: function(callback) {
        var callback = (callback) ? callback : function() {};
        if(this.infoWindow && this.infoWindow.visible) { return; } else {
            setTimeout(function() {
                if(this.infoWindow) { this.infoWindow.kill(); }
                var newTop = (this.el.css('top')) ? parseInt(this.el.css('top').replace('px', ''), 10)+20 : 0;
                
                function endAnimation() {
                    this.el.remove();
                    callback();
                }
                
                if($.support.opacity) {
                    this.el.animate({ top: newTop+'px', opacity: 0 }, 500, 'easeInSine', endAnimation.use(this));
                } else {
                    this.el.animate({ top: newTop+'px' }, 500, 'easeInSine', endAnimation.use(this)).hide();
                }
                
            }.use(this), this.loadNum*1000);
        }
    },
    toggleInfoWindow: function() {
        if(!this.infoWindow) { 
            var left = this.el.css('left').replace('px', '');
            var top = this.el.css('top').replace('px', '');
            this.infoWindow = new InfoWindow({
                topOffset: top, leftOffset: left, 
                width: this.el.width(), height: this.el.height()
            }, {id: this.id, origID: this.origID, message: this.message, names: this.names}); 
        }

        this.infoWindow.toggle();
    },
    dummy: function() {
        
    }
});
$.extend(Wish, {
    selectors: {
        container: '#wishes'
    }
});

/**
 * InfoWindow
 */
var InfoWindow = function(dimensions, data) {
    this.data = data;
    this.dimensions = dimensions;
    this.els = {
        container: $(InfoWindow.selectors.container).clone().attr('id', 'wish'+this.data.id).hide().appendTo('body')
    };
    $.extend(this.els, {
        content: this.els.container.find(InfoWindow.selectors.content),
        closeBtn: this.els.container.find(InfoWindow.selectors.closeBtn),
        sendBtn: this.els.container.find(InfoWindow.selectors.sendBtn),
        nameTo: this.els.container.find(InfoWindow.selectors.nameTo),
        nameFrom: this.els.container.find(InfoWindow.selectors.nameFrom),
        message: this.els.container.find(InfoWindow.selectors.message),
        form: this.els.container.find(InfoWindow.selectors.form).attr('id', ''),
        formMessage: this.els.container.find(InfoWindow.selectors.formMessage).attr('id', ''),
        confirm: this.els.container.find(InfoWindow.selectors.confirm),
        confirmName: this.els.container.find(InfoWindow.selectors.confirmName)
    });
    this.form = new Form(this.els.container, true);
    this.position = dimensions;
    this.visible = false;
    this.populateData();
};
$.extend(InfoWindow.prototype, {
    toggle: function() {
        if(!this.visible) {
            this.show();
            if(pageTracker) {
                pageTracker._trackPageview('/wishes/view/'+this.data.origID);
            }
        } else {
            this.hide();
        }
    },
    getScrollElement: function() {
        var scrollElement = 'html, body';
        $('html, body').each(function () {
            var initScrollLeft = $(this).scrollLeft();
            $(this).scrollLeft(initScrollLeft + 1);
            if ($(this).scrollLeft() == initScrollLeft + 1) {
                scrollElement = this.nodeName.toLowerCase();
                $(this).scrollLeft(initScrollLeft);
                return false;
            }    
        });
        this.els.scrollElement = $(scrollElement);
    },
    setPosition: function() {
        if(!this.els.scrollElement) { this.getScrollElement(); }
        var topOffset = parseInt(this.dimensions.topOffset, 10);
        var leftOffset = parseInt(this.dimensions.leftOffset, 10);

        if(this.els.container.height()+topOffset >= this.els.scrollElement.scrollTop()+$(window).height()) {
            topOffset = topOffset-this.els.container.height()+this.dimensions.height;
        }
        
        if(this.els.container.width()+leftOffset >= this.els.scrollElement.scrollLeft()+$(window).width()) {
            leftOffset = leftOffset-this.els.container.width()+this.dimensions.width;
        }
        
        this.els.container.css({ left: leftOffset+'px', top: topOffset+'px' });
    },
    populateData: function() {
        this.els.message.text(this.data.message);
        this.els.nameFrom.text(this.data.names.from);
        this.els.nameTo.text(this.data.names.to);
        this.els.formMessage.attr('value', this.data.message);
    },
    show: function() {
        $(document).trigger('showWindow');
        this.hideForm();
        this.setPosition();
        
        var callback = function() {
            this.visible = true;
            $(document).bind('showWindow', this.hide.useEL(this));
            this.els.closeBtn.bind('click', this.hide.useEL(this));
            this.els.sendBtn.bind('click', this.showForm.useEL(this));
        }.use(this);
        
        if($.support.opacity) {
            this.els.container.fadeIn(500, callback.use(this));
        } else {
            this.els.container.show();
            callback();
        }
    },
    hide: function(event) {
        if(event) { event.stop(); }
        
        var callback = function() {
            this.hideForm();
            this.els.container.hide();
            this.visible = false;
        }.use(this);
        
        if($.support.opacity) {
            this.els.container.fadeOut(500, callback.use(this));
        } else {
            this.els.container.hide();
            callback();
        }
    },
    kill: function() {
        if(!this.visible) {
            this.els.container.remove();
        } else {
            return false;
        }
    },
    showForm: function(event) {
        if(event) { event.stop(); }
  
        if($.support.opacity) {
            this.els.content.fadeOut(500);
            this.els.form.fadeIn(500);
            this.els.confirm.fadeOut(500);
        } else {
            this.els.confirm.hide();
            this.els.content.hide();
            this.els.form.show();
        }
                
        $(document).trigger('form:show');
                
        $(document).bind('wish:share', this.showConfirm.useEL(this));
    },
    hideForm: function(event) {
        if(event) { event.stop(); }

        this.els.content.show();
        this.els.form.hide();
        this.els.confirm.hide();

        $(document).trigger('form:hide');
    },
    showConfirm: function(event, event2, data) {
        if(event) { event.stop(); }
        
        $(document).unbind('wish:share');
        $(document).trigger('form:hide');
        
        this.els.confirmName.text(data[0]['data[Wish][to_name]']);
        
        if($.support.opacity) {
            this.els.content.fadeOut(500);
            this.els.form.fadeOut(500);
            this.els.confirm.fadeIn(500);
        } else {
            this.els.confirm.show();
            this.els.content.hide();
            this.els.form.hide();
         }
    }
});
$.extend(InfoWindow, {
    selectors: {
        container: '#infoWindow',
        content: '.content',
        closeBtn: '.close',
        sendBtn: '.send',
        nameTo: '.to',
        nameFrom: '.from',
        message: '.message',
        form: 'form',
        confirm: '.shared',
        confirmName: '.name',
        formMessage: 'input[name$="[message]"]'
    }
})

/**
 * Stage
 * Controls the parallax effects
 */
var Stage = function() {
    this.els = {
        container: $(Stage.selectors.container),
        leftBtn: $(Stage.selectors.leftBtn),
        rightBtn: $(Stage.selectors.rightBtn)
    };
    this.getScrollElement();
    
    this.layers = [];
    
    this.setSize();
    $(window).bind('resize', this.setSize.useEL(this));
    
    this.els.leftBtn.bind('click', this.panLeft.useEL(this));
    this.els.rightBtn.bind('click', this.panRight.useEL(this));
    $(document).bind('keydown', this.keyHandler.useEL(this));
    
    $(document).bind('form:show', this.disablePanButtons.useEL(this));
    $(document).bind('form:hide', this.enablePanButtons.useEL(this));
};
$.extend(Stage.prototype, {
    keyHandler: function(event) {
        switch(event.keyCode) {
            case 37:
                if(this.ablePanLeft) {
                    this.panLeft(event);
                }
            break;
            case 39:
                if(this.ablePanRight) {
                    this.panRight(event);
                }
            break;
        }
    },
    load: function() {
        var loader = new Preloader();
        var sources = $.map(Stage.layers, function(i) { return i.src; });
        
        $(loader).bind('complete', this.appendToEls.useEL(this));
        
        loader.load(sources);
    },
    appendToEls: function() {
        var self = this;
        $(Stage.layers).each(function() {
            self.els.container.append('<div id="'+this.id+'" style="background-image: url('+this.src+');"></div>');
            //$('#'+this.id).css({ backgroundPosition: '(0px 0px)'});
            self.layers.push(this);
        });
        $(document).trigger('stage:ready');
    },
    show: function() {
        this.els.container.fadeIn(500);
    },
    getRandomLocation: function(offset) {
        var offset = (offset) ? offset : 0;
        var width = this.els.container.width();
        var height = this.els.container.height();
        
        var leftOffset = Math.round(width*(Math.random()));
        leftOffset = (leftOffset+(offset*2) > width) ? leftOffset-+(offset*2) : leftOffset;
        leftOffset = (leftOffset-offset < 0) ? leftOffset+offset : leftOffset;
        leftOffset = (leftOffset < Stage.iconPadding.left) ? Stage.iconPadding.left+leftOffset : leftOffset;
        leftOffset = (leftOffset > width+Stage.iconPadding.right) ? leftOffset-Stage.iconPadding.right : leftOffset;
        
        var topOffset = Math.round(height*(Math.random()));
        topOffset = (topOffset+(offset*2) > height) ? topOffset-+(offset*2) : topOffset;
        topOffset = (topOffset-offset < 0) ? topOffset+offset : topOffset;
        topOffset = (topOffset < Stage.iconPadding.top) ? Stage.iconPadding.top+topOffset : topOffset;
        topOffset = (topOffset > height+Stage.iconPadding.bottom) ? topOffset-Stage.iconPadding.bottom : topOffset;
                
        return { left: leftOffset, top: topOffset };
    },
    getCenter: function(offset) {
        var windowCenterLeft = Math.round($(window).width()/2)+$(window).scrollLeft();
        var windowCenterTop  = Math.round($(window).height()/2)+$(window).scrollTop();
        
        return { left: windowCenterLeft, top: windowCenterTop };
    },
    setSize: function(event) {
        this.els.container.width($(window).width()*3).height($(window).height());
        this.togglePanButtons();
        //if(!event) {
        //    if(!this.els.scrollElement) { this.getScrollElement(); }
        //    this.els.scrollElement.scrollLeft((this.els.container.width()/2)-($(window).width()/2))
        //}
    },
    getScrollElement: function() {
        var scrollElement = 'html, body';
        $('html, body').each(function () {
            var initScrollLeft = $(this).scrollLeft();
            $(this).scrollLeft(initScrollLeft + 1);
            if ($(this).scrollLeft() == initScrollLeft + 1) {
                scrollElement = this.nodeName.toLowerCase();
                $(this).scrollLeft(initScrollLeft);
                return false;
            }    
        });
        this.els.scrollElement = $(scrollElement);
    },
    panLeft: function(event) {
        event.stop();
        this.els.leftBtn.unbind('click').bind('click', function(event) { event.stop(); });
        this.getScrollElement();
        var leftPos = Math.floor(this.els.scrollElement.scrollLeft()-($(window).width()/2));
        this.pan(leftPos);
    },
    panRight: function(event) {
        event.stop();
        this.els.rightBtn.unbind('click').bind('click', function(event) { event.stop(); });
        this.getScrollElement();
        var leftPos = Math.ceil(this.els.scrollElement.scrollLeft()+($(window).width()/2))-1;
        this.pan(leftPos);
    },
    pan: function(leftPos) {
        this.scrollLeft = this.els.scrollElement.scrollLeft();
        this.panTimer = setInterval(function() {
            this.parallax();
        }.use(this), 50);
        this.els.scrollElement.animate({ scrollLeft: leftPos+'px' }, 2000, 'easeInOutSine', function() {
            this.togglePanButtons();
            clearInterval(this.panTimer);
        }.use(this));
    },
    disablePanButtons: function(override) {
        if(this.els.scrollElement.scrollLeft()+$(window).width() >= this.els.container.width()-($(window).width()/3) || override) {
            this.ablePanRight = false;
            if($.support.opacity)  {
                this.els.rightBtn.fadeOut(500);
            } else {
                this.els.rightBtn.hide();
            }
        }
        if(this.els.scrollElement.scrollLeft() <= 0 || override) {
            this.ablePanLeft = false;
            if($.support.opacity)  {
                this.els.leftBtn.fadeOut(500);
            } else {
                this.els.leftBtn.hide();
            }
        }
    },
    enablePanButtons: function() {
        if(this.els.scrollElement.scrollLeft()+$(window).width() < this.els.container.width()-($(window).width()/3)) {
            this.ablePanRight = true;
            if($.support.opacity)  {
                this.els.rightBtn.fadeIn(500).bind('click', this.panRight.useEL(this));
            } else {
                this.els.rightBtn.show().bind('click', this.panRight.useEL(this));
            }
        }
        if(this.els.scrollElement.scrollLeft() > 0) {
            this.ablePanLeft = true;
            if($.support.opacity)  {
                this.els.leftBtn.fadeIn(500).bind('click', this.panLeft.useEL(this));
            } else {
                this.els.leftBtn.show().bind('click', this.panLeft.useEL(this));
            }
        }
    },
    togglePanButtons: function() {
        this.disablePanButtons();
        this.enablePanButtons();
    },
    parallax: function() {
        var scrollLeft = this.els.scrollElement.scrollLeft();
        var diff = this.scrollLeft-scrollLeft;
        $(this.layers).each(function() {
            var el = $('#'+this.id);

            var leftPos = (el.css('backgroundPosition')) ? parseInt(el.css('backgroundPosition').split(' ')[0], 10) : Number(0);
            $('#'+this.id).css({'backgroundPosition': (Math.ceil(diff*this.speed)-diff)+leftPos+'px 0px' });
        });
        this.scrollLeft = this.els.scrollElement.scrollLeft();
    }
});
$.extend(Stage, {
    layers: [
        { id: 'rainbowLeft',    src: '/images/rainbow-left.gif',    speed: 1.0 },
        { id: 'rainbowRight',   src: '/images/rainbow-right.gif',   speed: 1.0 },
        { id: 'cloud1',         src: '/images/cloud-1.gif',         speed: 0.5 },
        { id: 'cloud2',         src: '/images/cloud-2.gif',         speed: 0.6 },
        { id: 'cloud3',         src: '/images/cloud-3.gif',         speed: 0.5 },
        { id: 'cloud4',         src: '/images/cloud-4.gif',         speed: 0.7 },
        { id: 'cloud5',         src: '/images/cloud-5.gif',         speed: 0.8 },
        { id: 'foreground2',    src: '/images/foreground-2.gif',    speed: 0.6 },
        { id: 'foreground1',    src: '/images/foreground-1.gif',    speed: 1.0 }
    ],
    selectors: {
        container: '#stage',
        leftBtn: '#stageLeft',
        rightBtn: '#stageRight'
    },
    iconPadding: {
        top: 200,
        right: 50,
        bottom: 115,
        left: 50
    }
});

$(document).ready(function() {
    Preloader.init();
    Controller.init();
    
    var logoTimer;
    $('h1 a').css({'opacity': 0}).bind('mouseover', function() {
        if(logoTimer) { clearTimeout(logoTimer); }
        if($.support.opacity) {
            $(this).stop().siblings('span').fadeOut(1000);
            $(this).stop().animate({'opacity': 1}, 1000);
        } else {
            $(this).siblings('span').hide();
            $(this).css({'opacity': 1, 'backgroundColor': '#FFF'});
        }
    }).bind('mouseout', function() {
        logoTimer = setTimeout(function() {
            if($.support.opacity) {
                $(this).stop().siblings('span').fadeIn(1000);
                $(this).stop().animate({'opacity': 0}, 1000);
            } else {
                $(this).siblings('span').show();
                $(this).css({'opacity': 0});
            }
        }.use(this), 1000);
    })
});
