/**
 * @ignore
 * render process for control and render
 * @author yiminghe@gmail.com
 */
KISSY.add('component/control/process', function (S, Base, Promise) {
    var Defer = Promise.Defer,
        __getHook = Base.prototype.__getHook,
        noop = S.noop;

    /**
     * @class KISSY.Component.Process
     * @extends KISSY.Base
     */
    var ComponentProcess = Base.extend({
        bindInternal: noop,

        syncInternal: noop,

        initializer: function () {
            this._renderedDefer = new Defer();
        },

        createDom: noop,

        renderUI: noop,

        bindUI: noop,

        syncUI: noop,

        onRendered: function (fn) {
            return this._renderedDefer.promise.then(fn);
        },

        /**
         * create dom structure of this component
         * (control will delegate to render).
         * @chainable
         */
        create: function () {
            var self = this;
            if (!self.get("created")) {
                /**
                 * @event beforeCreateDom
                 * fired before root node is created
                 * @param {KISSY.Event.CustomEvent.Object} e
                 */
                self.fire('beforeCreateDom');
                self.createInternal();
                self.__callPluginsMethod('pluginCreateDom');
                /**
                 * @event afterCreateDom
                 * fired when root node is created
                 * @param {KISSY.Event.CustomEvent.Object} e
                 */
                self.fire('afterCreateDom');

                self.setInternal("created", true);
            }
            return self;
        },

        createInternal: function () {
            this.createDom();
        },

        /**
         * Put dom structure of this component to document, bind event and sync attribute.
         * @chainable
         */
        render: function () {
            var self = this;
            // 是否已经渲染过
            if (!self.get("rendered")) {
                self.create();

                /**
                 * @event beforeRenderUI
                 * fired when root node is ready
                 * @param {KISSY.Event.CustomEvent.Object} e
                 */

                self.fire('beforeRenderUI');
                self.renderUI();
                self.__callPluginsMethod('pluginRenderUI');

                /**
                 * @event afterRenderUI
                 * fired after root node is rendered into dom
                 * @param {KISSY.Event.CustomEvent.Object} e
                 */
                self.fire('afterRenderUI');

                /**
                 * @event beforeBindUI
                 * fired before component 's internal event is bind.
                 * @param {KISSY.Event.CustomEvent.Object} e
                 */

                self.fire('beforeBindUI');
                ComponentProcess.superclass.bindInternal.call(self);
                self.bindUI();
                self.__callPluginsMethod('pluginBindUI');
                /**
                 * @event afterBindUI
                 * fired when component 's internal event is bind.
                 * @param {KISSY.Event.CustomEvent.Object} e
                 */
                self.fire('afterBindUI');

                ComponentProcess.superclass.syncInternal.call(self);
                syncUIs(self);

                self.setInternal("rendered", true);
            }
            return self;
        },

        /**
         * sync attribute value
         */
        sync: function () {
            syncUIs(this);
        },

        plug: function (plugin) {
            var self = this,
                p,
                plugins = self.get('plugins');
            self.callSuper(plugin);
            p = plugins[plugins.length - 1];
            if (self.get('rendered')) {
                // plugin does not support decorate
                p['pluginCreateDom'] && p['pluginCreateDom'](self);
                p.pluginRenderUI && p.pluginRenderUI(self);
                p.pluginBindUI && p.pluginBindUI(self);
                p.pluginSyncUI && p.pluginSyncUI(self);
            } else if (self.get('created')) {
                p['pluginCreateDom'] && p['pluginCreateDom'](self);
            }
            return self;
        }

    }, {
        __hooks__: {
            createDom: __getHook('__createDom'),
            renderUI: __getHook('__renderUI'),
            bindUI: __getHook('__bindUI'),
            syncUI: __getHook('__syncUI')
        },

        name: 'ComponentProcess',

        ATTRS: {
            /**
             * Whether this component is rendered.
             * @type {Boolean}
             * @property rendered
             * @readonly
             */
            /**
             * @ignore
             */
            rendered: {
                value: false,
                setter: function (v) {
                    if (v) {
                        this._renderedDefer.resolve(this);
                    }
                }
            },
            /**
             * Whether this component 's dom structure is created.
             * @type {Boolean}
             * @property created
             * @readonly
             */
            /**
             * @ignore
             */
            created: {
                value: false
            }
        }
    });

    function syncUIs(self) {
        /**
         * @event beforeSyncUI
         * fired before component 's internal state is synchronized.
         * @param {KISSY.Event.CustomEvent.Object} e
         */
        self.fire('beforeSyncUI');
        self.syncUI();
        self.__callPluginsMethod('pluginSyncUI');
        /**
         * @event afterSyncUI
         * fired after component 's internal state is synchronized.
         * @param {KISSY.Event.CustomEvent.Object} e
         */
        self.fire('afterSyncUI');
    }

    return ComponentProcess;
}, {
    requires: ['base', 'promise']
});
/**
 * @ignore
 *
 * 2013.06.18 note:
 *  - ComponentProcess 流程化渲染过程定义
 *
 * Refer:
 *  - http://martinfowler.com/eaaDev/uiArchs.html
 *
 * render 和 create 区别
 *  - render 包括 create ,以及把生成的节点放在 document 中
 *  - create 仅仅包括创建节点
 **/