var mountOrder = 1;
import { CurrentOwner } from "./createElement";
function alwaysNull() {
    return null;
}
function Updater(instance, vnode, props, context) {
    //防止用户在构造器生成JSX
    vnode._instance = instance;
    instance.updater = this;
    this._mountOrder = mountOrder++;
    this._instance = instance;
    this._pendingCallbacks = [];
    this._pendingStates = [];
  
    this._lifeStage = 0; //判断生命周期
    this._hostNode = null;
    this.nextVnode = vnode;//用于DevTools工具中，通过实例找到生成它的那个虚拟DOM
    this.props =  props;
    this.context = context;
    if(instance.__isStateless){
        this.mergeStates = alwaysNull;
    }
}

Updater.prototype = {
    isMounted: function(){
        return !!this._hostNode;
    },
    mergeStates: function(){
        let pendings = this._pendingStates,
            n = pendings.length;
        if (n === 0) {
            return this.state;
        }
        let state = Object.assign({}, this.state);//每次都返回新的state
        for (let i = 0; i < n; i++) {
            let pending = pendings[i];
            if (pending && pending.call) {
                pending = pending.call(this, state, this.props, this.context);
            }
            Object.assign(state, pending);
        }
        pendings.length = 0;
        return state;
    },
  
    
    renderComponent: function( cb, rendered, parentInstance) {
        let vnode = this.nextVnode;
        let instance = this._instance;
        let parentContext = this.parentContext;
        //调整全局的 CurrentOwner.cur
        if (!rendered) {
            try {
                var lastOwn = CurrentOwner.cur;
                CurrentOwner.cur = instance;
                rendered = instance.render();
            } finally {
                CurrentOwner.cur = lastOwn;
            }
        }
    
        //组件只能返回组件或null
        if (rendered === null || rendered === false) {
            rendered = { type: "#comment", text: "empty", vtype: 0 };
        } else if (!rendered || !rendered.vtype) {
        //true, undefined, array, {}
            throw new Error(
                `@${vnode.type
                    .name}#render:You may have returned undefined, an array or some other invalid object`
            );
        }
        this.lastRendered = this.rendered;
        this.rendered = rendered;
      
        let childContext = rendered.vtype
            ? getChildContext(instance, parentContext)
            : parentContext;
        let dom = cb(rendered, this.vparent, childContext);
        if(parentInstance){
            this._parentInstance = parentInstance;
        }
       
        updateInstanceChain(this, dom);
    
        return dom;
    }
};

function getChildContext(instance, parentContext) {
    if (instance.getChildContext) {
        let context = instance.getChildContext();
        if (context) {
            parentContext = Object.assign({}, parentContext, context);
        }
    }
    return parentContext;
}


function updateInstanceChain(updater, dom) {
    updater._hostNode = dom;
    var parent = updater._parentInstance;
    if (parent) {
        updateInstanceChain(parent.updater, dom);
    }
}


export function instantiateComponent(type, vnode, props, context) {
    var instance;
    if (vnode.vtype === 2) {
        instance = new type(props, context);
        //props, context是不可变的
        instance.props = props;
        instance.context = context;
        new Updater(instance, vnode, props, context);
    } else {
        instance = {
            refs: {},
            render: function() {
                return type(this.props, this.context);
            },
            __isStateless: 1,
            state: null,
            props: props,
            context: context,
            //  __pendingCallbacks: [],
            //  __current: noop,
            //  __mergeStates: alwaysNull
        };
        var updater = new Updater(instance, vnode, props, context);
        let lastOwn = CurrentOwner.cur;
        CurrentOwner.cur = instance;
        try {
            var mixin = type(props, context);
        } finally {
            CurrentOwner.cur = lastOwn;
        }
        if (mixin && mixin.render) {
            //支持module pattern component
            delete instance.__isStateless;
            Object.assign(instance, mixin);
        } else {
            updater.rendered = mixin;
        }
    }

    return instance;
}
