/**  
 * @since Last modified: 2024/03/03 11:17:02
 * @class PubListen
 * @description Public methods, only the variables and methods about plan, can be extended.
 * @example
 * class Demo extends pipe(PubListen)(PubBase) {};
 */

import { T_obj } from '../../../types/ax';
import plan from '../utils/plan';
import startUpper from '../utils/startUpper';
const PubListen = (parent: any) => {
    return class extends (parent || class Empty { }) {
        /**
         * @name PubListen.plans
         * @description Plan collection.Add by the "on" method.
         * @type object
         */
        
        plans: T_obj = {};

        /**
        * @function PubListen.listen
        * @description Method's call back monitoring function.
        * @param {object} opt - params.
        * @param {string} opt.name - event name.
        * @param {array} opt.params - event params.
        * @param {Function} opt.cb - event cb.
        * @returns null
        */
        listen({ name, params = [], cb }: { name?: string, params?: any[], cb?: Function } = {}) {
            name && this.plans.hasOwnProperty(name) ? this.emit(name, ...params) : null;
            name && this.options[`on${startUpper(name)}`] && this.options[`on${startUpper(name)}`].call(this, ...params);
            cb && cb.call(this, ...params);
        }


        /**
        * @function PubListen.on
        * @description Add a plan.
        * @param {string} type - Name of plan.
        * @param {function} handler - The function to be executed in the plan.
        * @returns {*} Return the instance itself
        */
        
        on(type: string, handler: Function): any {
            plan.add(type, this, handler);
            return this;
        }
        /**
        * @function PubListen.emit
        * @description Implement a plan.
        * @param {string} type - Name of plan.
        * @param {array} params - Parameters of the implement plan.
        * @returns {*} Return the instance itself
        */
        
        emit(type: string, ...params: any): any {
            plan.do(type, this, ...params);
            return this;
        }
        /**
        * @function PubListen.off
        * @description Cancel a plan.
        * @param {string} type - Name of plan.
        * @param {function} handler - The function of plan.
        * @returns {*} Return the instance itself
        */
        
        off(type: string, handler: Function): any {
            plan.remove(type, this, handler,);
            return this;
        }
    }
}
export default PubListen;
