MenuManager = Class.create({
    initialize: function(rootMenuDisplayNode, menuItemNodes, globalNavRoot, handlerUrl){  
        this.rootMenuNode = rootMenuDisplayNode;
        this.menuItemNodes = menuItemNodes;
        this.globalNavRoot = globalNavRoot;
        this.handlerUrl = handlerUrl;
        
        this.globalNavRoot.observe('mouseout', this.fade.bindAsEventListener(this));
        this.globalNavRoot.observe('mouseover', this.cancelFade.bindAsEventListener(this));
        this.rootMenuNode.observe('mouseout', this.fade.bindAsEventListener(this));
        this.rootMenuNode.observe('mouseover', this.cancelFade.bindAsEventListener(this));
        
        this.globalNavNodes = this.globalNavRoot.childElements().collect(function(n,i) { 
            return new NavItem(n, this.menuItemNodes[i], this); 
        }, this);
        
        this.rootMenuNode.hide();
        this.rootMenuNode.setStyle({position:'absolute', visibility:'visible'});
        
        this.scriptQueue = {scope: 'menu', position:'end'};
    },
    appear:function() {
        Effect.Appear(this.rootMenuNode, { duration: 0.1, queue:this.scriptQueue });
    },
    fade: function() {
        Effect.Fade(this.rootMenuNode, { duration: 0.3, queue:this.scriptQueue, afterFinish:this.reset.bindAsEventListener(this)});
    },
    reset: function() {
        this.globalNavNodes.each(function(n) { n.hideMenu(); });
    },
    clearAndAppear: function() {
        this.reset();
        this.appear();
    },
    cancelFade: function() {
        Effect.Queues.get('menu').invoke('cancel');
        if (this.globalNavNodes.find(function(n) { return n.shown; })) 
            this.appear();
    }
}); 
NavItem = Class.create({
    initialize:function(element, menuElement, manager) {
        if (menuElement) {
            this.element = $(element);
            this.manager = manager;
            this.menuElement = menuElement;
            this.inset = new UpdatePanel(this.menuElement.select('.update_panel')[0],this.manager.handlerUrl);
            this.menuElement.hide();
            this.menuElementTab = this.menuElement.select('a.topmost_link')[0];
            this.manager = manager;
            this.menuElement.select('a').each(function(n, i) { new AjaxMenuLink(n, this.inset); }, this)
            this.element.observe('mouseover', this.showMenu.bindAsEventListener(this));    
        }
    },
    showMenu: function() {
        this.manager.reset()
        this.shown = true;
        this.menuElement.show();
        //we need to touch the position property in IE or the tab will ghost.
        this.menuElementTab.setStyle({position:"absolute"});
        //ensures that the menuElementTab is positioned properly        
        if(!this.manager.rootMenuNode.visible()) {
            this.manager.rootMenuNode.show();
            this.menuElementTab.clonePosition(this.element);
            this.manager.rootMenuNode.hide();
        } else {
            this.menuElementTab.clonePosition(this.element);
        }
        
        this.menuElementTab.show();
        this.manager.appear();
        //fixes another IE bug
        window.setTimeout(function() { this.element.replace(this.element) }.bindAsEventListener(this), 300);
        
    },
    hideMenu: function() {
        if (this.menuElementTab){
            this.shown = false;
            this.menuElementTab.setStyle({position:"static"});
            this.menuElement.hide();
        }
    }
});

UpdatePanel = Class.create({
    initialize:function(element, handlerUrl) {
        this.element = $(element);
        this.handlerUrl = handlerUrl;
        this.computePadding();
        this.cache = {};
    },
    update: function(id) {
        if (this.previousRequestObject && !this.previousRequestObject._complete){
            this.previousRequestObject.cancelRequest();
        }
        if (typeof(this.cache[id]) == 'undefined'){ 
            this.previousRequestObject = new Ajax.TransientRequest(this.handlerUrl, 
                {'method':'GET', 'parameters':{ id:id, isExplore: this.element.up().id == 'explore', isPart : this.element.up().id == 'gear'}, 
                timeout:5000, 
                onLoading:this.showLoading.bindAsEventListener(this),
                onSuccess:this.loadMarkup.bindAsEventListener(this),
                onFailure:this.failure.bindAsEventListener(this),
                onException:function(r,e){ console.debug(r); console.error(e) }
            });
        }                
        else this.element.update(this.cache[id]);
    },
    showLoading: function(response){
        this.element.setStyle({height: this.element.getHeight() - this.verticalPadding + "px"});
        this.element.innerHTML = "";
        this.element.update(new Element('div').addClassName('loader'));
        this.element.addClassName('loading');
    },
    loadMarkup: function(response){
        if (response.responseText != ""){
            this.cache[response.request.parameters.id] = response.responseText;
                
            var buffer = new Element('div').setStyle({display:'none'}).update(response.responseText)
            var bufferImg = buffer.select('img.pic')[0];
            new Event.transientObserve(bufferImg, 'load', 
                this.releaseHold.bind({element:this.element,text:buffer.innerHTML}), 3000, function() {  }.bind(this)
            );
        } 
    },
    releaseHold: function() {
        this.element.setStyle({height: 'auto'});
        this.element.update(this.text);
        this.element.removeClassName('loading');
    },
    failure: function() {
        this.element.update("<h4>A network error has prevented the request from completing.  Please try again.</h4>");
    },
    computePadding:function () {
        var vpadding = [this.element.getStyle('padding-top'), this.element.getStyle('padding-bottom')];
        this.verticalPadding = vpadding.inject(0, function(acc, n) { return acc += Number(n.gsub('px','')); });
    }
});
AjaxMenuLink = Class.create({
    initialize:function(element, panel) {
        this.element = $(element);
        this.id = this.element.readAttribute('rel');
        if (this.id) {
            this.panel = panel;
            this.element.observe('mouseover', this.scheduleUpdate.bindAsEventListener(this));
            this.element.observe('mouseout', this.cancelUpdate.bindAsEventListener(this));
        }
    },
    scheduleUpdate:function(evt){
        this.execId = window.setTimeout(this.update.bindAsEventListener(this), 50);
    },
    cancelUpdate:function(evt){
        window.clearTimeout(this.execId);
    },
    update:function(){
        this.panel.update(this.id);
    }
});

Tab = Class.create({
    initialize:function(element, page, manager, selectedTabID) {
        this.element = $(element);  
        this.page = page;
        this.manager = manager;
        this.element.observe('click', this.markSelected.bindAsEventListener(this));
        this.element.select('a')[0].href = "javascript:;";
        if (this.element.id != '' && this.element.id == selectedTabID)
            this.markSelected();
    },
    markSelected:function(){
        this.manager.setActive(this);
        this.element.className += 'on'; 
        this.page.show();
    },
    deSelect:function() {
        this.element.className = this.element.className.sub('on','');
        this.page.hide();
    }
});


TabManager = Class.create({
    initialize: function(tabs, pages){
        var id = window.location.hash ? window.location.hash.substr(1) : "";
        this.tabs = tabs.collect(function(n, i) { return new Tab(n, pages[i], this, id)}, this);
        this.tabs.invoke('deSelect');
        
        if (this.activeTab)
            this.activeTab.markSelected();
        else this.tabs[0].markSelected();
    },
    setActive: function(tab){
        if (this.activeTab)
            this.activeTab.deSelect();
        this.activeTab = tab;
    }
});

//used currently in NewsMarquee
VerticalMarquee = Class.create({
    initialize: function(element) {
        this.element = $(element);
        if (this.element && this.element.childElements() && (this.element.childElements().length > 1)) {
            var options = {duration:1.5, afterFinish:this.waitAndScroll.bindAsEventListener(this),transition:Effect.Transitions.linear, 
                 queue: {scope: 'news', position:'end'}};
            this.items = new ScrollingCollection(this.element, this.element.childElements(), options);
            
            this.items.elements.each(function(n) {
                n.observe('mouseover', this.cancel.bindAsEventListener(this));
                n.observe('mouseout', this.unblock.bindAsEventListener(this));
            }, this);
            
            this.waitAndScroll();
        }
    },
    waitAndScroll: function() {
        if (!this.block) {
            this.execId = window.setTimeout(this.scroll.bindAsEventListener(this), 3000);
        }
    },
    unblock: function() {
        this.block = false;
        this.waitAndScroll();
    },
    cancel: function() {    
        window.clearTimeout(this.execId);
        this.block = true;
    },
    scroll:function() {
        this.items.next();
    }
});

//controls the homePromoCollection slider
PromotionManager = Class.create({
    initialize:function(viewport, scrollRightBtn, scrollLeftBtn){
        this.viewport = viewport;

        this.scrollRightBtn = scrollRightBtn;
        this.scrollLeftBtn = scrollLeftBtn;
        this.scrollRightBtn.observe('click', this.Cycle.bindAsEventListener(this));
        this.scrollLeftBtn.observe('click', this.Cycle.bindAsEventListener(this));
        
        this.allPromos = new ScrollingCollection(this.viewport, this.viewport.select(".homePromoImg, .homePromo"), 
            {duration:0.5, transition:Effect.Transitions.linear, queue:{scope: 'promos', position:'end'}}, 3);
    },
    Cycle: function(evt) {
        var btn = evt.findElement('a');
        if (btn == this.scrollLeftBtn)
            this.allPromos.next();
        else this.allPromos.prev();
    }
});

ScrollingCollection = Class.create({
    initialize:function(viewport, elements, options, simultaniouslyVisible){
        this.viewport = $(viewport);
        this.elements = $(elements);
        
        this.options = options;
        this.first = this.elements[0];
        this.specifiedCallback = this.options.afterFinish;
        this.busy = false;
        
        var elementsRoot = this.elements[0].up();
        
        if (simultaniouslyVisible){
            for (var i = this.elements.length; i < simultaniouslyVisible + 2; i++){
                this.elements.each(function(n) {
                    n.up().insert(n.cloneNode(true));
                });
            }
            this.elements = elementsRoot.childElements();
        }
        
        //rejiggers the collection to give it a buffer to move in either direction
        this.elements = this.elements.partition(
            function(n, i) {    
                return i < Math.floor(this.length / 2) + 2;
            }, this.elements).reverse().flatten();
        
/*        
        elementsRoot.update();
        this.elements.each(function(n){
            this.appendChild(n);  
        }, elementsRoot);
*/        
        
        if (this.first){
            this.elements = this.elements[0].up().graft(this.elements);
            this.syncViewport(this.first);
        }
    },
    next:function() {
        if (!this.busy){
            this.busy = true;
            var oldNode = this.elements.shift();
            this.elements.push(oldNode);
            this.elements = this.elements[0].up().graft(this.elements);
            
            var displacement = this.syncViewport(this.first);
            this.first = this.first.next();
            
            new Effect.Scroll(this.viewport, Object.extend(this.options,
                { x:(this.viewport.scrollLeft + displacement[0]), 
                  y:(this.viewport.scrollTop + displacement[1]),
                  afterFinish:this.free.bindAsEventListener(this) }));
        }
    },
    prev:function(){
        if (!this.busy) {
            this.busy = true;
                        
            var displacement = this.syncViewport(this.first);
            this.first = this.first.previous();
            
            new Effect.Scroll(this.viewport, Object.extend(this.options, 
                { x:(this.viewport.scrollLeft - displacement[0]), 
                  y:(this.viewport.scrollTop - displacement[1]),
                  afterFinish:this.prevCallback.bindAsEventListener(this) }));
        }
    },
    prevCallback: function(){
        var oldNode = this.elements.pop();
        this.elements = [oldNode].concat(this.elements);
        this.elements = this.elements[0].up().graft(this.elements);
        this.syncViewport(this.first);
        this.free();
    },
    free:function(){
        this.busy = false;
        if (this.specifiedCallback)
            this.specifiedCallback();
    },
    syncViewport:function(element) {
        this.viewport.scrollLeft = element.offsetLeft;
        this.viewport.scrollTop = element.offsetTop;
        return element.getDisplacement();
    }
});

//if Scriptaculous is loaded create the Scroll Effect
if (typeof(Effect) != 'undefined') {
    Effect.Scroll = Class.create(Effect.Base.prototype, {
      initialize: function(element) {
        this.element = $(element);
        var options = Object.extend({
          x:    0,
          y:    0,
          mode: 'absolute'
        } , arguments[1] || {}  );
        this.start(options);
      },
      setup: function() {
        this.originalLeft = this.element.scrollLeft;
        this.originalTop = this.element.scrollTop;
        if(this.options.mode == 'absolute') {
          this.options.x -= this.originalLeft;
          this.options.y -= this.originalTop;
        }
      },
      update: function(position) {   
        this.element.scrollLeft = this.options.x * position + this.originalLeft;
        this.element.scrollTop  = this.options.y * position + this.originalTop;
      }
    });
}
FormHelper = new function() {
    this.init = function() {
         $$('input.info_text').each(function(n) { n.observe('focus', FormHelper.selectAll) });;
    };
    this.selectAll =  function(evt) {
        element = evt.element();
        if (!element.cleared) {
            element.cleared = true;
            element.clear();
        }
    };
}
URLUtil = Class.create({
    initialize:function(basePath){
        this.basePath = basePath;    
    },
    resolveUrl:function(virtualPath) {
        return virtualPath.replace('~/', this.basePath);
    }
});
Ajax.TransientRequest = Class.create(Ajax.Request, { 
    initialize:function($super, url, options){
        if (options.onComplete) {
            options.onComplete = options.onComplete.wrap(
                function(old, that){
                    that.request.cancelCancel();
                    old.bindAsEventListener(that)();
                });
        } else{
            options.onComplete = this.cancelCancel.bind(this);
        }
        this.timeout = window.setTimeout(this.cancelRequest.bindAsEventListener(this), options.timeout);
        $super(url,options);
    },
    cancelRequest: function(){
        if (this.isActive()) {
            this.transport.abort();
            if (this.options.onFailure) {
                this.options.onFailure(this.transport, this.json);
            }
        }
    },  
    cancelCancel: function() {
        window.clearTimeout(this.options.timeout);
    },
    isActive : function () {
        switch (this.transport.readyState) {
            case 1: case 2: case 3:
            return true;
            break;
            // Case 4 and 0
            default:
            return false;
            break;
        }
    }
});
Object.extend(Event, {
    transientObserve:function(element, eventName, handler, timeSlice, onTimeout){
        onTimeout = onTimeout.wrap(
            function(old, that){
                Event.removeTransientObserver(element, eventName, handler);
                old.bind(that)();
            });
        element.transientTimeout = window.setTimeout(onTimeout.bind, timeSlice);
        Event.observe(element, eventName, handler);        
    },
    removeTransientObserver: function(element, eventName, handler) {
        window.clearTimeout(element.transientTimeout);
        Event.stopObserving(element,eventName,handler);
    }
});
Element.addMethods({
    isAdjacentSibling: function(element, anotherElement){
        element = $(element);
        return element.siblings().member(anotherElement) && (element.next() == anotherElement || element.previous() == anotherElement);
    },
    getDisplacement: function(element) {
        element = $(element);
        var marginLeft = element.getStyle('margin-left');
        var marginRight = element.getStyle('margin-right');
        var marginTop = element.getStyle('margin-top');
        var marginBot = element.getStyle('margin-bottom');
        return [element.getWidth() + (marginLeft != null ? Number(marginLeft.gsub('px','')) : 0) + 
                                     (marginRight != null ? Number(marginRight.gsub('px','')) : 0),
                element.getHeight()+ (marginTop != null ? Number(marginTop.gsub('px','')) : 0) + 
                                     (marginBot != null ? Number(marginBot.gsub('px','')) : 0) ];
    },
    graft: function(element, collection) {
        element = $(element);
        return collection.each(function(n) { this.insert(n); }, element);
    },
    transientObserve:Event.transientObserve,
    removeTransientObserver:Event.removeTransientObserver
});

Popup = new function() {
  this.open = function(options) {
    this.options = {
      url: '#',
      width: 977,
      height: 500,
      name:"_blank",
      location:"no",
      menubar:"yes",
      toolbar:"no",
      status:"no",
      scrollbars:"yes",
      resizable:"yes",
      left:"",
      top:"",
      normal:false
    }
    Object.extend(this.options, options || {});

    if (this.options.normal){
        this.options.menubar = "yes";
        this.options.status = "yes";
        this.options.toolbar = "yes";
        this.options.location = "yes";
    }

    this.options.width = this.options.width < screen.availWidth?this.options.width:screen.availWidth;
    this.options.height=this.options.height < screen.availHeight?this.options.height:screen.availHeight;
    var openoptions = 'width='+this.options.width+',height='+this.options.height+',location='+this.options.location+',menubar='+this.options.menubar+',toolbar='+this.options.toolbar+',scrollbars='+this.options.scrollbars+',resizable='+this.options.resizable+',status='+this.options.status
    if (this.options.top!="")openoptions+=",top="+this.options.top;
    if (this.options.left!="")openoptions+=",left="+this.options.left;
    window.open(this.options.url, this.options.name, openoptions);
    return false;
  }
}

PopupLinks = Class.create({
    initialize:function(){
        $$('.pop a, a.pop').each(
            function(n) {
                n.observe('click', this.onclick);
            },
            this
        );
    },
    onclick:function(evt){
        evt.stop();
        Popup.open({url:evt.findElement('a').href});
    }
});

new PopupLinks();
