/**
 * @module ui
 */

/**
 * @namespace XN
 * @class ui
 * @static
 */

XN.namespace( 'ui' );

(function()
{
	/**
	 * @namespace XN.ui
	 * @class element
	 * @static
	 */
	
	XN.ui.element = {
		
		/**
		 *  the  frame element
		 *  @property frame
		 *  @type {HTMLElement}
		 */
		
		frame : null,
		
		/**
		 * @property iAmUIelement
		 * @protected
		 * @type {Boolean}
		 * @default true
		 */
		
		iAmUIelement : true
        
	};

	/**
	 * @method show
	 * @see XN.element.show
	 */
	
	/**
	 * @method hide
	 * @see XN.element.hide
	 */
	
	/**
	 * @method remove
	 * @see XN.element.remove
	 */
	
	/**
	 * @method addClass
	 * @see XN.element.addClass
	 */
	
	/**
	 * @method deClass
	 * @see XN.element.delClass
	 */
	
	XN.array.each( [ 'addClass' , 'delClass' , 'show' , 'hide' , 'remove' ] , function( i , v )
	{
		XN.ui.element[ v ] = function()
		{
			XN.element[ v ].apply( null , [ this.frame ].concat( XN.array.build( arguments ) ) );
		}
	} );

	/**
	 * @namespace XN.ui
	 * @class container
	 * @static
	 * @extends XN.ui.element
	 */
	
	XN.ui.container =
	{
		
		/**
		 * @property container
		 * @type {HTMLElement}
		 */
		
		container : null
	};
	
	/**
	 * @method addChild
	 * @see XN.element.addChild
	 */
	
	/**
	 * @method delChild
	 * @see XN.element.deChild
	 */
	
	/**
	 * @method setContent
	 * @see XN.element.setContent
	 */
	
	XN.array.each( [ 'addChild' , 'delChild' , 'setContent' ] , function( i , v )
	{
		XN.ui.container[ v ] = function()
		{
			XN.element[ v ].apply( null , [ this.container ].concat( XN.array.build( arguments ) ) );
		}
	} );
	
	$extend( XN.ui.container , XN.ui.element );
	
})();





/*
 *  patch for old version
 */

XN.UI = XN.Ui = XN.ui;
XN.ui.Element = XN.ui.element;
XN.ui.Content = XN.ui.container;

/*
 * patch end
 */
(function( ns )
{	
	var UI = XN.ui;
	var addEvent = XN.event.addEvent;
	var DEBUG = true;
	
	function log( s )
	{
		if ( DEBUG ) XN.log( isString( s ) ? 'xn.ui.button:' + s : s );
	}

	/**
	 * create a button
	 * @namespace XN.ui
	 * @class button
	 * @constructor
	 * @param  {Object} params The intial Attribute.
	 * @extends XN.ui.element
	 */
	
	ns.button = function( params )
	{
		$extend( this , params );
		this.init();
	};

	ns.button.prototype = $extend( {} , UI.Element );
	
	/**
	 * the title of the button
	 * @property text
	 * @type String
	 */
	
	ns.button.prototype.text = null;
	
	/**
	 *	the className of the button
	 * @property className
	 * @type String
	 * @default 'input-submit'
	 */

	ns.button.prototype.className = '';
	
	/**
	 *  the disable class of the button
	 *  @property disableClassName
	 *  @type String
	 *  @default 'gray'
	 */
	
	ns.button.prototype.disableClassName = 'gray';
	
	
	/**
	 * init
	 * @private
	 */
	
	ns.button.prototype.init = function()
	{
		var This = this;

		var el;

		if ( this.getConfig( 'el' ) )
		{
			el = $( this.getConfig( 'el' ) );
		}
		else
		{
			el = $element( 'input' );
		}
		
		this.frame = el;
		el.type = 'button';
	    this.addClass( 'input-submit' );	
		this.addClass( this.getConfig( 'className' ) );
		this.setText( this.getConfig( 'text' ) );
		
		addEvent( el , 'click' , function()
		{
			if ( This.onclick ) This.onclick();
		} , false );		
	};
	
	/**
	 * get user config
	 * @param {String} key
	 * @method getConfig
	 * @return {Any}
	 */
	
	ns.button.prototype.getConfig = function( key )
	{
		if ( key == 'el' ) return this.id;
		return this[ key ];
	};
	
	/**
	 * get dom element of the button
	 * @method getEl 
	 * @return {HTMLElement}
	 */
	
	ns.button.prototype.getEl = function()
	{
		return this.frame;
	};
	/**
	 * set title of the button
	 * @method setText 
	 * @param {String} text
	 */
	
	ns.button.prototype.setText = function( text )
	{
		this.text = text;
		this.getEl().value = text;
	};
	
	/**
	 * disable the button
	 * @method disable
	 */
	
	ns.button.prototype.disable = function(){
		var el = this.getEl();
		el.blur();
		el.disabled = true;
		el.addClass( this.getConfig( 'disableClassName' ) );
	};

	/**
	 *  enable the button
	 *	@method enable
	 */
	
	ns.button.prototype.enable = function(){
		var el = this.getEl();
		el.disabled = false;
		el.delClass( this.getConfig( 'disableClassName' ) );
	};

	/**
	 *  focus on the button
	 *  @method focus
	 */
			
	ns.button.prototype.focus = function(){
		this.getEl().focus();
	};
	
	/**
	 *  make the button blur
	 *  @method blur
	 */

	ns.button.prototype.blur = function(){
		this.getEl().blur();
	};

})( XN.ui );
(function()
{
	var rl = 'realLeft',rt = 'realTop',ow = 'offsetWidth',oh = 'offsetHeight';
	XN.ui.fixPositionMethods = {
		'1-1':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + 'px';
		},
		'1-2':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]()  + 'px';
		},
		'1-3':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() - f[ oh ] + 'px';
		},
		'1-4':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]()  - f[ oh ] + 'px';
		},
		'2-1':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]()  + 'px';
		},
		'2-2':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + 'px';
		},
		'2-3':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]()  - f[ oh ] + 'px';
		},
		'2-4':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]()  - f[ oh ] + 'px';
		},
		'3-1':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + el[ oh ] + 'px';
		},
		'3-2':function(f,el,x,y,p){
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() + el[ oh ] + 'px';
		},
		'3-3':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + el[ oh ] - f[ oh ] + 'px';
		},
		'3-4':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + el[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + el[ oh ] - f[ oh ] + 'px';
		},
		'4-1':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + el[ oh ] + 'px';
		},
		'4-2':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + el[ oh ] + 'px';
		},
		'4-3':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() - f[ ow ] + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + el[ oh ] - f[ oh ] + 'px';
		},
		'4-4':function(f,el,x,y,p)
		{
			f.style.left = x + el[ rl ]() - p[ rl ]() + 'px';
			f.style.top = y + el[ rt ]() - p[ rt ]() + el[ oh ] - f[ oh ] + 'px';
		}
	};	
})();

/**
 * create fix position element
 * @namespace XN.ui
 * @class fixPositionElement
 * @constructor
 * @param {Object} params
 * @extends XN.ui.container
 */

XN.ui.fixPositionElement = function( params )
{
	var This = this;
	
	this.config = {
		tagName : 'div',
        useIframeInIE6 : true
	};
	
	$extend( this.config , params );
	
	var f,x,y;

	if ( this.getConfig( 'id' ) )
	{
		this.frame = f = $( this.getConfig( 'id' ) );
        x = f.realLeft();
		y = f.realTop();
	}
	else if ( this.getConfig( 'tagName' ) )
	{
		this.frame = this.container = f = $element( this.getConfig( 'tagName' ) );
	}
	else return;

    this.container = $element( 'div' );
    this.frame.appendChild( this.container );
	
    XN.array.each( [ 'alignWith' , 'alignType' , 'offsetX' , 'offsetY' , 'alignParent' ] , function( i , v )
	{
        This[ v ] = This.getConfig( v ) || This[ v ];
	} );
    

    XN.element.setStyle( f , 'position:absolute;z-index:10001;left:-9999px;top:-9999px' );
	

    if( !$( this.alignParent ) ) this.alignParent = $( document.body );
	
    $( this.alignParent ).appendChild( this.frame );
	
    if ( ( XN.browser.IE6 && this.getConfig( 'useIframeInIE6' ) ) || this.getConfig( 'addIframe' ) )
	{
		var iframe;
		this._iframe = iframe = $element( 'iframe' );
		iframe.frameBorder = 0;
		iframe.setStyle( 'position:absolute;border:0px;left:0px;top:0px;z-index:-1;' );
        if ( XN.browser.Gecko ) iframe.setAttribute( 'style' , 'position:absolute;border:0px;left:0px;top:0px;z-index:-1;' );
        //fix 防止对话框高度改动时露出空白的iframe
        if ( XN.browser.IE ) iframe.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
        this.frame.appendChild( iframe );	
    }
	
    if ( XN.element.visible( f ) ) this.show();
    
    f.style.display = 'block';
};

XN.ui.fixPositionElement.prototype = $extend( {} , XN.ui.container );

$extend( XN.ui.fixPositionElement.prototype ,
{
	
	/**
	 * the element align with
	 * @property alignWith
	 * @type {HTMLElement | String}
	 */
	
	alignWith : null,
	
	/**
	 * @property alignType
	 * @type {String}
	 */
	
	alignType : '4-1',
	
	/**
	 * @property offsetX
	 * @type {Int}
	 * @default 0
	 */
	
	offsetX : 0,
	
	/**
	 * @property offsetY 
	 * @type {Int}
	 * @default 0
	 */
	
	offsetY : 0,
	
	/**
	 * @property alignParent
	 * @type {HTMLElement | String}
	 * @default 'dropmenuHolder'
	 */
	
	alignParent : 'dropmenuHolder',
	
	left : null,
	top : null,

	_isShow : false,

	getConfig : function( key )
	{
		return this.config[ key ];
	},
	
	/**
	 * set offset x
	 * @method setOffsetX
	 * @param {Int} x
	 * @return {Object} this
	 */
	
	setOffsetX : function( x )
	{
		this.offsetX = x;
		this.refresh();
		return this;
	},
	
	/**
	 * set offset y
	 * @method setOffestY
	 * @param {Int} y
	 * @return {Object} this
	 */
	
	setOffsetY : function( y )
	{
		this.offsetY = y;
		this.refresh();
		return this;
	},
	
	/**
	 * @method setAlignType
	 * @param {String} t
	 * @return {Object} this
	 */
	
	setAlignType : function( t )
	{
		this.alignType = t;
		this.refresh();
		return this;
	},
	
	/**
	 * @method setAlignParent
	 * @param {HTMLElement | String} p
	 * @return {Object} this
	 */
	
	setAlignParent : function( p )
	{
		this.alignParent = p;
		$( this.alignParent ).appendChild( this.frame );
		this.refresh();
		return this;
	},
	
	/**
	 * @method refresh
	 * @return {Object} this
	 */
	
	refresh : function()
	{
		if ( this.visible() )
		{
			this.show();
		}
		else
		{
			this.hide();
		}
		return this;
	},
	
	/**
	 * @method visible
	 * @return {Boolean}
	 */
	
	visible : function()
	{
		return this._isShow;
	},
	
	/**
	 * @method show
	 * @return {Object} this
	 */
	
	show : function()
	{
		this._isShow = true;
        
        this.frame.show();
		
        if ( this.alignWith )
		{
			this._moveToElement( this.alignWith );
		}
		else
		{
			var x = this.left === null ? parseInt( ( ( $( this.alignParent ).offsetWidth -  this.frame.offsetWidth ) / 2 ) , 10 ) : this.left;
			var y = this.top === null ? XN.event.scrollTop() + 200 : this.top;
			this._moveToPosition( x , y );
		}
        
		if( this._iframe )
		{
            //fix bug for ie6
            try
            {
			    this._iframe.style.height = this.frame.offsetHeight - 2 + 'px';
			    this._iframe.style.width = this.frame.offsetWidth + 'px';
            }catch( e ){}
		}

		return this;
	},
	
	/**
	 * @method hide
	 * @return {Object} this
	 */
	
	hide : function()
	{
        this._isShow = false;
		var f = this.frame;
		//this.left = f.offsetLeft;
		//this.top = f.offsetTop;
		f.style.left = '-9999px';
		f.style.top = '-9999px';
		return this;
	},
	
	/**
	 * @method moveTo
	 * @param {HTMLElement | String | Int} x
	 * @param {Int} y
	 * @return {Object} this
	 */
	
	moveTo : function( x , y )
	{
		if ( !x && !y ) return;
		if ( isNumber( x ) )
		{
			this.left = x;
            this.alignWith = null;
		}
		else if ( isString( x ) || isElement( x ) )
		{
			this.alignWith = $( x );
		}
		
		if ( isNumber( y ) )
		{
			this.top = y;
            this.alignWith = null;
		}
		
		this.refresh();
		
		return this;
	},
	
	/**
	 * @method setX
	 * @param {Int} x
	 * @return {Object} this
	 */
	
	setX : function( x )
	{
		this.moveTo( x );
		return this;
	},
	
	/**
	 * @method setY
	 * @param {Int} y
	 * @return {Object} this
	 */
	
	setY : function( y )
	{
		this.moveTo( null , y );
		return this;
	},

	/**
	 * @method setIndex
	 * @param {Int} i
	 * @return {Object} this
	 */
		
	setIndex : function( i )
	{
		this.frame.style.zIndex = i;
		return this;
	},
	
	_moveToElement : function( el )
	{
		XN.ui.fixPositionMethods[ this.alignType ](
			this.frame , $( el ) , this.offsetX , this.offsetY , $( this.alignParent )
		);
	},
	
	_moveToPosition : function( x , y )
	{
		if ( x )
		{
			this.frame.style.left = x + 'px';
		}
		if ( y )
		{
			this.frame.style.top = y + 'px';
		}
	}
} );
(function()
{
	var fixProto = XN.ui.fixPositionElement.prototype;
	var Event = XN.event;
	/**
	 * 创建一个dialog
     * <pre>
     * 参数形式如下
     * {
     *  HTML:''//自定义对话框的html代码
     * }
     *
     * 自定义代码中必须包含下面三个id的元素
     *  ui_dialog_header
     *  ui_dialog_body
     *  ui_dialog_footer
     * </pre>
	 * @namespace XN.ui
	 * @class dialog
	 * @constructor
	 * @param {Object} params
	 * @extends XN.ui.fixPositionElement
	 */
	
	XN.ui.dialog = function( params )
	{
		var This = this;
		XN.ui.fixPositionElement.call( this , params );
	    
        this.container = $element( 'div' );
        this.frame.appendChild( this.container );

        if ( this.getConfig( 'HTML' ) )
        {
            this.setContent( this.getConfig( 'HTML' ) )
        }
        else
        {
		    this.setContent( this.buildHTML() );
        }
		
		this.header = $( 'ui_dialog_header' );
		this.body = $( 'ui_dialog_body' );
		this.footer = $( 'ui_dialog_footer' );
	    this.closeButton = $( 'ui_dialog_close' );

        this.header.addChild = 
        this.body.addChild = 
        this.footer.addChild = function( s )
        {
            XN.element.addChild( this , s );
            setTimeout( function(){This.refresh();},0 );
        };

		this.header.removeAttribute( 'id' );
		this.body.removeAttribute( 'id' );
		this.footer.removeAttribute( 'id' );
	    this.closeButton.removeAttribute( 'id' );	
        
        if ( this.getConfig( 'showCloseButton' ) )
        {
            this.closeButton.show();
            XN.event.addEvent( this.closeButton, 'click', function()
            {
                This.hide();
            });
        }

		//lower than menu
		this.frame.style.zIndex = 10000;
		
		this.setWidth( this.getConfig( 'width' ) || 400 );
		
		if ( this.getConfig( 'height' ) ) this.setHeight( this.getConfig( 'height' ) );
		
		XN.array.each( [ 'header' , 'body' , 'footer' ] , function( i , v )
		{
			if ( This.getConfig( v ) ) This[ v ].setContent( This.getConfig( v ) );
		} );
		
		if ( this.getConfig( 'type' ) ) this.setType( this.getConfig( 'type' ) );
		
		this._buttons = [];
		
		XN.event.addEvent( this.footer , 'click' , function( e )
		{
			e = e || window.event;
			This._parseButtonEvent( e );
		} );

        XN.util.hotKey.add( '27' , this._hotKeyEvent , this );

        if ( this.getConfig( 'modal' ) )
        {
            XN.dom.disable();
        }
	};
	XN.ui.dialog.prototype = $extend( {} , fixProto );
	$extend( XN.ui.dialog.prototype , 
	{
		header : null,
		body : null,
		footer : null,
		_iframe : null,
		_buttons : null,
	    
        buildHTML : function()
        {
            return [
                '<table style="width: 100%; height: 100%;" class="pop_dialog_table">',
                    '<tbody>',
                        '<tr>',
                            '<td class="pop_topleft"></td>',
                            '<td class="pop_border"></td>',
                            '<td class="pop_topright"></td>',
                        '</tr>',
                        '<tr>',
                            '<td class="pop_border"></td>',
                            '<td class="pop_content">',
                                '<h2><span id="ui_dialog_header"></span><a style="display:none;" id="ui_dialog_close" href="#nogo">关闭</a></h2>',
                                '<div class="dialog_content">',
                                    '<div id="ui_dialog_body" class="dialog_body"></div>',
                                    '<div id="ui_dialog_footer" class="dialog_buttons"></div>',
                                '</div>',
                            '</td>',
                            '<td class="pop_border"></td>',
                        '</tr>',
                        '<tr>',
                            '<td class="pop_bottomleft"></td>',
                            '<td class="pop_border"></td>',
                            '<td class="pop_bottomright"></td>',
                        '</tr>',
                        '</tbody>',
                    '</table>'
            ].join( '' );
        },

		/**
		 * 通过一个按钮的标题获取按钮的实例
		 * @method getButton
		 * @param {String} text
		 * @return {XN.ui.button}
		 */
		
		getButton : function( text )
		{
			var buttons = this._buttons;

			for ( var i = buttons.length - 1 ; i >= 0 ; i -- )
			{
				if ( buttons[ i ].text == text ) return buttons[ i ];
			}
			
			return null;
		},

		/**
		 * 向对话框底部添加按钮
         * <pre>
         *  参数形式如下: 
         *  {
         *      text : '',//按钮的文字
         *      onclick : callback//按钮onclick时触发的函数
         *  } 
         * </pre>
		 * @method addButton
		 * @param {Object} b
		 * @return {Object} this
		 */
		
		addButton : function( b )
		{
			var o = {
				text : b.text,
				_onclickForDialog : b.onclick				
			};
			if ( b.className ) o.className = b.className;
			var button = new XN.ui.button( o );

            /*
             * patch for panel
             */
            
            button.frame.setAttribute( 'dialog' , '1' );

            /*
             * patch end
             */

			this._buttons.push( button );

			this.footer.addChild( button );
			return this;
		},

		/**
		 * 从从对话框删除按钮，参数为按钮的文字
		 * @method delButton
		 * @param {String} b title of the button
		 * @return {Object} this
		 */
		
		delButton : function( b )
		{
			if ( isString( b ) ) b = this.getButton( b );

			this.footer.delChild( b );
			return this;
		},
        
        
        _preventHide : false,

        /**
         * 阻止对话框关闭，用于按钮的回调函数
         * <pre>
         * callBack=function()
         * {
         *  this.preventHide();
         *  .....
         * }
         * </pre>
         * @method preventHide
         * @return {Object} this
         */

        preventHide : function()
        {
            this._preventHide = true;
            return this;
        },

		_parseButtonEvent : function( e )
		{
			var el = Event.element( e );
			if ( el.tagName.toLowerCase() !== 'input' || el.type !== 'button' ) return;
            if ( !el.getAttribute( 'dialog' ) ) return;
			
            var button = this.getButton( el.value );
			
            if ( button && button._onclickForDialog )
            {
                button._onclickForDialog.call( this );
            }
            
            if ( this._preventHide )
            {
                this._preventHide = true;
            }
            else
            {
			    this.hide();
                //XN.dom.enable();
            }
		},

        _hotKeyEvent : function()
        {
            this.hide();
        },
		
		/**
		 * 设置对话框的样式'normal' or 'error' type
		 * @method setType
		 * @param {String} t
		 * @return {Object} this
		 */
		
		setType : function( t )
		{
			if ( t == 'normal' )
			{
				this.frame.delClass( 'errorDialog' );
			}
			else if ( t == 'error' )
			{
				this.frame.addClass( 'errorDialog' );
			}
			return this;
		},
		
		/**
         * 设置对话框宽度
		 * @method setWidth
		 * @param {Int} w
		 * @return {Object} this
		 */
		
		setWidth : function( w )
		{
			if ( !w ) return this;
			this.width = w;
			this.frame.style.width = w + 'px';
			this.refresh();
			return this;
		},
		
		/**
         * 设置对话框高度，一般是自动伸展
		 * @method setHeight
		 * @param {Int} h
		 * @return {Object} this
		 */
		
		setHeight : function( h )
		{
			if ( !h )return this;
			this.hegith =  h;
			this.frame.style.height = h + 'px';
			this.refresh();
			return this;
		},
        
        /**
         * resize
         * @method resizeTo
         * @param {Int} w
         * @param {Int} h
         * @return {Object} this
         */

        resizeTo : function( w , h )
        {
            this.setWidth( w );
            this.setHeight( h );
            return this;
        },
		
		/**
         * 清空对话框的内容
		 * @method clear
		 * @return {Object} this
		 */
		
		clear : function()
		{
			this.header.setContent( '' );
			this.body.setContent( '' );
			this.footer.setContent( '' );
			this._buttons = [];
			return this;
		},
				
		/**
         * 设置对话框的标题
		 * @method setTitle
		 * @param {String} s
		 * @return {Object} this
		 */
		
		setTitle : function( s )
		{
			this.header.setContent( s );
			return this;
		},
		
		/**
         * 设置对话框的内容
		 * @method setBody
		 * @param {String} s
		 * @return {Object} this;
		 */
		
		setBody : function( s )
		{
			this.body.setContent( s );
			return this;
		},


        remove : function()
        {
            XN.util.hotKey.del( '27' , this._hotKeyEvent );
            XN.ui.element.remove.call( this );
            return this;
        },
        
        refresh : function()
        {
		    if ( this.visible() )
		    {
                fixProto.show.apply( this , arguments ); 
		    }
		    else
		    {
			    this.hide();
		    }
		    return this;
        },

        show : function()
        {
            this._clearHideTimer();
            fixProto.show.apply( this , arguments );
            return this;
        },

        hide : function()
        {
            this._clearHideTimer();
            fixProto.hide.apply( this , arguments );
            XN.dom.enable();
            return this;
        },

        _hideTimer : null,
        _clearHideTimer : function()
        {
            if ( this._hideTimer )
            {
                clearTimeout( this._hideTimer );
                this._hideTimer = null;
            }
        },
        
        /**
         * 自动关闭对话框
         * @method autoHide
         * @param {Int} t
         * @return {Object} this
         */

        autoHide : function( t )
        {
            var This = this;
            this._hideTimer = setTimeout(function()
            {
                This.hide();
            }, t * 1000 );
            return this;
        }
	} );
})();

/*
 *  patch for old version
 */
XN.ui.panel = XN.ui.dialog;
XN.ui.dialog.prototype.setHeader = function( h )
{
	if( h && h !== '')
	{
		this.header.addChild( h );
	}
	else
	{
		this.header.innerHTML = '';
	}	
};
XN.ui.dialog.prototype.setFooter = function( f )
{
	if ( f && f !== '' )
	{
		this.footer.addChild( f );
	}
	else
	{
		this.footer.innerHTML = '';
	}
};
/*
 * patch end
 */

/**
 * 菜单
 * <pre>
 *  参数形式如下
 *  {
 *      button : 'el',//触发元素的id
 *      hoverClass : 'classname',//菜单显示时button的样式
 *      event : 'mouseover',//事件类型，还可以是click,manual
 *      alignType : '4-1',//菜单对齐方式
 *      delay :　0.2,//延迟时间，用于mouseover
 *      useIframeInIE6 : true,//在ie6是否添加iframe
 *      addIframe : false,//是否强制添加iframe
 *  }
 * </pre>
 *
 * @namespace XN.ui
 * @class menu
 * @constructor
 * @param {Object} params
 */

XN.ui.menu = function( params )
{
	var This = this;

	this.config = {
		alignType : '4-1',
		barOnshowClass : '',
		tagName : 'div',
		disalbeButtonClickEvent : true,
		fireOn : 'click',
		keep : 0.2,
        useIframeInIE6 : true,
        effectTime : 50 
	};

	$extend( this.config , params );
	
	var frame;
	
	if ( this.getConfig( 'text' ) )
	{
		this.frame = frame = $element( this.getConfig( 'tagName' ) );
		frame.setContent( this.getConfig( 'text' ) );
	}
	else if ( this.getConfig( 'button' ) )
	{
		this.frame = frame = $( this.getConfig( 'button' ) );
	}
	else return false;
	
	this._alignType = this.getConfig( 'alignType' );
	
	if ( this.getConfig( 'menu' ) )
	{
        $( this.getConfig( 'menu' ) ).hide();

		this.menu = new XN.ui.fixPositionElement(
		{
			id : this.getConfig( 'menu' ),
			alignType : this._alignType,
			alignWith : this.getConfig( 'alignWith' ) || this.frame,
			addIframe : this.getConfig( 'addIframe' ),
            useIframeInIE6 : this.getConfig( 'useIframeInIE6' )
		}); 
		this.container = this.menu.frame;
		this._canAddSubMenu = false;
	}
	else
	{
        var dt = $element( 'div' );
        dt.hide();
		this.menu = new XN.ui.fixPositionElement(
		{
			//tagName : 'div',
            id : dt,
            alignType : this._alignType,
			alignWith : this.getConfig( 'alignWith' ) || this.frame,
			addIframe : this.getConfig( 'addIframe' ),
            useIframeInIE6 : this.getConfig( 'useIframeInIE6' )
		});
		this.container = $element( 'div' );
		this._menu.setContent( this.container );
	}
    
	
	this.menu.setIndex( 10001 );
	

	XN.event.addEvent( this.menu.frame , 'click' , function( e )
	{
		e = e || window.event;
        This._frameOnClick( e );
	} , false );
	this.menu.setOffsetX( this.getConfig( 'offsetX' ) || 0 );
	this.menu.setOffsetY( this.getConfig( 'offsetY' ) || 0 );
	var eventType = this.getConfig( 'event' );
	if ( eventType == 'click' )
	{
		XN.event.addEvent( this.frame , 'click' , function( e )
		{
			This._buttonClick( e || window.event );
		} );
		XN.event.addEvent( document , 'click' , function( e )
		{
			This._documentClick( e || window.event );
		} );
	}
	else if ( eventType == 'mouseover' )
	{
		XN.event.addEvent( this.frame , 'mouseover' , function( e )
		{
			This._frameMouseOver( e || window.event );
		} );
		
		if ( this.getConfig( 'disalbeButtonClickEvent' ) )
		{
			XN.event.addEvent( this.frame , 'onclick' , function( e )
			{
				XN.event.stop( e || window.event );
			} );
		}
		
		XN.event.addEvent( this.frame , 'mouseleave' , function()
		{
            This._buttonMouseLeave();
		});
		
		XN.event.addEvent( this.menu.frame , 'mouseleave' , function()
		{
            This._menuMouseLeave();
		});
		
		XN.event.addEvent( this.menu.frame , 'mouseover' , function()
		{
			This._mouseOverMenu = true;
		});
	}
	else if ( eventType == 'manual' )
	{
	}

    XN.event.addEvent( window , 'resize' , function()
    {
        This.menu.refresh();
    });

	this.hide();
};

XN.ui.menu.prototype = $extend( {} , XN.ui.container );

$extend( XN.ui.menu.prototype ,
{
	isShow : true,
	menu : null,
	_alignType : null,
	_button : null,
	_canAddSubMenu : true,
	_delayTimer : null,
	_mouseOverMenu : false,
	_mouseOverButton : false,
	_clearTimer : function()
	{
		if ( this._delayTimer )
		{
			clearTimeout( this._delayTimer );
			this._delayTimer = null;
		}
	},
	_buttonClick : function( e )
	{
		XN.event.stop( e );
		if ( this.isShow ) 
			this.hide();
		else
			this.show();
	},
	_documentClick : function( e )
	{
		this.hide();
	},
    
    _frameOnClick : function( e )
    {
        var This = this;
		var el = XN.event.element( e );
		var tag = el.tagName.toLowerCase();

        if ( tag == 'a' ) return true;
		if ( ( tag == 'input' && ( el.type == 'radio' || el.type == 'checkbox' ) ) || tag == 'label' )
        {
            this.isShow = false;
            setTimeout( function()
            {
                This.isShow = true;
            } , 20 );
            return true;
        }
        
        while ( el != this.menu.frame && el.tagName && el.tagName.toLowerCase() != 'a' )
        {
            el = el.parentNode;
        } 
        
        if ( el.tagName.toLowerCase() == 'a' ) return true;
        
        XN.event.stop( e );
    },

	_frameMouseOver : function( e )
	{
		var This = this;
		this._mouseOverButton = true;
		
		this._clearTimer();
		
		var delay = this.getConfig( 'delay' );
		if ( delay )
		{
			this._delayTimer = setTimeout( function()
			{
				if ( This._mouseOverButton ) This.show();
			} , delay * 1000 );
		}
		else
		{
			This.show();
		}
		XN.event.stop( e );
	},
	_buttonMouseLeave : function()
	{
		var This = this;
		this._mouseOverButton = false;
		this._clearTimer();
		setTimeout( function()
		{
			if ( !This._mouseOverMenu ) This.hide();
		} , this.getConfig( 'effectTime' ) );
	},
	_menuMouseLeave : function()
	{
        var This = this;
		this._mouseOverMenu = false;
		this._clearTimer();
		setTimeout( function()
		{
			if ( !This._mouseOverButton ) This.hide();
		} , this.getConfig( 'effectTime' ) );
	},
	getConfig : function( key )
	{
		var patch = 
		{
			'hoverClass' : 'barOnshowClass',
			'event' : 'fireOn',
			'button' : 'bar',
			'delay' : 'keep'
		};
		if ( patch[ key ] ) return this.config[ key ]  || this.config[ patch[ key ] ];

		return this.config[ key ];
	},

    /**
     * 显示菜单
     * @method show
     * @return {XN.ui.menu} this
     */

	show : function()
	{
		if ( this.isShow ) return this;
		this.menu.show();
		this.frame.addClass( this.getConfig( 'hoverClass' ) );
		this.onShow();
		this.isShow = true;
		return this;
	},
	
    /**
     * 设置菜单宽度
     * @method setWidth
     * @param {Int} width
     * @return {XN.ui.menu} this
     */

    setWidth : function( w )
	{
		this.menu.frame.style.width = w + 'px';
		this.menu.refresh();
        return this;
	},
	    
    /**
     * 隐藏菜单
     * @method hide
     * @return {XN.ui.menu} this
     */

    hide : function()
	{
		if ( !this.isShow ) return this;
		this.menu.hide();
		this.frame.delClass( this.getConfig( 'hoverClass' ) );
		this.isShow = false;
        this.onHide();
		return this;
	},
    
    /**
     * 刷新菜单
     * @method refresh
     * @return {XN.ui.menu} this
     */

    refresh : function()
    {
        if ( this.isShow )
        {
            this.menu.show();
        }
        return this;
    },

 	onShow : XN.func.empty,
	onHide : XN.func.empty
} );

XN.event.enableCustomEvent( XN.ui.menu.prototype );
/**
 * 自动完成
 * <pre>
 * 参数如下: 
 *  {
 *      input:id,//要使用自动完成的input元素
 *      searchDelay:num,//输入与搜索之间的延迟
 *      DS:obj,//搜索用的数据源,参见XN.util
 *      enableCache:true,//是否使用缓存
 *      maxCache:10//最大缓存长度
 *  }
 * </pre>
 *
 * @namespace XN.ui
 * @class autoComplete
 * @constructor
 * @param {Object} p
 * @extends XN.ui.element
 */

XN.ui.autoComplete = function( p )
{
	var This = this;
	
	this.config = this.config || {};
	
	$extend( this.config ,
	{
		inputTip : null,
		searchDelay : 0.2,
		DS : null,
		enableCache : true,
		maxCache : 10
	});
	
	$extend( this.config , p );
	
	if ( this.getConfig( 'enableCache' ) )
	{
		this.cache = new XN.util.cache({
			cacheLength : this.getConfig( 'maxCache' )
		});
	}
	
	if ( this.getConfig( 'input' ) )
	{
		var input = this.input = $( this.getConfig( 'input' ) );
	}
	else
	{
		var input = this.input = $element( 'input' );
        input.type = 'text';
        input.addClass( 'input-text' );
	}

	
	this.frame = input;
	
	XN.event.addEvent( input , 'focus' , function( e )
	{
		This._startCheck();
		This.fireEvent( 'focus' );
	});
	
	XN.event.addEvent( input , 'blur' , function( e )
	{
		This._endCheck();
		This.fireEvent( 'blur' );	
	});

    this.addEvent( 'focus' , function()
    {
        var v = this.input.value;
        if ( v == '' || v == this.getConfig( 'inputTip' ) )
        {
            this.fireEvent( 'noinput' );
        }
    });

    this.addEvent( 'blur' , function()
    {
        this._lastInput = null;
    });

    XN.event.addEvent( input , 'click' , function( e )
    {
        XN.event.stop( e || window.event );
    });
	
	XN.event.addEvent( input , 'keydown' , function( e )
	{
		This._userInput = true;
		e = e || window.event;
		if ( e.keyCode == 13 ) XN.event.stop( e );
		This.fireEvent( 'keydown' , e );
	});
	
	input.setAttribute( 'AutoComplete' , 'off' );

    this.DS = this.getConfig( 'DS' );
};

XN.ui.autoComplete.prototype = $extend( {} , XN.ui.element );

$extend( XN.ui.autoComplete.prototype,
{
	input : null,
	cache : null,
	_userInput : false,
	_lastInput : null,
	
	getConfig : function( key )
	{
		if ( key == 'input' ) return this.config[ 'input' ] || this.config[ 'id' ];
		return this.config[ key ];
	},
	
	_startCheck : function()
	{
		var This = this;
		this._inputTimer = setInterval(function()
		{
			if( This._userInput )
			{
			 	This._userInput = false;
				return;
			}
			This._checkInput();
		},this.getConfig( 'searchDelay' ) * 1000);
	},
	
	_endCheck : function()
	{
		clearInterval( this._inputTimer );
		this._inputTimer = null;		
	},
	
   
	_checkInput : function()
	{
		var This = this;
		var cv = this.input.value;
		
		if( XN.string.isBlank( cv ) )
		{
			if ( this._lastInput === '' )
			{
				return;
			}

			this._lastInput = '';
            this.fireEvent( 'noinput' );

			return;
		}
		
		if( cv == this._lastInput )
        { 
            return;
        }

		this._lastInput = cv;
		
		this.fireEvent( 'searchbegin' );
		
		if( this.cache )
		{
			var result = this.cache.get( cv );
			if( result )
			{
				this.fireEvent( 'searchover' , result );
				return;
			}
		}
		
		if ( !this.DS )
		{
            XN.log( 'no ds' );
			this.fireEvent( 'NO_DS' );
			return;
		}
		
		this.DS.query( cv , function( r )
		{
			if( This.cache ) This.cache.add( cv , r );
			This.fireEvent( 'searchover' , r );
		});		
	}
});

XN.event.enableCustomEvent( XN.ui.autoComplete.prototype );

(function()
{

var completeMenus = {};

getCompleteMenu = function( id )
{
    return  completeMenus[ id ];
};

/**
 * 自动完成菜单
 * @namespace XN.ui
 * @class autoCompleteMenu
 * @constructor
 * @param {Object} p
 * @extends XN.ui.autoComplete
 */

XN.ui.autoCompleteMenu  = function( p )
{
	var This = this;
    
    this._MID = XN.util.createObjID();
    
    completeMenus[ this._MID ] = this;

	this.config = this.config || {};
	
	$extend( this.config ,
	{
		ulClassName : '',
		liClassName : '',
		liHoverClass : 'm-autosug-hover',
		aClassName : '',
		noResult : '没有匹配结果',
		dataLoading : '正在加载数据...',
		noInput : null,
		autoSelectFirst : false
	} );
	
	XN.ui.autoComplete.call( this , p );
	
	var input = this.input;

	var m = $element('div');
    m.innerHTML = this.getConfig( 'wrapper' ) || this._wrapper();
	
    this._menuList = m.firstChild;

	this._ul = this._menuList.getElementsByTagName( 'ul' )[0];
	
	this.menu = new XN.ui.menu(
	{
		button : input,
		menu : this._menuList,
		fireOn : 'manual'
	});

	this.addEvent( 'keydown' , this._inputOnkeydown );
	
	XN.event.addEvent( this._ul , 'mousedown' , function( e )
	{
		This._menuOnclick( e || window.event );
	});
	
    /*
	XN.event.addEvent( this._ul , 'mousemove' , function( e )
	{
		return This._menuOnmouseover( e || window.event );
	});
    */
	/*XN.event.addEvent( document , 'click' , function(){
		This.menu.hide();
	} , false );*/
    XN.event.addEvent( input, 'blur', function()
    {
        This.menu.hide();
    });

	this.menu.hide();
	
	/*
	 * 没有输入时关闭菜单
	 */
	this.addEvent( 'noinput' , function()
	{
		var tip = this.getConfig( 'noInput' );
		if( !tip )
		{
			this.menu.hide();
			return;
		}
		this._ul.innerHTML = '<li>' + tip + '</li>';
		this.menu.show();
	});
	
	this.addEvent( 'NO_DS' , function()
	{
		var tip = this.getConfig( 'dataLoading' );
		this._ul.innerHTML = '<li>' + tip + '</li>';
		this.menu.show();			
	});
			
	this.addEvent( 'searchover' , this._buildMenu );
};

XN.ui.autoCompleteMenu.prototype = $extend( {} , XN.ui.autoComplete.prototype );

$extend( XN.ui.autoCompleteMenu.prototype ,
{
	menu : null,
	_menuList : null,
	_ul : null,
	_currentLi : null,
    _highlightMenuItem : function( li )
	{
		if ( li == this._currentLi ) return;
		var hoverClass = this.getConfig( 'liHoverClass' );
		if ( this._currentLi !== null )
        {
            XN.element.delClass( this._currentLi , hoverClass );
        }
		XN.element.addClass( li , hoverClass );
		this._currentLi = li;
		var aid = this._currentLi.getAttribute( 'aid' );

		if( aid )
        {
            this.fireEvent( 'highlight' , this.result[ parseInt( aid ) ] );
	    }
    },

	/*
	 *  键盘事件处理函数
	 */

	_inputOnkeydown : function( event )
	{
		var li;

		/*
		 *   回车选择一个菜单项
		 */

		if ( event.keyCode == 13 )
		{
			if( this.menu.isShow && this._currentLi )
			{
				var aid = this._currentLi.getAttribute( 'aid' );
				if( aid ) this._selectMenuItem( parseInt( aid ) );
			}
			return false;
		}

		/*
		 *  向上高亮上一个
		 */

		if ( event.keyCode == 38 )
		{
			if ( this._currentLi && this._currentLi.previousSibling )
			{
				li = 	this._currentLi.previousSibling;
			}
			else
			{
				li = this._ul.lastChild;			
			}
			this._highlightMenuItem( li );
			return false;
		}

		/*
		 *  向下高亮下一个
		 */

		if ( event.keyCode == 40 )
		{
			if ( this._currentLi && this._currentLi.nextSibling )
			{
				li = 	this._currentLi.nextSibling;
			}
			else
			{
				li = this._ul.firstChild;			
			}
			this._highlightMenuItem( li );
			return false;
		}
		
		return true;
	},

	/*
	 *  当在菜单上点击时触发
	 */	
 
	_menuOnclick : function( event )
	{
		var el = XN.event.element( event );
		
		while ( el && el.tagName && el.tagName.toLowerCase() !== 'li' )
		{
			el = el.parentNode;
		}
        
		if ( !el || el.nodeType !== 1 || !el.getAttribute( 'aid' ) ) return false;
        this._selectMenuItem( parseInt( el.getAttribute( 'aid' ) ) );
        return false;
	},

	/*
	 *  当在菜单上移动鼠标时触发
	 */

	_menuOnmouseover : function( event )
	{
		var el = XN.event.element( event );
	    if ( el.parentNode == $( 'dropmenuHolder' ) ) return;
		while ( el && el.tagName &&  el.tagName.toLowerCase() !== 'li' )
		{
			el = el.parentNode;
		}
		
		if ( !el || el.nodeType !== 1 || !el.getAttribute( 'aid' ) ) return false;
		this._highlightMenuItem( el );
		return false;
	},
	
	/*
	 *  选择一个菜单项
	 */

	_selectMenuItem : function( id )
	{
		this.menu.hide();
		this.input.focus();
		this.fireEvent( 'select' , this.result[ id ] );
		this._lastInput = this.input.value;
	},

	/*
	 * 匹配结束,显示匹配结果
	 */

	_buildMenu : function( result )
	{
		var This = this;
		this.result = result;
	    
		if ( result.length == 0 )
		{
			var noResult = this.getConfig( 'noResult' );

			if ( isFunction( noResult ) )
			{
				noResult = noResult.call( this );
			}

			this._ul.innerHTML = '<li>' + noResult + '</li>';
			this.menu.show();
			this._currentLi = null;
			return;
		}

		var lis = [];

        lis.push( this.firstMenuItem() );
	    
        var len = result.length - 1;

        XN.array.each( result , function( i , v )
		{
			lis.push( '<li onmouseover="getCompleteMenu(' + This._MID + ')._highlightMenuItem(this);" aid="' + i + '">' + This.buildMenu( v ) + '</li>' );
		});
		
        lis.push( this.lastMenuItem() );

        this._ul.innerHTML = lis.join('');
		
        if( this.getConfig( 'autoSelectFirst' ) ) this._highlightMenuItem( this._ul.firstChild );
		
        this.menu.show();
	},
    firstMenuItem : function()
    {
        return '';
    },
    
    lastMenuItem : function()
    {
        return '';
    },

	buildMenu : function( r )
	{
		return '<li>' + r.name + '</li>';
	},
	setMenuWidth : function( w )
	{
		this.menu.setWidth( w );
	}
} );
//XN.ui._friendsCacheData = null;
    patchForUiMenu();
})();

XN.ui.friendSelector = function( params )
{
	var This = this;
	this.config = this.config || {};
	
	$extend( this.config ,
	{
		getFriendsUrl:'/getfriendsajax.do?s=1',
        url : '/friendsSelector.do',
        param : {}
	});

	XN.ui.autoCompleteMenu.call( this , params );
	
	this.addEvent( 'select' , function( r )
	{
		this.input.value = r.name;
		if ( this.onSelectOne ) this.onSelectOne( r );			
	} );
	
	this.buildMenu = function( r )
	{
		return r.name ;
	};
	
	this.addEvent( 'focus' , function()
	{
		if ( this._ready ) return;
		if ( this._isLoading ) return;
        this.loadFriends();
	});
};

XN.ui.friendSelector.prototype = $extend( {} , XN.ui.autoCompleteMenu.prototype );
$extend( XN.ui.friendSelector.prototype,
{
	_isLoading:false,
	_ready:false,
	
    isReady : function()
    {
        return this._ready;
    },

    isLoading : function()
    {
        return this._isLoading;
    },
    
    loadFriends:function( r )
	{
        if ( this.isLoading() ) return;
        this._isLoading = true;
        var This = this;
        var p = {};
        p[ 'init' ] = true;
        p[ 'uid' ] = false;
        p[ 'uhead' ] = false;
        p[ 'uname' ] = false;
        p[ 'group' ] = false;
        p[ 'net' ] = false;
        p[ 'param' ] = this.getConfig( 'param' );

        new XN.NET.xmlhttp(
        {
            useCache : true,
            url : this.getConfig( 'url' ),
            method : 'get',
            data : 'p=' + XN.JSON.build( p ),
            onSuccess : function( r )
            {
                r = XN.JSON.parse( r.responseText );
                This._onload( r );
            }
        });
    },
    
    _onload : function( r )
    {
        this.isLoading = false;
        this._ready = true;
        this.config.qkey = r.qkey;
        this.DS = new XN.util.DS_friends(
        {
            url : this.getConfig( 'url' ),
            qkey : this.getConfig( 'qkey' ),
            limit : this.getConfig( 'limit' ) 
        });
    }
});

XN.ui.friendSelectorSynchronous = function( a , b )
{
    function s( id , ac , v )
    {
        if ( isObject( id ) ) id = id.id;

        if ( v.isReady() )
        {
            try{
                v[ ac ]( id );
            }catch(e){}
        }
        else
        {
            v.addEvent( 'load' , function()
            {
                try{
                    v[ ac ]( id );
                }catch(e){}
            } );
            v.loadFriends();
        }
    }
    
    a.addEvent( 'select' , function( id )
    {
        s( id , 'select' , b );
    } );
    a.addEvent( 'deselect' , function( id )
    {
        s( id , 'deselect' , b );
    } );
    b.addEvent( 'select' , function( id )
    {
        s( id , 'select' , a );
    } );
    b.addEvent( 'deselect' , function( id )
    {
        s( id , 'deselect' , a );
    });
};


(function(){

    /**
     * 多好友选择器
     * <pre>
     * 参数形式如下
     * {
     *      idInputName:'ids',//生成的id字段input的name属性
     *      nameInputName:'names',//生成的name字段input的name属性
     *      url:'/friendsSelector.do',//初始化的url
     *      initParam:{},//初始化参数
     *      param:{},//查询好友的额外参数
     *      maxNum:0//最大数量限制，超出时会触发'overMaxNum'事件
     * }
     * </pre>
     * @namespace XN.ui
     * @class multiFriendSelector
     * @constructor
     * @param {Object} params
     */

    XN.ui.multiFriendSelector = function(params)
    {
        var This = this;
        //ID_PRE ++;
        this._ID = XN.util.createObjID();

        this.config = this.config || {};
        $extend( this.config ,
        {
            inputName : 'ids',
            nameInputName : 'names',
            url : '/friendsSelector.do',
            initParam : {},
            param : {},
            noInput : false,
            maxNum : -1 
        });
        
        $extend( this.config , params );
        
        this.frame = $element('div');
        var div = $element( 'div' );
        div.hide();
        document.body.appendChild( div );
        div.appendChild( this.frame );
        
        this.frame.innerHTML = [
            '<div id="' + this.getID( 'friendsContainer' ) + '" class="tokenizer friendAutoSelector">',
            '<span class="tokenizer_stretcher">^_^</span>',
            '<span class="tab_stop"><input/></span>',
            '<span id="' + this.getID( 'inputContainer' ) + '" class="tokenizer_input"><input id="' + this.getID( 'input' ) + '" type="text" /></span>',
            '</div>',
            '<div class="float-right" id="' + this.getID( 'menu' ) + '"></div>'
        ].join('');
        
        /*
         * patch for old version
         */
        
        this.input = this.getEl( 'input' );
        this.menuContainer = this.getEl( 'menu' );

        //this._friendsContainer = this.frame.firstChild;
        //this._inputContainer = this.frame.getElementsByTagName('span')[2];
        /*
         * patch end
         */


        XN.event.addEvent( this.getEl( 'friendsContainer' )  , 'click' , function( e )
        {
            This._parseClickEvent( e || window.event ); 
        });
        
        this.autoComplete = new XN.ui.friendSelector(
        {
            id : this.input,
            inputTip : '输入好友姓名...',
            autoSelectFirst : true,
            url : this.getConfig( 'url' ),
            param : this.getConfig( 'param' )
        });

        this.autoComplete.loadFriends = function( r )
        {
            if ( this.isLoading() ) return;
            this._isLoading = true;
            var p = {};
            p[ 'init' ] = true;
            p[ 'uid' ] = true;
            p[ 'uhead' ] = false;
            p[ 'uname' ] = true;
            p[ 'group' ] = false;
            p[ 'net' ] = false;

            $extend( p , This.getConfig( 'initParam' ) );
            
            p[ 'param' ] = this.getConfig( 'param' );

            new XN.NET.xmlhttp(
            {
                useCache : true,
                url : this.getConfig( 'url' ),
                method : 'get',
                data : 'p=' + XN.JSON.build( p ),
                onSuccess : function( r )
                {
                    r = XN.JSON.parse( r.responseText );
                    This._allFriends = r.candidate;
                    This.fireEvent( 'load' );
                    This.autoComplete._onload( r );
                }
            });
        };
        
        this.autoComplete.buildMenu = function(r)
        {
            return '<p>' + r.name + '</p>';
        };

        this.autoComplete.setMenuWidth(129);
        this.autoComplete.addEvent( 'keydown' ,function( e )
        {
            This._onInputKeydown(e);
        });
        this.autoComplete.addEvent( 'select' , function( r )
        {
            XN.log( this.input );
            this.input.value = '';
            This.selectFriend( r );
        });

        if ( this.getConfig( 'noInput' ) )
        {
            this.input.hide();
        }
        
        this.fireEvent( 'init' );
    };
    var proto = XN.ui.multiFriendSelector.prototype = $extend( {} , XN.ui.element );
    
    $extend( proto ,
    {
        //_friendsContainer : null,
        //_inputContainer : null,
        
        /**
         * 选择器是否就绪
         * @method isReady
         * @return {Boolean}
         */

        isReady : function()
        {
            return this.autoComplete.isReady();
        },

        isLoading : function()
        {
            return this.autoComplete.isLoading();
        },

        /**
         * 加载好友数据
         * @method loadFriends
         */

        loadFriends : function()
        {
            this.autoComplete.loadFriends();
        },

        /**
         * 跟据用户id得到一个用户对象
         * @method getUserByID
         * @param {String} id
         * @return {Object}
         */

        getUserByID : function( id )
        {
            id = String( id );
            var rt = null;
            XN.array.each( this._allFriends , function( i , v )
            {
                if ( String( v.id ) == id )
                {
                    rt = v;
                    return false;
                }
            } );
            return rt;
        },

        getConfig : function( key )
        {
            if ( key == 'inputName' ) return this.config[ 'idInputName' ] || this.config[ 'inputName' ];
            return this.config[ key ];
        },

        getID : function( id )
        {
            return 'mfs_' + this._ID + id;
        },
        
        getFriendID : function( id )
        {
            return this.getID( 'friend_' + id );
        },
    
        getFriendEl : function( id )
        {
            return $( this.getFriendID( id ) );
        },

        getEl : function( id )
        {
            return $( this.getID( id ) );
        },

        getFriendsNum : function()
        {
            return this.getEl( 'friendsContainer' ).getElementsByTagName( 'a' ).length;
        },
        
        /**
         * 获取已选好友的id
         * @method getSelectedFriends
         * @return {Array}
         */

        getSelectedFriends : function()
        {
            var rt = [];
            var a = XN.array.build( this.getEl( 'friendsContainer' ).getElementsByTagName( 'a' ) );
            XN.array.each( a , function( i , v )
            {
                rt.push( v.uid + '' );
            });
            return rt;
        },
        
        /**
         * 重设选择器
         * @method reset
         */

        reset : function()
        {
            this.deselectAll(); 
        },

        /**
         * 取消全选
         * @method deselectAll
         */

        deselectAll : function()
        {
            var els = XN.array.build( this.getEl( 'friendsContainer' ).getElementsByTagName( 'a' ) );
            XN.array.each( els , function( i , v )
            {
                XN.element.remove( v );
            });
            this.fireEvent( 'deselectAll' , this.getIds() );
        },
        
        /**
         * 选择一组好友
         * @method selectFriends
         * @param {Array} a
         */

        selectFriends : function( fs )
        {
            var This = this;
            XN.array.each( fs , function( i , v )
            {
                This.select( v );
            } );
        },
        
        /**
         * 反选一组好友
         * @method deselectFriends
         * @param {Array} a
         */

        deselectFriends : function( fs )
        {
            var This = this;
            XN.array.each( fs , function( i , v )
            {
                This.deselect( v );
            } );
        },
        
        /**
         * 选择一个好友
         * @method select
         * @param {String} id
         */

        select : function( o )
        {
            XN.log( 'mfs select' );
            
            var maxNum = this.getConfig( 'maxNum' );
            
            if ( maxNum !== -1 )
            {
                if ( this.getFriendsNum() ==  maxNum )
                {
                    this.fireEvent( 'overMaxNum' , maxNum );
                    return;
                }
            }

            if ( isString( o ) )
            {
                o = {
                    id : o,
                    name : this.getUserByID( o ).name
                };
            }


            
            if ( this.getFriendEl( o.id ) ) return;
            
            this.getEl( 'friendsContainer' ).insertBefore( this.createFriendHTML( o.id , o.name ) , this.getEl( 'inputContainer' ) );
            this.fireEvent( 'select' , o.id );
        },
        
        /**
         * 反选一个好友
         * @method deselect
         * @param {String} id
         */

        deselect : function( uid )
        {
            if ( !this.getFriendEl( uid ) )return;
            this.getFriendEl( uid ).remove();
            this.fireEvent( 'deselect' , uid );
        },

        _parseClickEvent : function( e )
        {
            var el = XN.event.element( e );
            XN.event.stop( e );
            if ( el && el.getAttribute( 'action' ) )
            {
                this.deselectFriend( el.getAttribute( 'uid' ) );
            }
        },

        createFriendHTML : function( uid , uname )
        {
            var a = $element( 'a' );
            a.id = this.getFriendID( uid );
            a.uid = uid;
            a.href = '#nogo';
            a.className = 'token';
            a.tabindex = '-1';
            a.innerHTML = [
                '<span>\n<span>\n<span>\n<span>\n<input type=\"hidden\" value=\"',
                uid,
                '" name=\"',
                this.getConfig( 'inputName' ),
                '\" />\n',
                '<input type=\"hidden\" value=\"',
                uname,
                '" name=\"',
                this.getConfig( 'nameInputName' ),
                '\" />\n',
                uname,
                '<span uid=\"',
                uid,
                '\" action=\"x\" class=\"x\" onmouseout=\"this.className=\'x\'\" onmouseover=\"this.className=\'x_hover\'\" >\n</span>\n</span>\n</span>\n</span>\n</span>'
            ].join( '' );
            return a;
        },

        _onInputKeydown : function( event )
        {
            var i = this.getEl( 'inputContainer' ),
            pa = i.previousSibling,
            na = i.nextSibling,
            input = this.input,
            c = this.getEl( 'friendsContainer' );
            if ( event.keyCode == 8 && this.input.value =='' )
            {
                if( pa )
                {
                    c.removeChild( pa );
                    this.deselectFriend( pa.aid );
                }
                return true;
            }
            else if ( event.keyCode == 37 && this.input.value == '' )
            {
                if ( pa && pa.tagName.toLowerCase() == 'a' )
                {
                    i.parentNode.removeChild( i );
                    c.insertBefore( i , pa );
                    setTimeout( function(){input.focus();} , 0 );
                }
                return true;
            }
            else if ( event.keyCode == 39 && this.input.value == '' )
            {
                if ( na && na.tagName.toLowerCase() == 'a' )
                {
                    i.parentNode.removeChild( i );
                    XN.dom.insertAfter( i , na );
                    setTimeout( function(){input.focus();} , 0 );
                }
                return true;
            }		
            return false
        }
    });

    XN.event.enableCustomEvent( proto );

    /*
     * patch for old version
     */
    proto.deSelectAll = proto.deselectAll;
    proto.deSelectFriend = proto.deselectFriend = proto.deselect;
    proto.selectFriend = proto.select;
    proto.getSelectedFriendsID = proto.getSelectedFriends;
    proto.getIds = proto.getSelectedFriends;
    /*
     * patch end
     */
})();

XN.ui.friendSelectorWithMenu = function( p )
{
    var selector = new XN.ui.friendSelector( p );
    var menu = new XN.ui.friendSelectorMenu({
        url : selector.getConfig( 'url' ),
        param : selector.getConfig( 'param' ),
        multi : false ,
		alignType:p.alignType,
		offsetX:p.offsetX,
		offsetY:p.offsetY
    });

    var div = $element( 'div' );
    //selector.frame.parentNode.appendChild( div );
    div.addChild( selector );
    div.addChild( menu );
    selector.frame = div;
    //XN.ui.friendSelectorSynchronous( selector , menu );
    selector.addEvent( 'focus' , function()
    {
        menu.menu.hide();
    });

    menu.addEvent( 'select' , function( p )
    {
        var This = this;
        setTimeout( function()
        {
            This.menu.hide();
        },30);
        selector.fireEvent( 'select' , this.getUserByID( p ) );
    });
    
    if ( XN.browser.Gecko )
    {
        menu.menu.menu.setOffsetY( 1 );
    }

    return selector;

};

XN.ui.multiFriendSelectorWithMenu = function( p )
{
    var selector = new XN.ui.multiFriendSelector( p );

    var menu = new XN.ui.friendSelectorMenu({
        url : selector.getConfig( 'url' ),
        param : selector.getConfig( 'param' ),
        multi : true
    });
    
    selector.menuContainer.setContent( menu );
    
    XN.ui.friendSelectorSynchronous( selector , menu );
    
    return selector;
};

(function( ns )
{
	//var ID_PRE = 0;	
	var DEBUG = false;
	var addEvent = XN.event.addEvent;
	
	var log = function( s )
	{
		if ( DEBUG ) XN.log ( isString( s ) ? 'ui.tabView:' + s : s );
		return s;
	};

	/**
	 * tabview
	 * @namespace XN.ui
	 * @class tabView
	 * @constructor
	 * @param {Object} params
	 */
	
	ns.tabView = function( params )
	{
		this.config = {
			selectedClass : 'select',
			event : 'click',
            alwaysReload : false,
			mouseOverDelay : 0.2
		};
		$extend( this.config , params );
		this.init();
	};

	ns.tabView.prototype = {	
		
		_tabs : null,
		_currentTab : null,
		_idPre : null,
		_tabIndex : 0,

		init : function()
		{
			this._idPre = XN.util.createObjID();
			this._tabs = [];
		},
		
		getConfig : function( key )
		{
			if ( key == 'activeClass' ) return this.config[ 'activeClass' ] || this.config[ 'selectedClass' ];
			return this.config[ key ];
		},

		_getID : function( el )
		{
			log( '_getID start' );
			log( 'param:' );
			log( el );
			
			if ( isString( el ) ) return log( el );
			if ( el.id ) return log( el.id );
			
			log( 'do not have id' );
			this._tabIndex ++;
			el.setAttribute( 'id' , 'tabview_' + this._idPre + '_' + this._tabIndex );

			return log( el.id );
		},

		
		//get tab obj by key or element id or element refer
		_getTab : function( id )
		{
			log( '_getTab start' );
			log( 'param:id' );
			log( id );
			if ( !id ) return log( id );
			
			if ( id.label ) return log( id );

			
			var key = this._getID( id );
			log( 'key:' + key );
			
			var tabs = this._tabs;
			
			log( 'all tabs' );
			log( tabs );
			
			for ( var i = tabs.length - 1 ; i >= 0 ; i -- )
			{
				if ( tabs[ i ].key == key ) {
					log( '_getTab end' );
					return log( tabs[ i ] );
				} 
			}
			
			log( '_getTab end' );	
			return log( null );
		},
		
		/**
		 * @method getCurrentTab
		 * @return {Object}
		 */
		
		getCurrentTab : function()
		{
			return this._getTab( this._currentTab );
		},
		
		/**
		 * @method setCurrentTab
		 * @param {String} tab id
		 * @param {Boolean} forceReload
		 * @return {Object} this
		 */
		
		setCurrentTab : function( tab , forceReload )
		{
			log ( 'setCurrentTab start' );
			var oldC = this.getCurrentTab();
			var nowC = this._getTab( tab );
			
			log ( 'old current:' );
			log( oldC );
			log( 'now current:' );
			log( nowC );
			
			if ( oldC && oldC.key == nowC.key && !forceReload ) return;
			
			if ( oldC ) this._deactiveTab( oldC );
			this._activeTab( nowC );

			this._setCurrentTab( nowC );
			log( 'setCurrentTab end' );

            this.fireEvent( 'change' , nowC );
			
            return this;
		},

		/**
		 * @method reset
		 * @return {Object} this
		 */
		
		reset : function()
		{
			var tab = this.getCurrentTab();
			if ( tab )
			{
				this._deactiveTab( tab );
			}
			this._setCurrentTab( null );
			return this;
		},

		_activeTab : function( tab )
		{
			log( '_activeTab:' );
			log( tab );
			
			tab.getEl( 'label' ).addClass( this.getConfig( 'activeClass' ) );
			if ( tab.content ) tab.getEl( 'content' ).show();
			tab.onActive( tab );
			
			log( '_activeTab end' );
		},
		
		_deactiveTab : function( tab )
		{
            //防止元素被销毁
            if ( tab.getEl( 'label' ) )
            {
			    tab.getEl( 'label' ).delClass( this.getConfig( 'activeClass' ) );
            }
			if ( tab.content ) tab.getEl( 'content' ).hide();
			tab.onInactive( tab );
		},

		_setCurrentTab : function( tab )
		{
			log( '_setCurrentTab start' );
			tab = this._getTab( tab );
			
			log( 'currentTab:' );
			log( tab );
			
			this._currentTab = tab ? tab.key : null;
			
			log( 'this._currentTab' );
			log( this._currentTab );
			
			log( '_setCurrentTab end' );
		},

		/**
		 * @method addTab
		 * @param {Object} t
		 * @return {Object} this
		 */
		
		addTab : function( t )
		{
			
			log( 'addTab start' );
			log( 'params:' );
			log( t );
			
			var This = this;
			
			var tab = {
				onActive : XN.func.empty,
				onClick : XN.func.empty,
				onInactive : XN.func.empty,
				onInit : XN.func.empty,
				getEl : function( key )
				{
					return $( this[ key ] );
				},
				active : false
			};
			
			t.label = this._getID( t.label );
			log( 'get label id:' + t.label );
			t.key = t.key || t.label;
			log( 'get key:' +t.key );

			if ( t.content )
			{
				t.content = this._getID( t.content );
				log( 'get content id:' + t.content );
			}
			
			$extend( tab , t );

			this._tabs.push( tab );
			
			log( 'all tabs' );
			log( this._tabs );
			
			if ( tab.active && this._currentTab === null )
			{
				if ( tab.content ) tab.getEl( 'content' ).show();
				tab.getEl( 'label' ).addClass( this.getConfig( 'activeClass' ) );
				this._setCurrentTab( tab );
			}
			else
			{
				if ( tab.content ) tab.getEl( 'content' ).hide();
			}

			var ev = this.getConfig( 'event' );
			
			if ( ev == 'click' ){
				addEvent( tab.getEl( 'label' ) , 'click' , function( e )
				{
					e = e || window.event;
					XN.event.stop( e );
					This._eventHander( e , tab.getEl( 'label' ) );
				} , false );
			}
			else if ( ev == 'mouseover' )
			{
				var isMouseOn = true;
				var timer = null;
				
				addEvent( tab.getEl( 'label' ) , 'mouseover' , function( e )
				{
					var el = this;
					isMouseOn = true;
					timer = setTimeout( function()
					{
						if ( !isMouseOn ) return;
						e = e || window.event;
						This._eventHander( e , tab.getEl( 'label' ) );
					} , This.getConfig( 'mouseOverDelay' ) * 1000 );
				} , false );
				
				addEvent( tab.getEl( 'label' ) , 'mouseleave' , function( e )
				{
					isMouseOn = false;
					if ( timer ) clearTimeout( timer );
				} , false );
			}
			
			tab.onInit( tab );
			
			log( 'addTab end' );
			
			return this;
		},
		
		_eventHander : function( e , el )
		{
			log( 'on click,el:' );
			log( el );
			log( 'get tab form by el:' );
			var tab = this._getTab( el );

		    if ( this.getConfig('alwaysReload') )
            {
                this.setCurrentTab( tab, true );
            }
            else
            {
			    this.setCurrentTab( tab );
            }

            tab.onClick( e , tab );
		},
		
		/**
		 * @method refresh
		 * @return {Object} this
		 */
		
		refresh : function()
		{
			this._activeTab( this.getCurrentTab() );
			return this;
		},

		
		//patch for old version
		
		showTab : function( id , forceReload )
		{
			this.setCurrentTab( id , forceReload );
		},

		hideAll : function()
		{
			this.reset();
		}
	};

	XN.event.enableCustomEvent( ns.tabView.prototype );

})( XN.ui );

/**
 * 强制页面重新渲染
 * @method refreshAll
 */

XN.ui.refreshAll = function()
{
    document.body.style.zoom = 1.1;
    document.body.style.zoom = 1;
};


/**
 * effect
 * @class effect
 * @namespace XN
 * @static
 */

XN.effect = {
	fadeIn:function( element,callBack )
    {
		if(element.fadetimer)return;
		callBack = callBack || XN.FUNC.empty;
		var op = 0;
		element.setOpacity(0);
		element.style.display = '';
		element.fadetimer = setInterval(function(){
            XN.Element.setOpacity(element,(op += 0.20));
            if(op >= 1){
                clearInterval(element.fadetimer);
                element.fadetimer = null;
                callBack(element);
            }
		},60);
	},
	fadeOut:function(element,callBack){
		if(element.fadetimer)return;
		callBack = callBack || XN.FUNC.empty;
		var op =1;
		element.setOpacity(1);
		element.fadetimer = setInterval(function(){
            XN.Element.setOpacity(element,(op -= 0.20));
            if(op <= 0){
                clearInterval(element.fadetimer);
                element.fadetimer = null;
                callBack(element);
                element.setOpacity(1);
            }
        },60);		
	},
	gradient:function(element,r,g,b,callBack){
		if(element.gradientTimer)return;
		callBack = callBack || XN.FUNC.empty;
		element.style.backgroundColor = '#fff';
		element.style.backgroundColor = 'rgb(' + r + ',' + g + ',' + b + ')';
		element.gradientTimer = setInterval(function(){
			b += 10;
			element.style.backgroundColor = 'rgb(' + r + ',' + g + ',' + (b >255 ? 255 : b) + ')';
			if(b > 255){
				clearInterval(element.gradientTimer);
				element.gradientTimer = null;
				callBack(element);
			}
		},60);
	},
	slideOpen:function(element){
		if(element.slidetimer)return;
		if(!element.slideHeight){
			var _position = element.getStyle('position');
			element.setStyle('position:absolute;left:-99999px;top:-99999px;');
			element.show();
			element.slideHeight = element.offsetHeight;
			element.hide();
			element.setStyle('position:' + _position + ';left:auto;top:auto;');
		}
		var eh = element.slideHeight,h = 0;
		var step = parseInt(eh / 10);
		element.style.height = '0px';
		element.style.display = '';
		element.style.overflow = 'hidden';
		element.slidetimer = setInterval(function(){
			element.style.height = (h += step) + 'px';
			if(h >= eh){
				clearInterval(element.slidetimer);
				element.slidetimer = null;
				element.style.height = eh;
				element.style.overflow = element.slideOverflow;
			}
		},50);
	},
	slideClose:function(element){
		if(element.slidetimer)return;
		var eh = element.offsetHeight,h = eh;
		element.slideHeight = eh;
		element.slideOverflow = element.getStyle('overflow');
		element.style.overflow = 'hidden';
		var step = parseInt(eh / 10);
		element.slidetimer = setInterval(function(){
			element.style.height = (h -= step) + 'px';
			if(h <= 0){
				clearInterval(element.slidetimer);
				element.slidetimer = null;
				element.style.display = 'none';
				element.style.height = eh;
				element.style.overflow = element.slideOverflow;
			}
		},50);
	},
	scrollTo:function(element,speed,callBack){
		if(element.scrolltimer)return;
		speed = speed || 10;
		callBack = callBack || XN.FUNC.empty;
		var d = element.realTop();
		var i = XN.EVENT.winHeight();
		var h = document.body.scrollHeight;
		var a = XN.EVENT.scrollTop();;
		var offsetTop = null;
		if(d > a){
			if(d + element.offsetHeight < i + a )return;
			element.scrolltimer = setInterval(function(){
				a +=Math.ceil((d-a) / speed) || 1;
				window.scrollTo(0,a);
			  	if(a == d){
					clearInterval(element.scrolltimer);
					element.scrolltimer = null;
				}
			},10);
		}else{
			element.scrolltimer = setInterval(function(){
				a += Math.ceil((d-a) / speed) || -1;
				window.scrollTo(0,a);
			  	if(a == d){
					clearInterval(element.scrolltimer);
					element.scrolltimer = null;
				}
			},10);			
		}
	}
};

/*
 * patch for old version
 */

XN.EFFECT = XN.Effect = XN.effect;

/**
 * Motion - 动画组件
 *
 * @author  mingcheng<i.feelinglucky@gmail.com>
 * @since   2009-01-26
 * @link    http://www.gracecode.com/
 * @version $Id: motion.js 217 2009-04-06 03:49:08Z i.feelinglucky $
 *
 * @change
 *     [+]new feature  [*]improvement  [!]change  [x]bug fix
 *
 * [*] 2009-04-05
 *      优化对象接口
 *
 * [*] 2009-04-05
 *      优化 customEvent；增强动画函数判断，使其支持自定义函数
 *
 * [*] 2009-03-30
 *      增加 customEvent 函数，优化逻辑
 *
 * [!] 2009-02-01
 *      将 setTimeout 改成了 setInterval ，详见 http://ejohn.org/blog/how-javascript-timers-work/
 *
 * [*] 2009-01-27
 *      调整接口，优化代码
 *
 * [+] 2009-01-26
 *      最初版，完成基本功能
 */
(function(scope) {
    /**
     * Easing Equations
     *
     * @see http://developer.yahoo.com/yui/animation/
     * @see http://www.robertpenner.com/profmx
     * @see http://hikejun.com/demo/yui-base/yui_2x_animation.html
     */
    var Tween = {
        linear: function (t, b, c, d) {
            return c*t/d + b;
        },

        easeIn: function (t, b, c, d) {
            return c*(t/=d)*t + b;
        },

        easeOut: function (t, b, c, d) {
            return -c *(t/=d)*(t-2) + b;
        },

        easeBoth: function (t, b, c, d) {
            if ((t/=d/2) < 1) {
                return c/2*t*t + b;
            }
            return -c/2 * ((--t)*(t-2) - 1) + b;
        },
        
        easeInStrong: function (t, b, c, d) {
            return c*(t/=d)*t*t*t + b;
        },
        
        easeOutStrong: function (t, b, c, d) {
            return -c * ((t=t/d-1)*t*t*t - 1) + b;
        },
        
        easeBothStrong: function (t, b, c, d) {
            if ((t/=d/2) < 1) {
                return c/2*t*t*t*t + b;
            }
            return -c/2 * ((t-=2)*t*t*t - 2) + b;
        },

        elasticIn: function (t, b, c, d, a, p) {
            if (t === 0) { 
                return b; 
            }
            if ( (t /= d) == 1 ) {
                return b+c; 
            }
            if (!p) {
                p=d*0.3; 
            }
            if (!a || a < Math.abs(c)) {
                a = c; 
                var s = p/4;
            } else {
                var s = p/(2*Math.PI) * Math.asin (c/a);
            }
            return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
        },

        elasticOut: function (t, b, c, d, a, p) {
            if (t === 0) {
                return b;
            }
            if ( (t /= d) == 1 ) {
                return b+c;
            }
            if (!p) {
                p=d*0.3;
            }
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            } else {
                var s = p/(2*Math.PI) * Math.asin (c/a);
            }
            return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
        },
        
        elasticBoth: function (t, b, c, d, a, p) {
            if (t === 0) {
                return b;
            }
            if ( (t /= d/2) == 2 ) {
                return b+c;
            }
            if (!p) {
                p = d*(0.3*1.5);
            }
            if ( !a || a < Math.abs(c) ) {
                a = c; 
                var s = p/4;
            }
            else {
                var s = p/(2*Math.PI) * Math.asin (c/a);
            }
            if (t < 1) {
                return - 0.5*(a*Math.pow(2,10*(t-=1)) * 
                        Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
            }
            return a*Math.pow(2,-10*(t-=1)) * 
                    Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
        },

        backIn: function (t, b, c, d, s) {
            if (typeof s == 'undefined') {
               s = 1.70158;
            }
            return c*(t/=d)*t*((s+1)*t - s) + b;
        },

        backOut: function (t, b, c, d, s) {
            if (typeof s == 'undefined') {
                s = 1.70158;
            }
            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
        },
        
        backBoth: function (t, b, c, d, s) {
            if (typeof s == 'undefined') {
                s = 1.70158; 
            }
            if ((t /= d/2 ) < 1) {
                return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
            }
            return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
        },

        bounceIn: function (t, b, c, d) {
            return c - Tween['bounceOut'](d-t, 0, c, d) + b;
        },
        
        bounceOut: function (t, b, c, d) {
            if ((t/=d) < (1/2.75)) {
                return c*(7.5625*t*t) + b;
            } else if (t < (2/2.75)) {
                return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
            } else if (t < (2.5/2.75)) {
                return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
            }
            return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
        },
        
        bounceBoth: function (t, b, c, d) {
            if (t < d/2) {
                return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
            }
            return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
        } /* ,

        // extra, form http://hikejun.com/demo/yui-base/yui_2x_animation.html
        easeInQuad: function (t, b, c, d) {
            return c*(t/=d)*t + b;
        },

        easeOutQuad: function ( t, b, c, d) {
            return -c *(t/=d)*(t-2) + b;
        },

        easeInOutQuad: function ( t, b, c, d) {
            if ((t/=d/2) < 1) return c/2*t*t + b;
            return -c/2 * ((--t)*(t-2) - 1) + b;
        },

        easeInCubic: function ( t, b, c, d) {
            return c*(t/=d)*t*t + b;
        },

        easeOutCubic: function ( t, b, c, d) {
            return c*((t=t/d-1)*t*t + 1) + b;
        },

        easeInOutCubic: function ( t, b, c, d) {
            if ((t/=d/2) < 1) return c/2*t*t*t + b;
            return c/2*((t-=2)*t*t + 2) + b;
        },

        easeInQuart: function ( t, b, c, d) {
            return c*(t/=d)*t*t*t + b;
        },

        easeOutQuart: function ( t, b, c, d) {
            return -c * ((t=t/d-1)*t*t*t - 1) + b;
        },

        easeInOutQuart: function ( t, b, c, d) {
            if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
            return -c/2 * ((t-=2)*t*t*t - 2) + b;
        },

        easeInQuint: function ( t, b, c, d) {
            return c*(t/=d)*t*t*t*t + b;
        },

        easeOutQuint: function ( t, b, c, d) {
            return c*((t=t/d-1)*t*t*t*t + 1) + b;
        },

        easeInOutQuint: function ( t, b, c, d) {
            if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
            return c/2*((t-=2)*t*t*t*t + 2) + b;
        },

        easeInSine: function ( t, b, c, d) {
            return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
        },

        easeOutSine: function ( t, b, c, d) {
            return c * Math.sin(t/d * (Math.PI/2)) + b;
        },

        easeInOutSine: function ( t, b, c, d) {
            return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
        },

        easeInExpo: function ( t, b, c, d) {
            return (t===0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
        },

        easeOutExpo: function ( t, b, c, d) {
            return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
        },

        easeInOutExpo: function ( t, b, c, d) {
            if (t===0) return b;
            if (t==d) return b+c;
            if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
            return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
        },

        easeInCirc: function ( t, b, c, d) {
            return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
        },

        easeOutCirc: function ( t, b, c, d) {
            return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
        },

        easeInOutCirc: function ( t, b, c, d) {
            if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
            return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
        },

        easeInElastic: function ( t, b, c, d) {
            var s=1.70158;var p=0;var a=c;
            if (t===0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*0.3;
            if (a < Math.abs(c)) { a=c; var s=p/4; }
            else var s = p/(2*Math.PI) * Math.asin (c/a);
            return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
        },

        easeOutElastic: function ( t, b, c, d) {
            var s=1.70158;var p=0;var a=c;
            if (t===0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*0.3;
            if (a < Math.abs(c)) { a=c; var s=p/4; }
            else var s = p/(2*Math.PI) * Math.asin (c/a);
            return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
        },

        easeInOutElastic: function ( t, b, c, d) {
            var s=1.70158;var p=0;var a=c;
            if (t===0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(0.3*1.5);
            if (a < Math.abs(c)) { a=c; var s=p/4; }
            else var s = p/(2*Math.PI) * Math.asin (c/a);
            if (t < 1) return -0.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
            return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
        },

        easeInBack: function ( t, b, c, d, s) {
            if (s == undefined) s = 1.70158;
            return c*(t/=d)*t*((s+1)*t - s) + b;
        },

        easeOutBack: function ( t, b, c, d, s) {
            if (s == undefined) s = 1.70158;
            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
        },

        easeInOutBack: function ( t, b, c, d, s) {
            if (s == undefined) s = 1.70158; 
            if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
            return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
        },

        easeInBounce: function ( t, b, c, d) {
            return c - Tween['easeOutBounce']( d-t, 0, c, d) + b;
        },

        easeOutBounce: function ( t, b, c, d) {
            if ((t/=d) < (1/2.75)) {
                return c*(7.5625*t*t) + b;
            } else if (t < (2/2.75)) {
                return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
            } else if (t < (2.5/2.75)) {
                return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
            } else {
                return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
            }
        },

        easeInOutBounce: function ( t, b, c, d) {
            if (t < d/2) return Tween['easeInBounce']( t*2, 0, c, d) * 0.5 + b;
            return Tween['easeOutBounce']( t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
        }
        */
    };

    // 动画行进中
    var _Tweening = function() {
        // 动画进行时的回调
        customEvent(this.onTweening, this);

        if (this.current >= this.frames) {
            this.stop();
            customEvent(this.onComplete, this);
            this.tweening = false;
            return;
        }

        this.current++;
    };

    /**
     * 自定义事件
     * 
     * @params {Function} 事件回调
     * @params {Object} 作用域
     */
    var customEvent = function(func, scope) {
        var args = Array.prototype.slice.call(arguments);
            args = args.slice(2);
        if (typeof func == 'function') {
            try {
                return func.apply(scope || this, args);
            } catch (e) {
                scope.errors = scope.errors || [];
                scope.errors.push(e);
            }
        }
    };

    /**
     * 动画组件
     *
     * @params {String} 动画类型（方程式）
     * @params {Number} 过程动画时间
     */
    scope.Motion = function(tween, duration) {
        this.duration = duration || 1000;
        this.tween = tween || 'linear';
    };

    // 返回动画公式
    scope.Motion.getTweens = function(){return Tween};

    // 原型继承
    scope.Motion.prototype = {
        // 初始化
        init: function() {
            customEvent(this.onInit, this);

            // 默认 35 FPS
            this.fps = this.fps || 35;

            // 计算帧数
            this.frames = Math.ceil((this.duration/1000)*this.fps);
            if (this.frames < 1) this.frames = 1;

            // 确定动画函数，便于计算当前位置
            var f = ('function' == typeof this.tween) ? this.tween : Tween[this.tween] || Tween['linear'];
            this.equation = function(from, to) {
                return f((this.current/this.frames)*this.duration, from, to - from, this.duration);
            };
            this.current = this.tweening = 1;
        },

        //  开始动画
        start: function() {
            this.init();
            customEvent(this.onStart, this);
            var _self = this, d = this.duration / this.frames;
            this.timer = setInterval(function() {_Tweening.call(_self);}, d);
        },

        // 停止动画
        stop: function() {
            if (this.timer) {
                clearInterval(this.timer);
            }
            this.tweening = false;
        }
    };
})( XN.effect );
/*
 * patch end
 */

XN.ui.getHiddenDiv = function()
{
    if ( ! this._hiddenDiv )
    {
        this._hiddenDiv = $element( 'div' ).hide();
        document.body.appendChild( this._hiddenDiv );
    }

    return this._hiddenDiv;
}

XN.ui.friendSearchBar = function( p )
{
    var input = $(p.input);
    var submit = $(p.submit || null);
    var form = $(p.form);
    var tip = p.tip || '找人...';
    var action = p.action || function(p)
    {
        window.location.href = 'http://' + XN.ENV.domain + '/profile.do?id=' + p.id;
    };
    var gotoUserPage = false;
    
    (new XN.FORM.inputHelper(input)).setDefaultValue(tip).onEnter(function(el)
    {
        if(gotoUserPage)return;
        if(!XN.STRING.isBlank(el.value))
        {
            form.submit();
        }
    });

    var maxLength = 24;

    var friendSelector = new XN.UI.friendSelector({
        id:input,
        noResult:function(){
            return '搜索"' + this.input.value + '"';
        },
        noInput : '请输入好友姓名(支持拼音输入)',
        limit : maxLength
    });

    /* 
    friendSelector.lastMenuItem = function()
    {
        if ( this.result.length == maxLength )
        {
            return '<li><p><a href="http://friend.' + XN.env.domain + '/myfriendlistx.do?qu=' + this.input.value + '">点击查看更多..</a></p></li>';
        }
        else
        {
            return '';
        }
    }
    */

    friendSelector.setMenuWidth( p.width || input.offsetWidth );


    friendSelector.onSelectOne = function(p)
    {
        gotoUserPage = true;
        action(p);
    };
    if(submit)submit.onclick = function()
    {
        if(gotoUserPage)return;
        var v = input.value;
        if(v != tip && !XN.STRING.isBlank(v))
        {
            form.submit();
            return false;
        }
    }
};

function patchForUiMenu()
{
    //if ( /home\.kaixin\.com|friend\.kaixin\.com/.test( window.location.href ) )
    //{
    //    XN.ui.autoCompleteMenu.prototype._wrapper = function()
    //    {
    //        return [
    //            '<div class="fillet-guide-tips friends_list_float">',
    //                '<div class="j1"></div>',
    //                '<div class="j2"></div>',
    //                '<div class="fillet-content">',
    //                    '<ul></ul>',
    //                '</div>',
    //                '<div class="j3"></div>',
    //                '<div class="j4"></div>',
    //            '</div>'
    //        ].join( '' );
    //    };
    //}
    //else
    //{
        XN.ui.autoCompleteMenu.prototype._wrapper = function()
        {
            return [
            '<div class="m-autosug">',
                '<span class="x1">',
                    '<span class="x1a"></span>',
                '</span>',
                '<span class="x2">',
                    '<span class="x2a"></span>',
                '</span>',
                '<div class="m-autosug-minwidth">',
                    '<div class="m-autosug-content">',
                        '<ul></ul>',
                    '</div>',
                '</div>',
            '</div>'
            ].join( '' );
        };
    //} 
}
