/**
 * @file 弹出层组件, 基础版本。
 * @import core/widget.js
 * @module GMU
 */
(function( gmu, $, undefined ) {

    /**
     * 弹出层组件，具有点击按钮在周围弹出层的交互效果。至于弹出层内容，可以通过`content`直接设置内容，
     * 也可以通过`container`设置容器节点。按钮和弹出层之间没有位置依赖。
     *
     * 基础版本只有简单的点击显示，再点击隐藏功能。像用更多的功能请参看[插件介绍](#GMU:Popover:plugins)部分.
     *
     * @class Popover
     * @constructor Html部分
     * ```html
     * <a id="btn">按钮<a/>
     * ```
     *
     * javascript部分
     * ```javascript
     * $('#btn').popover({
     *     content: 'Hello world'
     * });
     * ```
     * @param {dom | zepto | selector} [el] 按钮节点
     * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Popover:options)
     * @grammar $( el ).popover( options ) => zepto
     * @grammar new gmu.Popover( el, options ) => instance
     */
    gmu.define( 'Popover', {

        // 默认配置项。
        options: {

            /**
             * @property {Zepto | Selector} [container] 指定容器，如果不传入，组件将在el的后面自动创建一个。
             * @namespace options
             */
            container: null,

            /**
             * @property {String | Zepto | Selector } [content] 弹出框的内容。
             * @namespace options
             */
            content: null,

            /**
             * @property {String} [event="click"] 交互事件名, 可能你会设置成tap。
             * @namespace options
             */
            event: 'click'
        },

        template: {
            frame: '<div>'
        },

        /**
         * @event ready
         * @param {Event} e gmu.Event对象
         * @description 当组件初始化完后触发。
         */

         // 负责dom的创建。
        _create: function() {
            var me = this,
                opts = me._options,
                $el = opts.target && $( opts.target ) || me.getEl(),
                $root = opts.container && $( opts.container );

            // 没传 或者 就算传入了选择器，但是没有找到节点，还是得创建一个。
            $root && $root.length || ($root = $( me.tpl2html( 'frame' ) )
                    .addClass( 'ui-mark-temp' ));
            me.$root = $root;

            // 如果传入了content, 则作为内容插入到container中
            opts.content && me.setContent( opts.content );
            me.trigger( 'done.dom', $root.addClass( 'ui-' + me.widgetName ),
                    opts );

            // 如果节点是动态创建的，则不在文档树中，就把节点插入到$el后面。
            $root.parent().length || $el.after( $root );

            me.target( $el );
        },

        // 删除标记为组件临时的dom
        _checkTemp: function( $el ) {
            $el.is( '.ui-mark-temp' ) && $el.off( this.eventNs ) &&
                    $el.remove();
        },

        /**
         * @event beforeshow
         * @param {Event} e gmu.Event对象
         * @description 但弹出层打算显示时触发，可以通过`e.preventDefault()`来阻止。
         */


        /**
         * @event show
         * @param {Event} e gmu.Event对象
         * @description 当弹出层显示后触发。
         */


        /**
         * 显示弹出层。
         * @method show
         * @chainable
         * @return {self} 返回本身。
         */
        show: function() {
            var me = this,
                evt = gmu.Event( 'beforeshow' );

            me.trigger( evt );

            // 如果外部阻止了关闭，则什么也不做。
            if ( evt.isDefaultPrevented() ) {
                return;
            }

            me.trigger( 'placement', me.$root.addClass( 'ui-in' ), me.$target );
            me._visible = true;
            return me.trigger( 'show' );
        },

        /**
         * @event beforehide
         * @param {Event} e gmu.Event对象
         * @description 但弹出层打算隐藏时触发，可以通过`e.preventDefault()`来阻止。
         */


        /**
         * @event hide
         * @param {Event} e gmu.Event对象
         * @description 当弹出层隐藏后触发。
         */

        /**
         * 隐藏弹出层。
         * @method hide
         * @chainable
         * @return {self} 返回本身。
         */
        hide: function() {
            var me = this,
                evt = new gmu.Event( 'beforehide' );

            me.trigger( evt );

            // 如果外部阻止了关闭，则什么也不做。
            if ( evt.isDefaultPrevented() ) {
                return;
            }

            me.$root.removeClass( 'ui-in' );
            me._visible = false;
            return me.trigger( 'hide' );
        },

        /**
         * 切换弹出层的显示和隐藏。
         * @method toggle
         * @chainable
         * @return {self} 返回本身。
         */
        toggle: function() {
            var me = this;
            return me[ me._visible ? 'hide' : 'show' ].apply( me, arguments );
        },

        /**
         * 设置或者获取当前`按钮`(被点击的对象)。
         * @method target
         * @param {dom | selector | zepto} [el] target新值。
         * @chainable
         * @return {self} 当传入了el时，此方法为setter, 返回值为self.
         * @return {dom} 当没有传入el时，为getter, 返回当前target值。
         */
        target: function( el ) {

            // getter
            if ( el === undefined ) {
                return this.$target;
            }

            // setter
            var me = this,
                $el = $( el ),
                orig = me.$target,
                click = me._options.event + me.eventNs;

            orig && orig.off( click );

            // 绑定事件
            me.$target = $el.on( click, function( e ) {
                e.preventDefault();
                me.toggle();
            } );

            return me;
        },

        /**
         * 设置当前容器内容。
         * @method setContent
         * @param {dom | selector | zepto} [value] 容器内容
         * @chainable
         * @return {self} 组件本身。
         */
        setContent: function( val ) {
            var container = this.$root;
            container.empty().append( val );
            return this;
        },

        /**
         * 销毁组件，包括事件销毁和删除自动创建的dom.
         * @method destroy
         * @chainable
         * @return {self} 组件本身。
         */
        destroy: function() {
            var me = this;

            me.$target.off( me.eventNs );
            me._checkTemp( me.$root );
            return me.$super( 'destroy' );
        }
    } );
})( gmu, gmu.$ );