
// dependencies for a class
const dep = new Map();

// sigelton classes
const singelton = new Map();

// transient classes
const transient = new Map();


/**
 * keeps track of our classes and dependencies
 *
 */
export class ContainerClasses {



    /**
     * returns a instance of a class, pass in the class type/prototype to get it
     *
     */
    public static get(_class: any): any {

        const instance = this.getInstance(_class);

        return instance;

    }



    /**
     * returns dependencies only (I dont use this atm)
     *
     */
 /*     public static getDepOnly<T>(_class: T): T {

        return dep.get(_class);

    }
 */


    /**
     * get instance of class and create if it is not created before
     *
     */
    private static getInstance<T>(_class: T): T {

        if (transient.has(_class)) {
            return this.create(_class);
        } else {

            if (!singelton.get(_class)) {
                singelton.set(_class, this.create(_class));
            }

            return singelton.get(_class);

        }
    }


    /**
     * ...todo
     *
     */
    private static create(_class: any): any {

        let deps = dep.get(_class) || [];
        deps = deps.map((classX: any) => {
            try {
                return this.get(classX);
            } catch (e) {
                return classX;
            }
        });
        // @ts-ignore: Unreachable code error

        return new _class(...deps);
    }



    /**
     * set dependencies for a class
     *
     */
    public static setDep(_class: any, deps: any) {
        dep.set(_class, deps);
    }



    /**
     * registers a class as transient
     *
     */
    public static regTransient(_class: any) {
        if (!transient.has(_class)) {
            transient.set(_class, null);
        }
    }
}
