
/**
 * @author raisch
 * $Id: loader.js 7999 2008-09-02 20:31:35Z raisch $
 * $HeadURL$
 */
if (typeof Prototype != 'object') 
    throw "requires Prototype.js";

/*
 * Toolbar Loader class
 */
// create our namespace
var CW = {
	/***** generally useful flags and such *****/
	$logging: false, // enable/disable logging (doesn't work on IE)
	$debug: false, // enable/disable debug messages, requires $logging
	$has_console: typeof console == 'object' && typeof console.log == 'function',
	
	/***** logging *****/
	log: function(m){
		m = (new Date()).toLocaleString() + " " + m;
		if (CW.$logging) {
			if (CW.$has_console) 
				console.log(m);
			//else $$('body').shift().insert({ "top": "<H4>" + m.escapeHTML() + "</H4>" });
		}
	},
	
	debug: function(m){
		CW.$debug && CW.log("DEBUG: " + m)
	},
	
	error: function(m){
		CW.log("ERROR: " + m)
	},
	
	extendElement: function(elt) { 
		var result = null;
		if( elt ) result = Object.extend(elt, CW.Element.Methods); 
		return result;
	},
	
	// element taxonomy
	kindOf: function(elt){ 	// Elements are "of a kind" if they have a class named "tb_(kind)"
		elt = $(elt);
		var result = "UNKNOWN";
		elt.classNames().each(function(name){
			if (name.startsWith('tb_')) {
				result = name.sub('^tb_', '');
				CW.debug("in Element.kindOf, " + elt.id + " is a " + result);
				throw $break;
			}
		});
		return result;
	},
	isKindOf: function(elt, kind){
		return kind == CW.kindOf(elt);
	},
	
	// global element functions
	hideAll: function( elts ) {
		$A(elts).each(function(elt){
			elt = $(elt);
			if( elt instanceof Element) elt.hide();
		});
	},
	removeHighlightAll: function( elts ) {
		$A(elts).each(function(elt){
			elt = CW.extendElement($(elt));
			if( elt instanceof Element) elt.removeHighlight();
		});
	}
};

// extend Hash
Hash.addMethods({
	// returns value from hash using a path
	getPath: function( path ) {
		var curr = this;
		CW.debug("Hash.getPath starting with '"+path+"'");
		$A(path.split('.')).each( function(part) {
			CW.debug("Hash.getPath getting part '"+part+"'");
			curr = $H(curr).get(part);
			if( ! curr ) throw $break;
		});
		return curr;
	}
});

CW.Element = {
	Methods: {
		// timers
		getTimer:function(){
			return this.$timer;
		},
		setTimer:function(t){
			CW.debug("Element.setTimer("+this.id+','+t+')');
			this.$timer = t;
			return this;
		},
		clearTimer:	function() { 
			if( this.$timer ) { 
				CW.debug("Element.clearTimer("+this.id+')');
				window.clearTimeout(this.$timer); 
				this.$timer = 0; 
			} 
			return this; 
		},
		
		// coordinates
		getCoords: function() {
			return $H(
				this.getDimensions()
			).merge(
				$H(this.cumulativeOffset())
			).toObject();
		},
		
		// highlighting
		addHighlight: function() {
			this.addClassName('tb_'+CW.kindOf(this)+'_highlight');
			return this;
		},
		removeHighlight: function() {
			this.removeClassName('tb_'+CW.kindOf(this)+'_highlight');
			return this;
		},
		
		// moving
		positionRelativeTo: function(target,offsetLeft,offsetTop) {
			
			source = CW.extendElement($(this));
			target  = CW.extendElement($(target));
			
			offsetTop = offsetTop || 0;
			offsetLeft = offsetLeft || 0;

			if ( target ) {
				CW.debug(
					"moving #{sid} relative to #{tid} using x,y:#{x},#{y}".interpolate(
						{ sid:source.id, tid:target.id, x:offsetLeft, y:offsetTop }
					)
				);
				var target_coords = target.getCoords();
				if (Prototype.Browser.IE) {
					source.setStyle({
						top: target_coords.top + offsetTop,
						left: target_coords.left + offsetLeft
					});
				}
				else {
					source.clonePosition(target, {
						setWidth: false,
						setHeight: false,
						offsetTop: offsetTop,
						offsetLeft: offsetLeft
					});
				}
				var coords = source.getCoords();
				CW.debug(
					"moved #{src} to x,y: #{x},#{y}".interpolate(
						{src: source.id, x: coords.left, y: coords.y}
					)
				);
			}
			return this;
		}
	}
};

CW.Element.Cache = Class.create({
    initialize: function() {
		this._buckets = $H({
        	button: $A(),
			subscribe: $A(),
        	menu: $A(),
			box_menu: $A(),
        	item: $A(),
        	box_item: $A()
    	});
	},
    kinds: function(){
        return $A($H(this._buckets).keys());
    },
    get: function(kind, id){
		var cache = this._buckets.get(kind);
        if (cache instanceof Array) {
            if (typeof id == 'string') {
                var result = null;
                cache.each(function(elt){
                    if (elt.id == id) {
                        result = elt;
                        throw $break;
                    }
                });
                return result;
            }
            else
				return cache;
        }
        throw "no such kind of cached element as '" + kind + "'";
    },
    contains: function(kind, id){
		return this.get(kind, id) != null;
    },
    add: function(kind, elt){
		elt = $(elt);
		var cache = this._buckets.get(kind);
        if (cache instanceof Array) {
	        if (!elt instanceof Element) throw "elt is not an Element";
	        if (!this.contains(kind, elt.id)) cache.push(elt);
	        return this;
		}
        throw "no such kind of cached element as " + kind;
    }
});

CW.ToolbarEvent = {
    onMouseOver: function(evt,kind,mgr){
		CW.debug("onMouseOver event handler called for "+kind+" with id "+this.id);
		
		var button = CW.extendElement( mgr.getRelatedButton(this.id) );
		CW.debug("onMouseOver("+this.id+"):related.button = "+(button && button.id));
		
		var menu = CW.extendElement( mgr.getRelatedMenu(this.id) );
		CW.debug("onMouseOver("+this.id+"):related.menu = "+(menu && menu.id));
		
        if ( (kind == 'button' || kind == 'subscribe') && button) {
			var button_coords = button.getCoords();
			CW.hideAll( mgr.getAll('menu') );
         	button.clearTimer().addHighlight();
			if (menu) {
				var left = 0;  // default for firefox
				if( Prototype.Browser.IE) left = 1;
				menu.clearTimer().show().positionRelativeTo(button, left, button_coords.height);
			}
		}
		else if( (kind == 'menu' || kind == 'box_menu') && menu) {
			menu.clearTimer().show();
			if( button ) button.clearTimer().addHighlight();
		}
		else if( kind == 'item' || kind == 'box_item' ) {
			var item = CW.extendElement( $(this) );
			if( menu ) menu.clearTimer().show();
			if( button ) button.clearTimer().addHighlight();
			item.addHighlight();
		}
    },
    onMouseOut: function(evt,kind,mgr){
		CW.debug("onMouseOut event handler called for "+kind+" with id "+this.id);
		
		var button = CW.extendElement( mgr.getRelatedButton(this.id) );
		CW.debug("onMouseOvut("+this.id+"):related.button = "+(button && button.id));
		
		var menu = CW.extendElement( mgr.getRelatedMenu(this.id) );
		CW.debug("onMouseOut("+this.id+"):related.menu = "+(menu && menu.id));
        
		var secs = 0.05;
		
		if ( (kind == 'button' || kind == 'subscribe') && button) {
			button.setTimer(button.removeHighlight.bind(button).delay(secs));
			if( menu ) menu.setTimer(menu.hide.bind(menu).delay(secs));
		}
		else if( ( kind == 'menu' || kind == 'box_menu' ) && menu) {
			menu.setTimer( menu.hide.bind(menu).delay(secs) );
			if( button ) button.setTimer(button.removeHighlight.bind(button).delay(secs));
		}
		else if( (kind == 'item' || kind == 'box_item') ) {
			var item = CW.extendElement( $(this) );
			item.removeHighlight();
			if (menu) menu.setTimer(menu.hide.bind(menu).delay(secs));
			if (button) button.setTimer(button.removeHighlight.bind(button).delay(secs));
		}

    },
    onClick: function(evt,kind,mgr){
		
		var path = '';
		var parts = this.id.split('_');
		var num = parts[parts.length-1];
		
		if( kind == 'button' || kind == 'subscribe') path = "buttons."+num;
		else if ( kind == 'item' ) 		path = "menus."+parts[parts.length-3]+".items."+num;
		else if ( kind == 'box_item' ) 	path = "menus."+parts[parts.length-4]+".items."+num;
		
		var target = $H(mgr.getConfig()).getPath(path+".target");
		
		if( target ) {
			mgr.resetAll();
			CW.debug("setting document location to: " + target);
			document.location = target;
		}
    }
};

// ToolbarManager class
CW.ToolbarManager = Class.create({
	
    config: null,
	
	initialize: function(conf) {
		this.config = $H(conf || {});
		this.cache = new CW.Element.Cache();
		this.collectElements();
		this.addEventHandlers();
	},
	
	getConfig: function(id) {
		return this.config;
	},
	
	moveRelativeTo: function(source,target,offsetTop,offsetLeft) {
		
		source = $(source);
		target  = $(target);
		offsetTop = offsetTop || 0;
		offsetLeft = offsetLeft || 0;

		if (source && target ) {
			CW.debug(
				"moving #{src} relative to #{tgt} plus/minus x,y:#{x},#{y}".interpolate(
					{ src:source.id, tgt:target.id, x:offsetLeft, y:offsetTop }
				)
			);
			var target_offset = target.cumulativeOffset();
			if (Prototype.Browser.IE) {
				source.setStyle({
					top: target_offset.top + offsetTop,
					left: target_offset.left + offsetLeft
				});
			}
			else {
				source.clonePosition(target, {
					setWidth: false,
					setHeight: false,
					offsetTop: offsetTop,
					offsetLeft: offsetLeft
				});
			}
			var offset = source.cumulativeOffset();
			CW.debug(
				"moved #{src} to x,y: #{x},#{y}".interpolate(
					{src: source.id, x: offset.left, y: offset.y}
				)
			);
		}
	},
	
	moveMenus: function() {
		CW.debug("moving menus");
		$$('.tb_menu', '.tb_box_menu').each(function(menu){
			CW.debug("menu = " + menu.id);
			var button_id = menu.id.sub('_(?:menu|box_menu)_', '_button_');
			var button = $(button_id);
			if (button) {
				//CW.debug("adding observers to button "+button_id);
				//button.observe('mouseover', menu.show.bindAsEventListener(menu));
				//button.observe('mouseout', menu.hide.bindAsEventListener(menu));
				var button_offset = button.cumulativeOffset();
				var button_dims = button.getDimensions();
				menu.show();
				if (Prototype.Browser.IE) {
					menu.style.left = button.style.left;
					menu.style.top = button.style.top + button.style.height;
				}
				else {
					menu.clonePosition(button, {
						setWidth: false,
						setHeight: false,
						offsetLeft: -2,
						offsetTop: button_dims.height - 2
					});
				}
				var offset = menu.cumulativeOffset();
				CW.debug("menu is now at x,y:"+offset.left+','+offset.top);
			}
			menu.hide();
		});
	},
	
	collectElements: function(){
		CW.debug("entering CW.ToolbarManager.collectElements...");
		this.cache.kinds().each(function(kind){
			var target = '.tb_'+kind;
			CW.debug("in CW.ToolbarManager.collectElements, looking for "+target+" elements");
			$$(target).each(function(elt){
				CW.debug("in CW.ToolbarManager.collectElements, found "+elt.id);
				this.cache.add(kind, CW.extendElement(elt));
			},this);
		},this);
	},
	
	addEventHandlers: function(){
	    this.cache.kinds().each(function(kind){
	        this.cache.get(kind).each(function(elt){
	            elt = $(elt);
	            //CW.debug("adding handlers for " + elt.id);
	            elt.observe('mouseover', CW.ToolbarEvent.onMouseOver.bindAsEventListener(elt,kind,this));
	            elt.observe('mouseout', CW.ToolbarEvent.onMouseOut.bindAsEventListener(elt,kind,this));
	            elt.observe('click', CW.ToolbarEvent.onClick.bindAsEventListener(elt,kind,this));
	        },this);
	    },this);
	},
	
	kindOfElement: function(elt){
        var result = null;
		elt = $(elt);
        elt.classNames().each(function(name){
            if (name.startsWith('tb_')) {
                result = name.sub('^tb_', '');
                //CW.debug("in CW.ToolbarManager.kindOfElement, " + elt.id + " is a " + result);
                throw $break;
            }
        });
        return result;
    },
	
	getRelatedElement: function(elt,kind){
		elt = $(elt);
		var id = elt.id;
		var elt_kind = this.kindOfElement(elt);
        var match = '_'+elt_kind+'_';
        var replacement = '_'+kind+'_';
        var target_id = id.sub(match, replacement).sub('^(.*?)_(?:item|box_item)_\d+$','$1');
        //CW.debug("@@@@@@@@@@@@ in CW.ToolbarManager.getRelatedElement, looking for a "+kind+" for '"+id+"' using target id '"+target_id+"'");
        return this.cache.get(kind,target_id);
    },
	
	getRelatedButton: function(elt) {
		return this.getRelatedElement(elt,'button') || this.getRelatedElement(elt,'subscribe');
	},
	
	getRelatedMenu: function(elt) {
		return this.getRelatedElement(elt,'menu') || this.getRelatedElement(elt,'box_menu');
	},
	
	getAll: function(kind) {
		return this.cache.get(kind);
	},
	
	resetAll: function() {
		CW.hideAll(this.getAll('menu'));
		CW.hideAll(this.getAll('box_menu'));
		CW.removeHighlightAll(this.getAll('button'));
		CW.removeHighlightAll(this.getAll('subscribe'));
		CW.removeHighlightAll(this.getAll('item'));
		CW.removeHighlightAll(this.getAll('box_item'));
	}
});

// startup
var tb = null;

function init_toolbar(config){
    tb = new CW.ToolbarManager(config);
}
