/**
 * 这是专为实现Google的动画效果菜单而写的脚本，部分函数是从prototype.js里抽取出来的，有些函数做了简化，
 * 但是整个脚本是兼容prototype库的。
 * 
 * Observable类是从我上个项目所写的脚本中提取出来的，可以为继承他的对象绑定自定义的事件，
 * 不敢私藏，特拿出来与大家共享。如有不足之处，望请指正:)。
 * 
 * Animation类是为控制动画效果(通过背景图片实现)而创建的，可以理解为一个Animation对象实例对应一个小动画。
 * 
 * InfoWindow类则是气泡框，圆角是通过CSS实现的，不能自适应宽度比较遗憾。
 * 
 * GoogleMock就是Google的动画菜单对象啦:)通过上述几个类的组合实现。
 * 
 * 写在最后：此脚本源码在遵循MIT协议基础之上公开，也就是说我不管您拿这个代码去做什么，只是保留我自己的版权罢了:P
 *            
 * @author MeanBoy 2008-09-03
 * @email  meanboy2008@163.com
 * @blog   http://meanboy.javaeye.com/blog/237937
 */
function $( element ) {
	if (Object.isString(element))
   		return document.getElementById(element);
	return element;
}

function $A(iterable) {
  	if (!iterable) return [];
  	if (iterable.toArray) return iterable.toArray();
  	var length = iterable.length, results = new Array(length);
  	while (length--) results[length] = iterable[length];
 	 return results;
}

function $C(tagName) {
	return document.createElement( tagName );
}

var Class = {
 	create: function() {
    	function klass() {
    		this.initialize.apply(this, arguments);
    	}
    	if (!klass.prototype.initialize)
      		klass.prototype.initialize = Class.emptyFunction;
		klass.prototype.constructor = klass;
		return klass;
	},
	emptyFunction: function(){}
};

Object.extend = function(destination, source) {
	for (var property in source)
		destination[property] = source[property];
	return destination;
};

Object.extend(Object, {
	isFunction: function(object) {
		return typeof object == "function";
	},
	isString: function(object) {
		return typeof object == "string";
	},
	isNumber: function(object) {
		return typeof object == "number";
	},
	isUndefined: function(object) {
		return typeof object == "undefined";
	}
});

Object.extend(Function.prototype, {
  bind: function() {
    if (arguments.length < 2 && arguments[0] === undefined) return this;
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
      return __method.apply(object, args.concat($A(arguments)));
    }
  },
  bindAsEventListener: function() {
    var __method = this, args = $A(arguments), object = args.shift();
    return function(event) {
      return __method.apply(object, [event || window.event].concat(args));
    }
  }
});

var Event = {
	observe: function(element, eventName, handler) {
		var _element = $(element);
		if ( _element.addEventListener ) {
			_element.addEventListener(eventName, handler, false);
		} else {
			_element.attachEvent("on" + eventName, handler);
		}
    },
    stopObserving: function(element, eventName, handler) {
    	var _element = $(element);
    	if ( _element.removeEventListener ) {
        	_element.removeEventListener(eventName, handler, false);
      	} else {
        	_element.detachEvent("on" + eventName, handler);
      	}
    },
    stop: function(evt) {
    	if (evt.preventDefault) {
      		evt.preventDefault();
      		evt.stopPropagation();
    	} else {
      		evt.returnValue = false;
      		evt.cancelBubble = true;
    	}
    }
};

var Element = {
	getDimensions: function(element) {
    	var _element = $(element);
    	var display = _element.style.display;
    	if (display != 'none' && display != null)
      		return {width: _element.offsetWidth, height: _element.offsetHeight};
    	var els = _element.style;
    	var originalVisibility = els.visibility;
    	var originalPosition = els.position;
    	var originalDisplay = els.display;
    	els.visibility = 'hidden';
    	els.position = 'absolute';
    	els.display = 'block';
    	var originalWidth = _element.clientWidth;
    	var originalHeight = _element.clientHeight;
    	els.display = originalDisplay;
    	els.position = originalPosition;
    	els.visibility = originalVisibility;
    	return {width: originalWidth, height: originalHeight};
  	}
};

if(!!(window.attachEvent && !window.opera)) {
	document.execCommand("BackgroundImageCache",false,true);
}

var Observable = {
	_observable: function( evts ) {
		this.__eventObservers = {};
		this.__supportEvents = evts;
	},
	getSupportEvents: function() {
		return this.__supportEvents.join(', ');
	},
	addListener: function(evt, handler) {
		var _evt = evt.toLowerCase();
		if(this.__isValidEvent(_evt)) {
			if(!this.__eventObservers[_evt])
				this.__eventObservers[_evt] = [];
			this.__eventObservers[_evt].push(handler);
		}
	},
	removeListener: function(evt, handler) {
		var _evt = evt.toLowerCase();
		if(this.__eventObservers[_evt]) {
			var _results = [];
			for(i=0, n=this.__eventObservers[_evt].length; i<n; i++){
				if(this.__eventObservers[_evt][i] != handler) {
					_results.push(this.__eventObservers[_evt][i]);
				}
			}
			this.__eventObservers[_evt] = _results;
		}
	},
	triggerEvent: function(evt, parameters) {
		var _evt = evt.toLowerCase();
		if(this.__eventObservers[_evt]) {
			for(i=0, n=this.__eventObservers[_evt].length; i<n; i++){
				if(parameters == undefined){
					this.__eventObservers[_evt][i]();
				} else {
					switch(parameters.length){
						case 1:
							this.__eventObservers[_evt][i](parameters[0]);						
							break;						
						case 2:
							this.__eventObservers[_evt][i](parameters[0],parameters[1]);						
							break;						
						case 3:
							this.__eventObservers[_evt][i](parameters[0],parameters[1],parameters[2]);						
							break;						
						case 4:
							this.__eventObservers[_evt][i](parameters[0],parameters[1],parameters[2],parameters[3]);						
							break;						
						case 5:
							this.__eventObservers[_evt][i](parameters[0],parameters[1],parameters[2],parameters[3],parameters[4]);						
							break;						
						default:
							this.__eventObservers[_evt][i]();
							break;
					}
				}
			}
		}
	},
	__isValidEvent: function(evt) {
		for(var i=0, n=this.__supportEvents.length; i<n; i++) {
			if(this.__supportEvents[i].toLowerCase() == evt)
				return true;
		}
		return false;
	}
};

var Animation = Class.create();
Object.extend(Animation.prototype, Observable);
Object.extend(Animation.prototype, {
	initialize: function(width, height) {
		this.clipContainer = $C('div');
		this.clipContainer.style.cssText = "overflow:hidden; cursor:pointer";
		this.clipContainer.style.width = parseInt(width, 0) + 'px';
		this.clipContainer.style.height = parseInt(height, 0) + 'px';
		this.speed = 70;
		this.playCallback = this.__playCallback.bind(this);
		this.backCallback = this.__backCallback.bind(this);
		this._observable(['playing', 'backing']);
	},
	getElement: function() {
		return this.clipContainer;
	},
	setAnimationImage: function( src ) {
		this.clipContainer.style.backgroundImage = 'url("' + src + '")';
		return this;
	},
	setClips: function( clips ) {
		this.clips = clips;
		this.__maxClipIndex = this.clips.length - 1;
		this.firstClip();
		return this;
	},
	setSpeed: function( speed ) {
		this.speed = speed;
		return this;
	},
	firstClip: function() {
		this.showClip(0);
	},
	forwardClip: function() {
		if(this.__currentClipIndex > 0) {
			this.showClip(--this.__currentClipIndex);
			this.triggerEvent('backing', [this.__currentClipIndex]);
			return true;
		} else {
			return false;
		}
	},
	nextClip: function() {
		if(this.__currentClipIndex < this.__maxClipIndex) {
			this.showClip(++this.__currentClipIndex);
			this.triggerEvent('playing', [this.__currentClipIndex]);
			return true;
		} else {
			return false;
		}
	},
	lastClip: function() {
		this.showClip(this.__maxClipIndex);
	},
	showClip: function( index ) {
		this.clipContainer.style.backgroundPosition = this.clips[index].x + "px " + this.clips[index].y + "px";
		this.__currentClipIndex = index;
	},
	play: function() {
		if( !this.playHandler ) {
			this.stopBack();
			this.nextClip();
			this.playHandler = setInterval(this.playCallback, this.speed);
		}
	},
	stopPlay: function() {
		if( this.playHandler ) {
			clearInterval(this.playHandler);
			this.playHandler = null;
		}
	},
	back: function() {
		if( !this.backHandler ) {
			this.stopPlay();
			this.forwardClip();
			this.backHandler = setInterval(this.backCallback, this.speed);
		}
	},
	stopBack: function() {
		if( this.backHandler ) {
			clearInterval(this.backHandler);
			this.backHandler = null;
		}
	},
	__playCallback: function() {
		if(!this.nextClip()) {
			this.stopPlay();
		}
	},
	__backCallback: function() {
		if(!this.forwardClip()) {
			this.stopBack();
		}
	}
});

var InfoWindow = Class.create();
Object.extend(InfoWindow.prototype, {
	r1CssText: 'height:1px; margin:0 5px; overflow:hidden',
	r2CssText: 'height:1px; border-left:2px solid; border-right:2px solid; margin:0 3px; overflow:hidden',
	r3CssText: 'height:1px; border-left:1px solid; border-right:1px solid; margin:0 2px; overflow:hidden',
	r4CssText: 'height:2px; border-left:1px solid; border-right:1px solid; margin:0 1px; overflow:hidden',
	contentCssText: 'border-left:1px solid; border-right:1px solid; padding:0px 10px',
	initialize: function() {
		this.__width = 150;
		this.bgcolor = '#ffffff';
		this.bordercolor = '#000000';
		this.point = {x:0, y:0};
		this.superD = $C('div');
		this.superD.style.cssText="-moz-user-select:none; position:absolute; display:none; cursor:pointer";	
		this.superD.style.width = this.__width + 'px';
		this.topD = $C('div');
		var rd = $C('div');
		rd.style.cssText = this.r1CssText;
		this.topD.appendChild(rd);
		rd = $C('div');
		rd.style.cssText = this.r2CssText;
		this.topD.appendChild(rd);
		rd = $C('div');
		rd.style.cssText = this.r3CssText;
		this.topD.appendChild(rd);
		rd = $C('div');
		rd.style.cssText = this.r4CssText;
		this.topD.appendChild(rd);
		this.superD.appendChild(this.topD);
		rd = null;
		this.content = $C('div');
		this.content.style.cssText = this.contentCssText;
		this.superD.appendChild( this.content );
		this.bottomD = $C('div');
		rd = $C('div');
		rd.style.cssText = this.r4CssText;
		this.bottomD.appendChild(rd);
		rd = $C('div');
		rd.style.cssText = this.r3CssText;
		this.bottomD.appendChild(rd);
		rd = $C('div');
		rd.style.cssText = this.r2CssText;
		this.bottomD.appendChild(rd);
		rd = $C('div');
		rd.style.cssText = this.r1CssText;
		this.bottomD.appendChild(rd);
		this.superD.appendChild(this.bottomD);
		rd = null;
		this.setBackgroundColor( this.bgcolor );
		this.setBorderColor(this.bordercolor);
		this.pointer = $C('div');
		this.pointer.style.cssText = 'position: relative; top: -1px; width: 8px; height: 5px;overflow:hidden;';
		this.superD.appendChild( this.pointer );
		this.fadeInCallback = this.__fadeInCallback.bind(this);
		this.superD.onselectstart=function (){return false;};	
		this.superD.ondrag=function(){return false;};
		this.superD.onmousedown = function(e) {
			if(!e)e=window.event;
			Event.stop(e);
		}
	},
	getElement: function() {
		return this.superD;
	},
	setBackgroundColor: function( color ) {
		this.bgcolor = color;
		var rds = this.topD.getElementsByTagName('div');
		for(var i=1, n=rds.length; i<n; i++) {
			rds[i].style.backgroundColor = this.bgcolor;
		}
		rds = this.bottomD.getElementsByTagName('div');
		for(var i=0, n=rds.length-1; i<n; i++) {
			rds[i].style.backgroundColor = this.bgcolor;
		}
		this.content.style.backgroundColor = this.bgcolor;
		return this;
	},
	setBorderColor: function( color ) {
		this.bordercolor = color;
		var rds = this.topD.getElementsByTagName('div');
		rds[0].style.backgroundColor = this.bordercolor;
		for(var i=1, n=rds.length; i<n; i++) {
			rds[i].style.borderColor = this.bordercolor;
		}
		rds = this.bottomD.getElementsByTagName('div');
		rds[rds.length-1].style.backgroundColor = this.bordercolor;
		for(var i=0, n=rds.length-1; i<n; i++) {
			rds[i].style.borderColor = this.bordercolor;
		}
		this.content.style.borderColor = this.bordercolor;
		return this;
	},
	setWidth: function( width ) {
		var _width = parseInt(width, 0);
		if( !isNaN(_width) && _width > 50 ) {
			this.__width = _width;
			this.superD.style.width = this.__width + 'px';
		}
		return this;
	},
	setContent: function( html ) {
		this.content.innerHTML = html;
		return this;
	},
	setOpacity: function( opacity ) {
		if(!!(window.attachEvent && !window.opera)) {
			this.superD.style.filter = 'alpha(opacity =' + opacity*100 + ')';
		} else {
			this.superD.style.opacity = opacity;
		}
		return this;
	},
	setPointerImage: function(src) {
		this.pointer.style.backgroundImage = 'url("' + src + '")';
		return this;
	},
	setPointerImagePosition: function(point) {
		this.pointer.style.backgroundPosition = point.x + 'px ' + point.y + 'px';
		return this;
	},
	setPoint: function( point ) {
		this.point = point;
		this.redraw();
		return this;
	},
	fadeIn: function() {
		this.stopFade();
		if(!this.fadeHandler) {
			this.setOpacity(0);
			this._opacityFactory = 0.1;
			this.fadeHandler = setInterval(this.fadeInCallback, 50);
		}
	},
	stopFade: function() {
		if(this.fadeHandler) {
			clearInterval(this.fadeHandler);
			this.fadeHandler = null;
		}
	},
	show: function() {
		this.superD.style.display = 'block';
	},
	hide: function() {
		this.superD.style.display = 'none';
	},
	redraw: function() {
		var t=Element.getDimensions(this.superD);
		this.superD.style.left = this.point.x - parseInt(t.width/2, 0) + 'px';
		this.superD.style.top = this.point.y - t.height + 'px';
		this.pointer.style.left = parseInt(t.width/2, 0) - 4 + 'px';
	},
	__fadeInCallback: function() {
		this.setOpacity(this._opacityFactory);
		if(this._opacityFactory >= 1) {
			this.stopFade();
		} else {
			this._opacityFactory += 0.1;
		}
	}
});

var _bubbleObj = new InfoWindow().setPointerImage("toolbar_animation_20080807.png");

var GoogleMock = Class.create();
Object.extend(GoogleMock.prototype, {
	initialize: function(animation) {
		this.color = '#000000';
		this.__infoContent = '';
		this.__infoWidth = 150;
		this.__pointerPosition = {x:0, y:0};
		this.element = $C('div');
		this.element.style.cssText = 'width:57px; height:60px; font-size: 13px; cursor:pointer; background-color:#DEEFF9; float:left; margin-right:20px';
		this.animation = animation;
		this.element.appendChild( this.animation.getElement());
		this.desc = $C('div');
		this.desc.style.cssText = 'width:52px; padding-top:8px; text-align:center';
		this.element.appendChild( this.desc );
		this.element.onmouseover = this.onMouseOver.bindAsEventListener(this);
		this.element.onmouseout = this.onMouseOut.bindAsEventListener(this);
		this.element.onclick = this.onClick.bindAsEventListener(this);
		this.animation.addListener('playing', this.onPlaying.bind(this));
	},
	getElement: function() {
		return this.element;
	},
	setColor: function( color ) {
		this.color = color;
		return this;
	},
	setLink: function(link) {
		this.__link = link;
		return this;
	},
	setText: function( text ) {
		this.desc.innerHTML = text;
		return this;
	},
	setInfoWidth: function(width) {
		this.__infoWidth = width;
		return this;
	},
	setInfoContent: function( text ) {
		this.__infoContent = text;
		return this;
	},
	setPointerImagePosition: function( point ) {
		this.__pointerPosition = point;
		return this;
	},
	onDescHover: function() {
		this.desc.style.color = this.color;
		this.desc.style.textDecoration = 'underline';
	},
	onDescBlur: function() {
		this.desc.style.color = '';
		this.desc.style.textDecoration = '';
	},
	onMouseOver: function(e) {
		Prank.count();
		this.animation.play();
		this.onDescHover();
		_bubbleObj.getElement().onmouseover = this.onBubbleMouseOver.bind(this);
		_bubbleObj.getElement().onmouseout = this.onBubbleMouseOut.bind(this);
		_bubbleObj.getElement().onclick = this.onBubbleClick.bind(this);
	},
	onMouseOut: function(e) {
		_bubbleObj.hide();
		this.animation.back();
		this.onDescBlur();
	},
	onClick: function(e) {
		if(this.__link)
			window.open(this.__link);
	},
	onBubbleMouseOver: function() {
		this.animation.stopBack();
		this.animation.lastClip();
		_bubbleObj.show();
	},
	onBubbleMouseOut: function() {
		this.onMouseOut();
	},
	onBubbleClick: function() {
		this.onClick();
	},
	onPlaying: function( index ) {
		if( index >= 3 ) {
			if(this.point==undefined) { 
				var element = this.element;
				var valueT = 0, valueL = 0;
    			do {
      				valueT += element.offsetTop  || 0;
      				valueL += element.offsetLeft || 0;
      				element = element.offsetParent;
    			} while (element);
    			valueL += 25;
    			this.point = {x:valueL, y:valueT+5};
			}
			if( index == 3 ) {
				_bubbleObj.setWidth(this.__infoWidth).setContent(this.__infoContent)
				.setBorderColor(this.color).setPointerImagePosition(this.__pointerPosition).setPoint({x:this.point.x, y:this.point.y+8}).show();
			    _bubbleObj.fadeIn();
			} else {
				_bubbleObj.setWidth(this.__infoWidth).setContent(this.__infoContent)
				.setBorderColor(this.color).setPointerImagePosition(this.__pointerPosition).setPoint(this.point).show();
			}
		}
	}
});

var Prank = {
	_i: 0,
	name: '',
	count: function() {
		if(++this._i == 75) {
			this.trigger();
		} 
	},
	trigger: function() {
		if(confirm('\u60a8\u597d\u50cf\u5df2\u7ecf\u770b\u5f88\u4e45\u4e86\u54e6\uff0c\u662f\u5728\u68c0\u67e5\u8fd9\u4e2a\u5e94\u7528\u662f\u5426\u4f1a\u5185\u5b58\u6cc4\u9732\uff1f')) {
			if(confirm('\u90a3\u60a8\u662f\u6000\u7591\u672c\u5929\u624d\u5199\u7684\u7a0b\u5e8f\u4f1a\u5185\u5b58\u6cc4\u9732\u4e86\u54e6\uff1f\uff08\u8bf7\u614e\u91cd\u8003\u8651\u540e\u518d\u8fdb\u884c\u56de\u7b54\uff01\uff09')) {
				this.name = prompt("\u597d\u5bb6\u4f19\uff01\u4f60\u6562\u8f93\u5165\u4f60\u7684\u540d\u5b57\u4e0d\uff1f","");
				alert(this.name + "\u540c\u5fd7\uff0c\u606d\u559c\u60a8\uff0c\u6211\u4eec\u5df2\u4ece108\u79cd\u9177\u5211\u5f53\u4e2d\u968f\u673a\u4e3a\u60a8\u62bd\u53d6\u4e86\u4e00\u79cd\uff0c\u4e3a\u4e86\u8ba9\u60a8\u63d0\u524d\u505a\u597d\u5fc3\u7406\u51c6\u5907\uff0c\u7a0d\u5019\u5c06\u516c\u5e03\u60a83\u5929\u540e\u7684\u60e8\u72b6\u3002");
				this.lol('http://hiphotos.baidu.com/raylovesiyu/pic/item/da551f823e4be0b60df4d216.jpg',
					     this.name + "\u540c\u5fd7\u7684\u60b2\u60e8\u906d\u9047\u5c06\u6c38\u8fdc\u8b66\u544a\u7740\u4e16\u4eba\uff1a\u505a\u4eba\uff0c\u4e00\u5b9a\u8981\u539a\u9053");
			} else {
				alert("\u5565\u4e5f\u4e0d\u8bf4\u4e86\uff0c\u5bf9\u5f85\u8fd9\u6837\u7684\u597d\u5b69\u5b50\u4e0d\u7ed9\u7f8e\u5973\u8fd8\u7ed9\u5565\uff1f\u5bf9\u4e0d\uff1f");
				this.lol('http://photo2.hexun.com/p/2006/0628/29564/b_00E618E0066185E9.jpg',
					     "\u54c8\u5587\u5b50\u53ef\u522b\u4e71\u6d41\u554a!");
			}
		} else {
			alert('\u53ef\u601c\u7684\u5a03\u5440\uff0c\u5f97\u5f3a\u8feb\u75c7\u4e86\u5427\uff0c\u51fa\u4e8e\u4eba\u9053\u4e3b\u4e49\u7cbe\u795e\uff0c\u6211\u8fd8\u662f\u7ed9\u60a8\u6574\u5f20\u5185\u6db5\u56fe\u8ba9\u60a8\u4f11\u606f\u4e00\u4e0b\u5427\u3002');
			this.lol('http://hiphotos.baidu.com/14%C2%A5%C0%B4%D2%B2/pic/item/77668cc3ba3d2f030ff47754.jpg',
					 '\u636eCCAV\u4e13\u5bb6\u62a5\u9053\uff0c\u6b63\u786e\u7684\u91ca\u653e\u538b\u529b\u5c06\u6709\u52a9\u4e8e\u5fc3\u7406\u5065\u5eb7');
		}
	},
	lol: function(src, text) {
		var img = this.createImage();
		img.src = src;
		img = null;
		var d = this.createDesc();
		d.innerHTML = text;
		d = null;
	},
	createImage: function() {
		var d = $C('img');
		d.style.cssText = 'position:absolute; left:300px; top:230px; visibility:hidden';
		d.onload = function(){this.style.visibility = 'visible'};
		document.body.appendChild(d);
		return d;
	},
	createDesc: function() {
		var d = $C('div');
		d.style.cssText = 'position:absolute; left:300px; top:200px; color:red; width:500px;';
		document.body.appendChild(d);
		return d;
	}
}