# Source: recorder.maia

    ///
    /// @license
    /// Copyright 2020 Roberto Luiz Souza Monteiro,
    ///                Renata Souza Barreto,
    ///                Hernane Borges de Barros Pereira.
    ///
    /// Licensed under the Apache License, Version 2.0 (the 'License');
    /// you may not use this file except in compliance with the License.
    /// You may obtain a copy of the License at;
    ///
    ///   http://www.apache.org/licenses/LICENSE-2.0;
    ///
    /// Unless required by applicable law or agreed to in writing, software;
    /// distributed under the License is distributed on an 'AS IS' BASIS,
    /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, eitherMath.express or implied.
    /// See the License for the specific language governing permissions and;
    /// limitations under the License.
    ///
    /// This code is based on https://github.com/webrtcHacks/jitsiLocalRecorder.git
    ///

     ///
     /// MaiaScript screen recorder library.
     /// @class MaiaRecorder
     /// @param {object}   options - Object containing options for configuring the recorder.
     ///                             It can be: startButton, pauseButton, stopButton,
     ///                                        playButton, saveButton, videoPlayer,
     ///                                        fileNamePrefix, mimeType.
     /// @return {object}  Screen recorder object.
     ///
    constructor MaiaRecorder(options) {
        opts = {
            "startButton": "",
            "pauseButton": "",
            "stopButton": "",
            "playButton": "",
            "saveButton": "",
            "videoPlayer": "",
            "fileNamePrefix": "Screen-recording",
            "mimeType": "video/webm"
        }

        if (core.type(options) != "undefined") {
            foreach (options; key; value) {
                opts[key] = value
            }
        }

        local startButton
        local pauseButton
        local stopButton
        local playButton
        local saveButton
        local videoPlayer
        local fileNamePrefix
        local mimeType

        local recorder
        local recordingData = []
        local recorderStream
        local isPlaying = false

        startButton = document.getElementById(opts["startButton"])
        pauseButton = document.getElementById(opts["pauseButton"])
        stopButton = document.getElementById(opts["stopButton"])
        playButton = document.getElementById(opts["playButton"])
        saveButton = document.getElementById(opts["saveButton"])
        videoPlayer = document.getElementById(opts["videoPlayer"])
        fileNamePrefix = opts["fileNamePrefix"]
        mimeType = opts["mimeType"]

        ///
        /// Mixes two audio tracks and the first video track found.
        /// @method mixTracks
        /// @memberof MaiaRecorder
        /// @param {object}   trackA - Track A.
        /// @param {object}   trackB - Track B.
        /// @return {object}  Video stream containing mixed audio and video tracks.
        ///
        function mixTracks(trackA, trackB) {
            ctx := AudioContext()
            dest = ctx.createMediaStreamDestination()

            audioTracksA = trackA.getAudioTracks()
            if (audioTracksA.length > 0) {
                mediaStreamSourceA = ctx.createMediaStreamSource(trackA)
                mediaStreamSourceA.connect(dest)
            }
            audioTracksB = trackB.getAudioTracks()
            if (audioTracksB.length > 0) {
                mediaStreamSourceB = ctx.createMediaStreamSource(trackB)
                mediaStreamSourceB.connect(dest)
            }

            mixedTracks = dest.stream.getTracks()
            mixedTracks = mixedTracks.concat(trackA.getVideoTracks())
            mixedTracks = mixedTracks.concat(trackB.getVideoTracks())

            mediaStream := MediaStream(mixedTracks)

            return(mediaStream)
        }

        ///
        /// Return the file name for the captured video.
        /// @method getFilename
        /// @memberof MaiaRecorder
        /// @return {object}  File name for the captured video.
        ///
        function getFilename() {
            now := Date()
            timestamp = now.toISOString()
            fileName = fileNamePrefix + "-" + timestamp
            return(fileName)
        }

        ///
        /// Start recording screen.
        /// @method startRecording
        /// @memberof MaiaRecorder
        /// @return {object}  Screen recording started.
        ///
        async startRecording () {
            local userMediaStream
            local displayMediaStream
            recordingData = []

            audioOptions = {
                "video": false,
                "audio": true
            }
            videoOptions = {
                "video": {"displaySurface": "browser"},
                "audio": true
            }

            try {
                userMediaStream ?= navigator.mediaDevices.getUserMedia(audioOptions)
                displayMediaStream ?= navigator.mediaDevices.getDisplayMedia(videoOptions)
            } catch (e) {
                system.showMessageDialog("Error: screen recording is not supported by this browser.")
                return()
            }

            if (userMediaStream) {
                recorderStream = mixTracks(userMediaStream, displayMediaStream)
            } else {
                recorderStream = displayMediaStream
            }
            recorder := MediaRecorder(recorderStream, {"mimeType": mimeType})

            function onDataAvailable (e) {
                if (e.data && e.data.size > 0) {
                    recordingData.push(e.data)
                }
                console.log("available")
            }
            function onStop () {
                function stopTrackRecording(track) {
                    track.stop()
                }
                recorderStreamTracks = recorderStream.getTracks()
                recorderStreamTracks.forEach(stopTrackRecording)

                userMediaStreamTracks = userMediaStream.getTracks()
                userMediaStreamTracks.forEach(stopTrackRecording)

                displayMediaStreamTracks = displayMediaStream.getTracks()
                displayMediaStreamTracks.forEach(stopTrackRecording)
            }
            recorder.ondataavailable = onDataAvailable
            recorder.onstop = onStop

            function onInactive () {
                stopRecording()
                console.log(recorder.state)
            }
            recorderStream.addEventListener("inactive", onInactive)

            recorder.start()

            startButton.innerText = "Recording"
            startButton.disabled = true
            pauseButton.disabled = false
            stopButton.disabled = false
            playButton.disabled = true
            saveButton.disabled = true

            console.log(recorder.state)
        }
        startButton.addEventListener("click", startRecording)

        ///
        /// Stop recording screen.
        /// @method stopRecording
        /// @memberof MaiaRecorder
        /// @return {object}  Screen recording stopped.
        ///
        function stopRecording() {
            if ((recorder.state == "recording") || (recorder.state == "paused")) {
                recorder.stop()
            }

            startButton.disabled = false
            pauseButton.disabled = true
            stopButton.disabled = true
            playButton.disabled = false
            saveButton.disabled = false

            startButton.innerText = "Record"
            pauseButton.innerText = "Pause"

            console.log(recorder.state)
        }
        stopButton.addEventListener("click", stopRecording)

        ///
        /// Pause recording screen.
        /// @method pauseRecording
        /// @memberof MaiaRecorder
        /// @return {object}  Screen recording paused.
        ///
        function pauseRecording() {
            if (recorder.state == "paused") {
                recorder.resume()
                pauseButton.innerText = "Pause"
            } elseif (recorder.state == "recording") {
                recorder.pause()
                pauseButton.innerText = "Resume"
            }

            console.log(recorder.state)
        }
        pauseButton.addEventListener("click", pauseRecording)

        ///
        /// Plays the recording.
        /// @method playRecording
        /// @memberof MaiaRecorder
        /// @return {object}  The recorded video is played.
        ///
        function playRecording() {
            videoPlayer.hidden = !videoPlayer.hidden
            if ((!isPlaying) && (!videoPlayer.hidden)) {
                videoSource := Blob(recordingData, {"type": mimeType})
                videoPlayer.src = window.URL.createObjectURL(videoSource)
                videoPlayer.play()
                playButton.innerText = "Hide"
            } else {
                playButton.innerText = "Play"
            }
        }
        playButton.addEventListener("click", playRecording)

        function setIsPlaying() {
            isPlaying = true
        }
        function unsetIsPlaying() {
            isPlaying = false
        }
        videoPlayer.addEventListener("play", setIsPlaying)
        videoPlayer.addEventListener("pause", unsetIsPlaying)
        videoPlayer.addEventListener("playing", setIsPlaying)
        videoPlayer.addEventListener("ended", unsetIsPlaying)

        ///
        /// Saves the recording.
        /// @method saveRecording
        /// @memberof MaiaRecorder
        /// @return {object}  The recorded video is saved.
        ///
        function saveRecording() {
            blob := Blob(recordingData, {"type": mimeType})
            url = window.URL.createObjectURL(blob)
            a = document.createElement("a")
            a.style.display = "none"
            a.href = url
            a.download = getFilename() + ".webm"
            document.body.appendChild(a)
            a.click()
            function removeDownloadLink() {
                document.body.removeChild(a)
                window.URL.revokeObjectURL(url)
            }
            setTimeout(removeDownloadLink, 500)
        }
        saveButton.addEventListener("click", saveRecording)
    }