import { point } from "./point.js";

/**
 * This is controler. Controler is responsible for managing events after 
 * mouse move. App can create controler for each view, and ads more
 * listeners, which could be removed with one instruction. Listeners get 
 * point with mouse move difference as parameter.
 */
export class controler {
    #last;
    #event;
    #listeners;

    /**
     * This create new controler.
     * @return {controler} - New controler
     */
    constructor() {
        this.#last = null;
        this.#event = null;
        this.#listeners = [];
    }

    /**
     * This is inside function, which calculate mouse move, and save it new
     * position, to calculate it after next move. It also run all listeners.
     * 
     * @param {MouseEvent} event - Event from mousemove 
     */
    #moved(event) {
        const current = new point(event.screenX, event.screenY);

        if (this.#last === null) {
            this.#last = current;
            return;
        }

        const difference = this.#last.compare(current);
        this.#last = current;
        
        this.#run(difference);
    }

    /**
     * This run all listeners, and give them as parameter difference between 
     * last and current mouse position.
     * 
     * @param {point} target - Difference between mouse positions
     */
    #run(target) {
        this.#listeners.forEach(item => item(target));
    }

    /**
     * This enable event listening on window.
     */
    enable() {
        if (this.#event) {
            return;
        }

        this.#event = (event) => { this.#moved(event); };
        window.addEventListener("mousemove", this.#event);
    }

    /**
     * This disable even listening on window. It is recomended to use, when
     * view is changing. 
     */
    clean() {
        if (this.#event === null) {
            return;
        }

        window.removeEventListener("mousemove", this.#event);
        this.#event = null;
    }

    /**
     * This add new listener. Listener get point with difference between
     * old and new mouse position as argument. 
     * 
     * @param {function} target - New listener
     * @returns {bool} - True when added, false when already exists
     */
    add_listener(target) {
        if (this.#listeners.includes(target)) {
            return false;
        }

        this.#listeners.push(target);
        return true;
    }

    /**
     * This remove listener which is given as argument.
     * 
     * @param {function} target - Function to remove
     * @returns {?function} - Null when function is not removed, or function
     */
    remove_listener(target) {
        const where = this.#listeners.indexOf(target);

        if (where === -1) {
            return null;
        }

        return this.#listeners.pop(where);
    }
}