class Script {

    constructor() {

        //Nodejs functions
        this.fs = require('fs');
        this.path = require('path');

        //path elements
        this.basePath = this.path.join(__dirname, "../../");
        this.assetsFolder = "./assets";
        this.imgFolder = "img";
        this.soundsFolder = "sounds";
        this.savesFolder = "saves";

        console.log("__dirname", __dirname);

        console.log(this.path.join(this.basePath, this.assetsFolder, this.imgFolder));

        //files lists
        this.imgFileList = this.getFileListFromPath(this.path.join(this.basePath, this.assetsFolder, this.imgFolder));
        this.soundFileList = this.getFileListFromPath(this.path.join(this.basePath, this.assetsFolder, this.soundsFolder));

        console.log(this.imgFileList, this.soundsList);

        /*audio files management*/
        //all sounds buffers (convertion from Nodejs Buffer to ArrayBuffer)
        this.soundsBuffers = [];

        this.soundFileList.forEach((file) => {
            const nodeBuffer = this.fs.readFileSync(file);
            //console.log("nodeBuffer", nodeBuffer);
            const arrayBuffer = this.toArrayBuffer(nodeBuffer);
            this.soundsBuffers.push(arrayBuffer);
        });

        //Mobilizing.js sounds list -> see Setup
        this.soundList = [];

        /*icons management*/
        //base png files
        this.imgList = [];

        //AVIcons list
        this.UIAVIcons = [];
        this.CompositionAVIcons = [];

        //HTML container element for img
        this.HTMLContainer = document.body;

        //HTML container for composition
        this.compositionContainer = document.getElementById("composition");

        //HTML playhead
        this.playhead = document.getElementById("playhead");
        this.playhead.transform = new Transform(this.playhead);

        //
        this.compositionIsPlaying = false;

        //Listen mode or Edit mode
        this.editMode = false;

        //event handlers
        this.compositionContainer.addEventListener("mousemove", this.onMouseMoveHandler.bind(this));
        this.compositionContainer.addEventListener("mouseup", this.onMouseUpHandler.bind(this));
        this.compositionContainer.addEventListener("mousedown", this.onMouseDownHandler.bind(this));
    }

    setup() {

        //audio setup
        this.audioRenderer = new Mobilizing.audio.Renderer();
        this.context.addComponent(this.audioRenderer);

        const uiTopNb = [1, 6, 7, 3, 9, 14, 15, 11];
        const uiBottomNb = [8, 16, 2, 10, 4, 12, 5, 13];

        //AVIcon generation for UI
        for (let i = 0; i < this.imgFileList.length; i++) {

            const imgPath = this.imgFileList[i];
            const soundBuffer = this.soundsBuffers[i];

            let currentTopIcon;
            let currentBottomIcon;

            if (uiTopNb.indexOf(i + 1) >= 0) {
                this.HTMLContainer = document.getElementById("uitop");
                currentTopIcon = uiTopNb[uiTopNb.indexOf(i + 1)];
                console.log("i", i, "currentTopIcon", currentTopIcon);
            }
            if (uiBottomNb.indexOf(i + 1) >= 0) {
                this.HTMLContainer = document.getElementById("uibottom");
                currentBottomIcon = uiBottomNb[uiBottomNb.indexOf(i + 1)];
                console.log("i", i, "currentBottomIcon", currentBottomIcon);
            }

            const icon = new AVIcon({
                imgPath: imgPath,
                audioRenderer: this.audioRenderer,
                soundBuffer: soundBuffer,
                HTMLContainer: this.HTMLContainer,
                scriptContext: this,
                mobilizingContext: this.context,
            });

            //position des icones fixes dans l'UI
            icon.img.style.position = "absolute";

            switch (currentTopIcon) {
                case 1:
                    icon.transform.position.x = 8;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 6:
                    icon.transform.position.x = 306;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 7:
                    icon.transform.position.x = 368;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 3:
                    icon.transform.position.x = 474;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 9:
                    icon.transform.position.x = 8;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
                case 14:
                    icon.transform.position.x = 306;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
                case 15:
                    icon.transform.position.x = 368;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
                case 11:
                    icon.transform.position.x = 474;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
            }

            switch (currentBottomIcon) {
                case 8:
                    icon.transform.position.x = 8;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 2:
                    icon.transform.position.x = 272;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 4:
                    icon.transform.position.x = 355;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 5:
                    icon.transform.position.x = 432;
                    icon.transform.position.y = 8;
                    icon.transform.apply();
                    break;
                case 16:
                    icon.transform.position.x = 8;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
                case 10:
                    icon.transform.position.x = 272;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
                case 12:
                    icon.transform.position.x = 355;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
                case 13:
                    icon.transform.position.x = 432;
                    icon.transform.position.y = 64;
                    icon.transform.apply();
                    break;
            }

            //console.log(icon);
            this.UIAVIcons.push(icon);
        }

        //compute the median timeSpace unit to use
        setTimeout(() => {
            this.getMedianTimeDurationRatio();
            //console.log("this.timePixelRatio", this.timePixelRatio);
            //playlist
            this.playlist = new Playlist(this.audioRenderer, this.HTMLContainer.offsetWidth / this.timePixelRatio);
            window.playlist = this.playlist;
        }, 1000);

        //Time component for audio playback
        this.time = new Mobilizing.Time();
        this.time.scale = 1;
        this.time.setup();
        this.time.on();
        this.context.addComponent(this.time);

        //the currentTime
        this.currentTime = 0;

        //set the radio button callback
        let ecouter = document.getElementById("ecouter");
        ecouter.addEventListener("change", () => {
            this.editMode = false;
        });

        let modifier = document.getElementById("modifier");
        modifier.addEventListener("change", () => {
            this.editMode = true;
        });

        //set the saveBt callback
        let save = document.getElementById("saveBt");
        save.addEventListener("click", () => {
            this.playlist.record();
        });
    }

    /**
     * getMedianTimeDurationRatio from all UIAVIcon
     */
    getMedianTimeDurationRatio() {

        this.timePixelRatio = 0;
        for (let i = 0; i < this.UIAVIcons.length; i++) {
            const icon = this.UIAVIcons[i];
            this.timePixelRatio += icon.timePixelRatio;
        }
        this.timePixelRatio /= this.UIAVIcons.length;
        console.log("median ratio is : ", this.timePixelRatio);
    }

    /**
     * add an AVIcon to the scene container
     * @param {*} params 
     */
    addIcon(params) {

        const icon = new AVIcon({
            imgPath: params.imgPath,
            audioRenderer: params.audioRenderer,
            soundBuffer: params.soundBuffer,
            HTMLContainer: this.compositionContainer,
            scriptContext: this,
            mobilizingContext: this.context,
        });
        icon.isUIIcon = false;
        icon.isCompositionIcon = true;
        icon.img.style.position = "absolute";

        this.CompositionAVIcons.push(icon);
        //console.log(this.CompositionAVIcons);
        this.playlist.addIcon(icon);
        this.audioRenderer.registerNode(icon.sound);
    }

    /**
     * 
     * @param {*} event 
     */
    onMouseMoveHandler(event) {

        if (this.editMode) {
            this.CompositionAVIcons.forEach((icon) => {

                if (icon.draggable) {

                    const x = event.movementX;
                    const y = event.movementY;

                    icon.transform.position.x += x / window.devicePixelRatio;
                    icon.transform.position.y += y / window.devicePixelRatio;

                    //avoid to go out the composition visual frame
                    if (icon.transform.position.y < 0) {
                        icon.transform.position.y = 0;
                    }

                    if (icon.transform.position.y > this.compositionContainer.offsetHeight - icon.img.height) {
                        icon.transform.position.y = this.compositionContainer.offsetHeight - icon.img.height;
                    }
                    icon.transform.apply();

                    icon.sound.baseScheduleStartTime = icon.transform.position.x / this.timePixelRatio;
                    //console.log(icon);
                }
            });
        }
    }

    /**
     * 
     * @param {*} event 
     */
    onMouseDownHandler(event) {

        if (!this.editMode) {
            if (this.timePixelRatio) {
                this.currentTime = event.offsetX / this.timePixelRatio;
                console.log(event.offsetX, this.currentTime);
                this.compositionIsPlaying = true;

                //playlist
                this.playlist.setCurrentTime(this.currentTime);
            }
        }
    }

    /**
     * 
     * @param {*} event 
     */
    onMouseUpHandler(event) {

        this.CompositionAVIcons.forEach((icon) => {
            icon.draggable = false;
        });
        this.compositionIsPlaying = false;
        this.playlist.stop();
    }

    update() {

        if (this.timePixelRatio && this.compositionIsPlaying) {

            this.currentTime += this.time.getDeltaSeconds();

            //animate the playhead
            this.playhead.transform.position.x = this.currentTime * this.timePixelRatio;
            this.playhead.transform.apply();

            //update the playlist
            this.playlist.setCurrentTime(this.currentTime);
            this.playlist.update();
        }
    }


    //UTILS
    /**
     * Get an array of files from the given path
     * @param {Path} rootpath 
     */
    getFileListFromPath(rootpath) {

        const root = this.fs.readdirSync(rootpath);
        const fileList = [];

        root.forEach((file) => {
            //exclude .DS_Store files
            if (file !== ".DS_Store") {
                const filePath = this.path.join(rootpath, file);
                fileList.push(filePath);
            }
        });

        return fileList;
    }

    /**
     * convert a NodeJS buffer to an ArrayBuffer
     * @param {NodeJS Buffer} buf
     * @returns {ArrayBuffer} arrayBuffer
     */
    toArrayBuffer(buf) {
        const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
        return arrayBuffer;
    }

}

//Moiblizing runner
const context = new Mobilizing.Context();
const script = new Script();
context.addComponent(script);
const runner = new Mobilizing.Runner({ context });