/**
 * $Id: application.js 95 2010-03-25 23:12:21Z ihorton $
 */
/*********************************************************
 * Global
 *********************************************************/
var com_xsorb = {};
com_xsorb.namespace = "com.xsorb";

/*********************************************************
 * Base
 *********************************************************/
com_xsorb.Base = Class.create({
	initialize : function() {
	},
	/**
	 * Return an element by object or id
	 * @return HTMLObject
	 */
	elementByObjectOrId: function(element) {
		return (Object.isElement(element)) ? element : $(element);
	}
});

/*********************************************************
 * Extend Element
 *********************************************************/
Element.addMethods( { 
	toHTML: function(element) {
		if (typeof element=='string') element = $(element);  // IE needs that check with XML
		return Try.these(
			function() {
				var xmlSerializer = new XMLSerializer();
				return  element.nodeType == 4 ? element.nodeValue : xmlSerializer.serializeToString(element);
			},
			function() {
				return element.xml || element.outerHTML || $(element).clone().wrap().up().innerHTML;
			}
		) || '';
	}, 
	getStyles: function(element) {
		element = $(element);
		return $A(element.style).inject({}, function(styles, styleName) {
			styles[styleName.camelize()] = element.getStyle( styleName );
			return styles;
		});
	}, 
	clone: function(element) {
		element = $(element);
		var clone = new Element(element.tagName);
		$A(element.attributes).each(function(attribute) { 
			if( attribute.name != 'style' ) clone.setAttribute(attribute.name,attribute.value); 
		});
		clone.setStyle( element.getStyles() );
		clone.update(element.innerHTML);
		return clone;
	}
}); 

/*********************************************************
 * Utility
 *********************************************************/
com_xsorb.util = {};

/**********************************************************
 * Logging
 *********************************************************/
com_xsorb.util.Logger = Class.create({
    /**
     * Constructor
     * @param String namespace
     * @param Number level
     */
    initialize: function(namespace, level) {
        this.namespace = (Object.isString(namespace)) ? namespace : com_xsorb.namespace;
        this.level = (Object.isNumber(level)) ? level : 0;
    },
    /**
     * Console level setter
     * @param Number level
     */
    setLevel: function(level) {
        this.level = level;
    },
    /**
     * Write a LOG level message
     * @param String message
     */
    log: function(message) {
        this._write("LOG: " + this.namespace + " - " + message, 1);
    },
    /**
     * Write a INFO level message
     * @param String message
     */
    info: function(message) {
        this._write("INFO: " + this.namespace + " - " + message, 2);
    },
    /**
     * Write a WARN level message
     * @param String message
     */
    warn: function(message) {
        this._write("WARN: " + this.namespace + " - " + message, 3);
    },
    /**
     * Write a ERROR level message
     * @param String message
     */
    error: function(message) {
        this._write("ERROR: " + this.namespace + " - " + message, 4);
    },
    /**
     * Console writer
     * @param String message
     * @param Number level
     */
    _write: function(message, level) {
        if (!Object.isUndefined(console) && this.level >= level) {
            switch (level) {
                case 1:
                    console.log(message);
                    break;
                case 2:
                    console.info(message);
                    break;
                case 3:
                    console.warn(message);
                    break;
                case 4:
                    console.error(message);
                    break;
                default:
                    break;
            }
        }
    }
});
/**********************************************************
 * UI
 **********************************************************/
com_xsorb.ui = {};
/**********************************************************
 * UI : Rotator (for Spotlight)
 **********************************************************/
com_xsorb.ui.Rotator = Class.create(com_xsorb.Base, {
	/**
	 * Constructor
	 * @param HTMLElement element
	 * @param Array args
	 */
	initialize: function($super, element, nav, args) {
		// container element or id
		// see com_xsorb.Base.elementByObjectOrId
		this.rotator = this.elementByObjectOrId(element);
		// slide elements
		this.slides = this.rotator.childElements();
		// total slide
		this.iterations = this.slides.length;
		// current slide
		this.iteration = 0;
		// interal id
		this.interval = null;
		// state
		this.isRotating = false;
		// Animating (Don't Interrupt)
		this.running = false;
		this.flagOver = false;
		this.flagOverNav = false;

		// Navigation
		this.nav = this.elementByObjectOrId(nav);
		this.navNext = this.nav.select("#"+nav+"-next")[0];
		this.navPrev = this.nav.select("#"+nav+"-prev")[0];
		this.navPlayPause = this.nav.select("#"+nav+"-playpause")[0];
		this.navPause = this.nav.select("#"+nav+"-playpause")[0].down(0);
		this.navPlay = this.nav.select("#"+nav+"-playpause")[0].down(1);
		this.navPlay.setStyle({"display": "none"});
        // process args
        if (args) {
            this.delay = (Object.isNumber(args.delay)) ? args.delay : 5;
            this.duration = (Object.isNumber(args.duration)) ? args.duration : 1;
        } else {
            this.delay = 5;
            this.duration = 1;
        }

        // Pick Random Start
        this.iteration = Math.floor(Math.random()*this.iterations);
        // set default object visibility
        this.slides[this.iteration].show();
        /**
        this.slides.each(function(node) {
            (this.iteration > 0) ? node.hide() : node.show();
            this.iteration++;
        }.bind(this));
         */
        //this.iteration = 0;
        if (this.slides.length > 1) {
            this.start();
        }
		this.bindEvents();    
    },
    /**
     * Start the rotator
     */
    start: function() {
        this.isRotating = true;
        this.interval = this.advance.bind(this).delay(this.delay);
    },
    /**
     * Stop the rotator
     */
    stop: function() {
        this.isRotating = false;
        this._clear();
    },
    /**
     * Toggle the rotator
     */
    toggle: function() {
        (this.isRotating) ? this.stop() : this.start();
    },
   /**
     * Advance 1 slide
     */
    advance: function() {
		if(!this.running){
			this.running=true;
    	    this._clear();
    	    this._hide();
    	    this.iteration++;
    	    if (this.iteration >= this.slides.length) {
    	        this.iteration = 0;
    	    }
    	    this._show();
    	    if(this.isRotating)this.interval = this.advance.bind(this).delay(this.delay);
			this.running=false;
		}
    },
    /**
     * Rewind 1 slide
     */
    rewind: function() {
		if(!this.running){
			this.running=true;
	        this._clear();
	        this._hide();
	        this.iteration--;
	        if (this.iteration < 0) {
	            this.iteration = (this.slides.length - 1);
	        }
	        this._show();
			if(this.isRotating)this.interval = this.advance.bind(this).delay(this.delay);
			this.running=false;
		}
    },
	/**
	 * Mouse Over Stuff
	 */
    onMouseOver : function() {
		this.flagOver = true;
//		if(this.isRotating) this.stop();
		this.navShow();
    },
	onMouseOut : function() {
		this.flagOver = false;
//		if(!this.isRotating) this.start();
		this.navHide();
	},
	navOver : function() {
		this.flagOverNav = true;
		this.navShow();
	},
	navOut : function() {
		this.flagOverNav = false;
		this.navHide();
	},
	navHide : function() {
		this.nav.setStyle({"visibility": "hidden"});
		//Effect.Fade(this.nav, { duration: this.duration });
	},
	navShow : function() {
		this.nav.setStyle({"visibility": "visible"});
		//Effect.Appear(this.nav, { duration: this.duration });
	},
	navPlayPauseClick : function() {
		this.toggle();
		if(this.isRotating){
			this.navPlay.setStyle({"display": "none"});
			this.navPause.setStyle({"display": "inline"});
		} else {
			this.navPause.setStyle({"display": "none"});
			this.navPlay.setStyle({"display": "inline"});
		}
	},
	navNextClick : function() {
		this.advance();
	},
	navPrevClick : function() {
		this.rewind();
	},
    /**
     * Clear the current interval
     */
    _clear: function() {
        if (!Object.isUndefined(this.interval)) {
            window.clearTimeout(this.interval);
        }
    },
    /**
     * Show the current slide
     */
    _show: function() {
        if (Object.isElement(this.slides[this.iteration])) {
            Effect.Appear(this.slides[this.iteration], { duration: this.duration });
        }
    },
    /**
     * Hide the current slide
     */
    _hide: function() {
        if (Object.isElement(this.slides[this.iteration])) {
            Effect.Fade(this.slides[this.iteration], { duration: this.duration });
        }
    },
	/**
	 * Bind Events
	 */
    bindEvents : function() {
        this.rotator.observe("mouseover", this.onMouseOver.bind(this));
        this.rotator.observe("mouseout", this.onMouseOut.bind(this));
		this.nav.observe("mouseover", this.navOver.bind(this));
		this.nav.observe("mouseout", this.navOut.bind(this));
		this.navPrev.observe("click", this.navPrevClick.bind(this));
		this.navNext.observe("click", this.navNextClick.bind(this));
		this.navPlayPause.observe("click", this.navPlayPauseClick.bind(this));
    }
});
/**********************************************************
 * UI : Carousel (for Features)
 **********************************************************/
com_xsorb.ui.Carousel = Class.create(com_xsorb.Base, {
	initialize: function($super, container, element, prev, next, args){
		//this.debug = this.elementByObjectOrId("debug")
		//this.debug.update(this.carousel);
		this.carouselParent = this.elementByObjectOrId(container);
		this.btnPrev = this.elementByObjectOrId(prev);
		this.btnNext = this.elementByObjectOrId(next);
		this.btnPrev.observe("click", this.clickPrev.bind(this));
		this.btnNext.observe("click", this.clickNext.bind(this));

		this.delay = 6;				// Seconds to Delay between Scroll

		this.visible = 4;			// Number of Features Visible at once
		this.start = 0;				// Start at Feature 0
		this.scroll = 1;			// Scroll One at a Time

		this.circular = true;		// Loop around (always move one direction)
		this.direction = true;		// Used if Circular is False
		this.running = false;

		if(this.circular) {			// If Circular, have to pad both sides by visible slides so we have room to Loop
			var l = $(element).childElements().length;
			var i = l-this.visible + 1;
			for(i; i<=l; i++){
				$(element).insert({top : $(element).childElements()[l-1].clone()}); 	// Clones to Beginning
			}
			for(i=this.visible; i < this.visible*2; i++){
				$(element).appendChild($(element).childElements()[i].clone());			// Clones to End
			}
			this.start+=this.visible;
        }
		this.carousel = this.elementByObjectOrId(element);
		this.slides = this.carousel.childElements();
		this.curr = this.start;
        this.carouselParent.setStyle({"visibility": "visible"});

        this.carousel.setStyle({overflow: "hidden", 'float':"left", margin: "0", padding: "0", height:"156px", position: "relative", "z-index": "-1"});
        this.carouselParent.setStyle({overflow: "hidden", 'float':"left", position: "relative", "z-index": "2", left: "0px"});
		var slideWidth   = this.slides[0].getWidth();									// Full slide size(incl margin)-Used for animation
		this.slideWidth = slideWidth;
		var slideHeight  = this.slides[0].getHeight();			
        var carouselSize = this.slideWidth * this.slides.length;						// size of full carousel (total length, not just for the visible items)
        var parentSize   = this.slideWidth * this.visible;								// size of container div (total length for just the visible items)
		this.slides.each(function(s, index){
			s.setStyle({overflow: "hidden", "visibility": "visible", 'float': "left", width: slideWidth, height: slideHeight, "z-index":"-2" });
		});		
        this.carouselParent.setStyle({width: parentSize+"px"});                     	// Width of the container div. length of visible images
        this.carousel.setStyle({width: carouselSize+"px", left: -(this.curr*this.slideWidth)+"px"});
		this.interval = this.autoNext.bind(this).delay(this.delay);
	},
	autoNext: function(){
		if(this.direction)	this.go(this.curr+this.scroll);
		else 				this.go(this.curr-this.scroll);
	},
	clickPrev: function(){
		this.go(this.curr-this.scroll);
	},
	clickNext: function(){
		this.go(this.curr+this.scroll);
	},
	go: function(to){
		window.clearTimeout(this.interval);

		if(!this.running){
			this.running=true;
			if(this.circular){
				if(to <= this.start - this.visible - 1) {					// If first, then goto last
					this.carousel.setStyle({left: -((this.slides.length-(this.visible*2))*this.slideWidth)+"px"});
					this.curr = to==curr.start - this.visible - 1 ? this.slides.length - (this.visible*2) - 1 : this.slides.length-(this.visible*2) - this.scroll;
				} else if(to >= this.slides.length - this.visible + 1) { 	// If last, then goto first
					this.carousel.setStyle({left: -( (this.visible) * this.slideWidth ) + "px" });
					this.curr = to==this.slides.length - this.visible + 1 ? this.visible + 1 : this.visible + this.scroll;
				} else this.curr = to;
			} else {
				if(this.direction){		// going Right
					if(to < 0)running=false;
					else if(to > this.slides.length - this.visible) { this.direction = !this.direction; }
					else { this.curr = to; }
				} else {				// going Left
					if(to > this.slides.length - this.visible)running=false;
					else if(to < 0) { this.direction = !this.direction; }
					else { this.curr = to; }
				}
			}
			if(this.running){
				var newPosition = this.curr * this.slideWidth;
				if(newPosition == 0)newPosition = 1;
				this.carousel.morph('left:-'+newPosition+"px");
				this.running=false;
			}
		}
		this.interval = this.autoNext.bind(this).delay(this.delay);
	}
});
/**********************************************************
 * UI : MenuList (for DropDown Menus)
 **********************************************************/
com_xsorb.ui.MenuList = Class.create(com_xsorb.Base, {
    /**
     * Constructor
     * @param menuItem
     * @param menuList
     */
    initialize: function($super, menuItem, menuList) {
        /**
         * Element to trigger menu visibility
         */
        // container element or id
        // see com_xsorb.Base.elementByObjectOrId
        this.menuItem = this.elementByObjectOrId(menuItem);
        /**
         * Menu container
         */
        this.menu = this.elementByObjectOrId(menuList);
        /**
         * Timeout object
         */
        this.timeout = null;
        /**
         * Menu show/hide delay
         */
        this.delay = 0.10;
        /**
         * Trigger element active state css
         */
        this.activecss = "active";
        /**
         * Bind menu events
         */
        if (this.menuItem)
            this.bindEvents();
    },
    /**
     * Toggle menu
     */
    onClick : function() {
        this.timeout = this.showMenu.bind(this).delay(this.delay);
        return false;
    },
    /**
     *
     */
    onMouseOut : function() {
        this.timeout = this.hideMenu.bind(this).delay(this.delay);
    },
    /**
     *
     */
    onMouseOver : function() {
        window.clearTimeout(this.timeout);
    },
    /**
     *
     * @param o
     */
    hideMenu : function() {
        if (this.menu.visible()) {
            this.menu.hide();
            this.menuItem.toggleClassName(this.activecss);
        }
    },
    /**
     *
     * @param o
     */
    showMenu : function() {
        window.clearTimeout(this.timeout);
        this.menu.toggle();
        this.menuItem.toggleClassName(this.activecss);
    },
    /**
     * Observe menu events
     */
    bindEvents : function() {
        this.menu.childElements().each(function(node) {
            node.observe("mouseout", this.onMouseOut.bind(this));
            node.observe("mouseover", this.onMouseOver.bind(this));
        }.bind(this));
        this.menuItem.observe("click", this.onClick.bind(this));
        this.menuItem.href = "Javascript:void(0);";
        this.menuItem.observe("mouseover", this.onMouseOver.bind(this));
        this.menuItem.observe("mouseout", this.onMouseOut.bind(this));
    }
});
