#include eventtarget.js

const UmiWebSocket = function(url, useWorker) {
    if(typeof useWorker !== 'boolean')
        useWorker = (() => {
            // Overrides
            if(mami.settings.get('neverUseWorker'))
                return false;
            if(mami.settings.get('forceUseWorker'))
                return true;

            // Detect chromosomes
            if((!!window.chrome || (!!window.Intl && !!Intl.v8BreakIterator)) && 'CSS' in window)
                return true;

            // Phones
            if((/iphone|ipod|android|ie|blackberry|fennec/i).test(navigator.userAgent.toLowerCase()))
                return true;

            return false;
        })();

    const eventTarget = new MamiEventTarget('ws');
    let send, close, sendInterval, clearIntervals;

    if(useWorker) {
        const worker = new Worker(MAMI_WS);
        worker.addEventListener('message', ev => {
            if(ev.data.act.startsWith('ws:'))
                eventTarget.dispatch(ev.data.act.substring(3), ev.data.detail);
        });
        worker.postMessage({act: 'ws:open', url: url});
        send = text => {
            worker.postMessage({act: 'ws:send', text: text});
        };
        close = () => {
            worker.postMessage({act: 'ws:close'});
        };
        sendInterval = (text, interval) => {
            worker.postMessage({act: 'ws:send_interval', text: text, interval: interval});
        };
        clearIntervals = () => {
            worker.postMessage({act: 'ws:clear_intervals'});
        };
    } else {
        const websocket = new WebSocket(url), intervals = [];
        websocket.addEventListener('open', ev => {
            eventTarget.dispatch('open');
        });
        websocket.addEventListener('close', ev => {
            eventTarget.dispatch('close', {
                code: ev.code,
                reason: ev.reason,
                wasClean: ev.wasClean,
            });
        });
        websocket.addEventListener('error', ev => {
            eventTarget.dispatch('error');
        });
        websocket.addEventListener('message', ev => {
            eventTarget.dispatch('message', {
                data: ev.data,
                origin: ev.origin,
                lastEventId: ev.lastEventId,
            });
        });
        send = text => {
            websocket.send(text);
        };
        close = () => {
            websocket.close();
        };
        sendInterval = (text, interval) => {
            const intervalId = setInterval(() => {
                if(websocket) {
                    websocket.send(text);
                    eventTarget.dispatch('call_interval', { id: intervalId });
                }
            }, interval);

            intervals.push(intervalId);
            eventTarget.dispatch('create_interval', { id: intervalId });
        };
        clearIntervals = () => {
            for(let i = 0; i < intervals.length; ++i)
                clearInterval(intervals[i]);
        };
    }

    return {
        isUsingWorker: useWorker,
        send: send,
        close: close,
        sendInterval: sendInterval,
        clearIntervals: clearIntervals,
        watch: eventTarget.watch,
        unwatch: eventTarget.unwatch,
    };
};
