const socketIO = require('socket.io'),
    path = require('path'),
    chalk = require("chalk"),
    os = require('os'),
    utils = require('./utils'),
    types = require('./event-types');

const socketServer = class socketServer {
    constructor({
        config,
        server,
        version,
        schedulePlayer,
        announcePlayer,
        djPlayer,
        bluetooth,
        schedulesDownloader,
        announcesDownloader,
        streamPlayer,
        prayer,
        masterMixer
    }) {
        this.clients = [];
        this.osName = os.platform();
        this.io = socketIO(server);
        this.socket = null;
        this.config = config;
        this.version = version;
        this.schedulePlayer = schedulePlayer;
        this.announcePlayer = announcePlayer;
        this.djPlayer = djPlayer;
        this.bluetooth = bluetooth;
        this.schedulesDownloader = schedulesDownloader;
        this.announcesDownloader = announcesDownloader;
        this.streamPlayer = streamPlayer;
        this.prayer = prayer;
        this.masterMixer = masterMixer;
        this.bluetoothScanOn = false;
        this.bluetoothScanTimer = null;
        this.bluetoothScanTimeout = 30000;
        this.configFilePath = path.join(process.cwd(), "config.ini");
    }

    // Emit sender method for all clients
    emitToAllClients(namespace, event, data) {
        let validClients = this.clients.filter(function (elem) {
            return !!elem;
        });

        if (validClients.length) {
            let eventName = (namespace) ? `${namespace}/${event}` : event

            validClients.forEach(function (sock) {
                sock.emit(eventName, data);
            });
        }
    }

    // Bluetooth scan toggle
    bluetoothScanToggle(bool) {
        console.log(chalk.bgBlue.white('Bluetooth Scan: ' + bool));
        if (bool) {
            if (this.bluetoothScanOn) return;
            this.bluetooth.scan(bool);
            this.bluetoothScanTimer = setInterval(() => this.bluetoothScanToggle(false), this.bluetoothScanTimeout)
        } else {
            this.bluetooth.scan(bool);
            this.socket.emit(`${types.bluetooth.namespace}/${types.bluetooth.events.scanOff}`);
            clearInterval(this.bluetoothScanTimer);
        }
    }

    // Application restart method
    refreshApplication() {
        process.exit(1);
    }

    async init() {

        // Schedule initiliaze
        if (this.schedulePlayer) {
            this.scheduleEventsInit();
        }

        // Announce initiliaze
        if (this.announcePlayer) {
            this.announceEventsInit();
        }

        // DjPlayer initiliaze
        if (this.djPlayer && this.config.DJ.DJEnabled === '1') {
            this.djPlayerEventsInit()
        }

        // Schedule Downloader initiliaze
        if (this.schedulesDownloader) {
            this.scheduleDownloaderEventsInit();
        }

        // Annnounce Downloader initiliaze
        if (this.announcesDownloader) {
            this.announceDownloaderEventsInit();
        }

        // Bluetooth initiliaze
        if (this.osName === 'linux' && this.bluetooth) {
            this.bluetoothEventsInit();
        }

        // Stream Player initiliaze
        if (this.streamPlayer) {
            this.streamPlayerEventsInit();
        }

        // Prayer events initialize
        if(this.prayer) {
            this.prayerEventsInit();
        }


        this.io.on('connect', (socket) => {

            this.socket = socket;

            if (this.clients.indexOf(socket) === -1) {
                this.clients.push(socket);
                console.log(chalk.bgGreen("New connection with id " + socket.id + "\nTotal " + this.clients.length));
            } else {
                return;
            }

            // Initialize (Connect)
            socket.emit(types.initialize, {
                config: {
                    version: this.version,
                    hasBluetooth: this.bluetooth.isBluetoothControlExists,
                    hasDj: this.config.DJ.DJEnabled,
                    hasSchedulesNextButton: this.config.Settings.NextButtonVisible,
                    bluetoothAutoConnectMac: this.config.Bluetooth.macID,
                    prayerEnabled: this.config.PrayerTime.Enabled,
                    hasVolumeControl: this.config.Settings.VolumeControl
                },
                schedules: {
                    currentSongIndex: this.schedulePlayer.currentSong.FilePosition,
                    currentSong: {
                        originalName: this.schedulePlayer.currentSong.OriginalName,
                        fileName: this.schedulePlayer.currentSong.FileName
                    },
                    songCount: this.schedulePlayer.currentSong.TotalFiles,
                    duration: this.schedulePlayer.currentSong.Duration,
                    position: this.schedulePlayer.currentSong.Position,
                    vumeter: {
                        left: this.schedulePlayer.currentSong.vumeterLeft,
                        right: this.schedulePlayer.currentSong.vumeterRight
                    }
                },
                connected: true,
                itsPrayerTime: this.prayer.itsPrayerTime,
                masterVolume: this.masterMixer.volume
            })

            // Disconnect
            socket.once(types.disconnect, () => {
                console.log(chalk.bgBlue.white("Client id " + socket.id + " disconnected"));
                utils.removeFromArray(this.clients, socket);
                console.log(chalk.bgBlue.white("Total connections: " + this.io.engine.clientsCount));
            });

            // Settings: Refresh Application
            socket.on(`${types.settings.namespace}/${types.settings.events.refreshApplication}`, () => {
                socket.emit(`${types.settings.namespace}/${types.settings.events.startedRefreshed}`)
                this.refreshApplication()
            });

            // Set master mixer volume
            socket.on(types.volume, (newVolume) => {
                if(newVolume) {
                    this.masterMixer.setMasterVolume(newVolume);
                    this.emitToAllClients(null, types.volume, newVolume);
                }
            });


            /*
                Schedules
            */

            if (this.schedulePlayer) {
                // Schedules: Next Song
                socket.on(`${types.schedules.namespace}/${types.schedules.events.nextTrack}`, () => {
                    this.schedulePlayer.playNext();
                });

                // Schedules: Get web media player status
                socket.on(`${types.schedules.namespace}/${types.schedules.events.getWebMediaPlayerStatus}`, () => {
                    socket.emit(`${types.schedules.namespace}/${types.schedules.events.getWebMediaPlayerStatus}`, {
                        src: this.schedulePlayer.currentSong.FileName,
                        songName: this.schedulePlayer.currentSong.OriginalName,
                        isPlaying: this.schedulePlayer.isPlaying,
                        position: this.schedulePlayer.currentSong.Position
                    });
                });
            }

            /* 
                Announces
            */

            if (this.announcePlayer) {
                // Announce: Get Status
                socket.on(`${types.announces.namespace}/${types.announces.events.getStatus}`, () => {
                    socket.emit(`${types.announces.namespace}/${types.announces.events.songChanged}`, {
                        fileName: this.announcePlayer.nowPlaying.FileName,
                        originalName: this.announcePlayer.nowPlaying.OriginalName,
                        duration: this.announcePlayer.nowPlaying.duration,
                        totalFiles: this.announcePlayer.nowPlaying.TotalFiles,
                        filePosition: this.announcePlayer.nowPlaying.FilePosition
                    });
                });

                // Announce: Get web media player status
                socket.on(`${types.announces.namespace}/${types.announces.events.getWebMediaPlayerStatus}`, () => {
                    socket.emit(`${types.announces.namespace}/${types.announces.events.getWebMediaPlayerStatus}`, {
                        src: this.announcePlayer.nowPlaying.FileName,
                        songName: this.announcePlayer.nowPlaying.OriginalName,
                        isPlaying: this.announcePlayer.isPlaying,
                        position: this.announcePlayer.nowPlaying.Position
                    });
                });
            }

            /*
                DJ
            */

            if (this.djPlayer) {
                // DJ: Get Play List
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.getLists}`, async () => {
                    let playList = await this.djPlayer.getCurrentPlaylist();
                    socket.emit(`${types.djPlayer.namespace}/${types.djPlayer.events.getLists}`, playList);
                });

                // DJ: Get Status
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.getStatus}`, () => {
                    socket.emit(`${types.djPlayer.namespace}/${types.djPlayer.events.getStatus}`, {
                        currentSong: this.djPlayer.nowPlaying,
                        looping: this.djPlayer.isLooping,
                        announce: this.djPlayer.enableAnnounces,
                        shuffle: this.djPlayer.enableShuffle,
                        currentList: this.djPlayer.currentList,
                        // CodinQ Added
                        playing: this.djPlayer.isPlaying
                    });
                });

                // DJ: Get web media player status
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.getWebMediaPlayerStatus}`, () => {
                    socket.emit(`${types.djPlayer.namespace}/${types.djPlayer.events.getWebMediaPlayerStatus}`, {
                        src: this.djPlayer.nowPlaying.FileName,
                        songName: this.djPlayer.nowPlaying.OriginalName,
                        isPlaying: this.djPlayer.isPlaying,
                        position: this.djPlayer.nowPlaying.Position
                    });
                });

                // DJ: Get Playing
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.getPlaying}`, () => {
                    socket.emit(`${types.djPlayer.namespace}/${types.djPlayer.events.getPlaying}`, {
                        playing: this.djPlayer.isPlaying
                    });
                });

                // DJ: Play List
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.playList}`, async (scheduleID) => {
                    await this.djPlayer.Play(scheduleID, this.djPlayer.enableAnnounces, this.djPlayer.isLooping, this.djPlayer.enableShuffle);

                    socket.emit(`${types.djPlayer.namespace}/${types.djPlayer.events.getStatus}`, {
                        currentSong: this.djPlayer.nowPlaying,
                        looping: this.djPlayer.isLooping,
                        announce: this.djPlayer.enableAnnounces,
                        shuffle: this.djPlayer.enableShuffle,
                        currentList: this.djPlayer.currentList,
                        // CodinQ Added
                        playing: this.djPlayer.isPlaying
                    });
                });

                // DJ: Stop
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.stopList}`, () => {
                    this.djPlayer.Stop();
                });

                // DJ: Next Song
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.nextSong}`, () => {
                    this.djPlayer.playNext();
                    // Refresh changed to getStatus event
                    socket.emit(`${types.djPlayer.namespace}/${types.djPlayer.events.getStatus}`, {
                        currentSong: this.djPlayer.nowPlaying,
                        looping: this.djPlayer.isLooping,
                        announce: this.djPlayer.enableAnnounces,
                        shuffle: this.djPlayer.enableShuffle,
                        currentList: this.djPlayer.currentList,
                        // CodinQ Added
                        playing: this.djPlayer.isPlaying
                    });
                });

                // DJ: Refresh Playlist
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.refreshPlaylist}`, async () => {
                    let playLists = await this.djPlayer.getCurrentPlaylist();
                    socket.emit(`${types.djPlayer.namespace}/${types.djPlayer.events.refreshPlaylist}`, {
                        playLists: playLists
                    });
                })

                // DJ: Toggle Announces
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.changeAnnounce}`, () => {
                    this.djPlayer.enableAnnounces = !this.djPlayer.enableAnnounces;
                });

                // DJ: Toggle Looping
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.changeLooping}`, () => {
                    this.djPlayer.isLooping = !this.djPlayer.isLooping;
                    this.djPlayer.Loop();
                });

                // DJ: Toggle Shuffle
                socket.on(`${types.djPlayer.namespace}/${types.djPlayer.events.changeShuffling}`, () => {
                    this.djPlayer.enableShuffle = !this.djPlayer.enableShuffle;
                    this.djPlayer.Shuffle();
                });
            }

            /*
                Stream
            */

            if (this.streamPlayer) {
                // Stream Player: Get status
                socket.on(`${types.streaming.namespace}/${types.streaming.events.getStatus}`, () => {
                    socket.emit(`${types.streaming.namespace}/${types.streaming.events.status}`, {
                        isActive: this.streamPlayer.isPlaying,
                        streamUrl: this.streamPlayer.streamUrl,
                        position: this.streamPlayer.position
                    });
                });

                // Stream Player: Get web media player status
                socket.on(`${types.streaming.namespace}/${types.streaming.events.getWebMediaPlayerStatus}`, () => {
                    socket.emit(`${types.streaming.namespace}/${types.streaming.events.getWebMediaPlayerStatus}`, {
                        src: this.streamPlayer.streamUrl,
                        songName: this.streamPlayer.streamUrl,
                        isPlaying: this.streamPlayer.isPlaying,
                        position: this.streamPlayer.position
                    });
                });
            }

            /*
                Bluetooth (BT)
            */

            if (this.osName === 'linux' && this.bluetooth) {
                // BT: Toggle Scan
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.scan}`, (bool) => {
                    this.bluetoothScanToggle(bool);
                });

                // BT: Get Devices  
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.getDevices}`, () => {
                    let bluetoothDevices = this.bluetooth.devices;
                    socket.emit(`${types.bluetooth.namespace}/${types.bluetooth.events.devices}`, bluetoothDevices)
                });

                // BT: Get Controller
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.getControllers}`, () => {
                    socket.emit(`${types.bluetooth.namespace}/${types.bluetooth.events.controllers}`, this.bluetooth.controllers);
                });

                // BT: Connect
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.connect}`, (deviceMac) => {
                    this.bluetooth.pair(deviceMac);
                    this.bluetooth.connect(deviceMac);
                });

                // BT: Disconnect
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.disconnect}`, (deviceMac) => {
                    this.bluetooth.disconnect(deviceMac);
                });

                // BT: Get Paired Devices
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.getPairedDevices}`, () => {
                    this.bluetooth.devices = [];
                    this.bluetooth.getPairedDevices();
                });

                // BT: Remove Device
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.removeDevice}`, (deviceMac) => {
                    console.log(chalk.bgBlue.white("Bluetooth removing device" + deviceMac));
                    this.bluetooth.remove(deviceMac);
                })

                // BT: Remember bluetooth device
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.rememberBluetooth}`, (deviceMac) => {
                    console.log(chalk.bgBlue.white(`Bluetooth device saving: ${deviceMac} to config`));

                    this.config.Bluetooth.isAutoConnectEnabled = "1";
                    this.config.Bluetooth.macID = deviceMac;

                    // Config File Write
                    let status = utils.iniContol.write(this.configFilePath, this.config);

                    socket.emit(`${types.bluetooth.namespace}/${types.bluetooth.events.rememberedBluetooth}`, {
                        status: status,
                        deviceMac: deviceMac
                    });
                });

                // BT: Forget bluetooth device
                socket.on(`${types.bluetooth.namespace}/${types.bluetooth.events.forgetBluetooth}`, (deviceMac) => {
                    console.log(chalk.bgBlue.white(`Bluetooth device removing: ${deviceMac} to config`));

                    this.config.Bluetooth.isAutoConnectEnabled = "0";
                    this.config.Bluetooth.macID = "";

                    let status = utils.iniContol.write(this.configFilePath, this.config);

                    socket.emit(`${types.bluetooth.namespace}/${types.bluetooth.events.forgetedBluetooth}`, {
                        status: status,
                        deviceMac: deviceMac
                    });
                });
            }

        });

    }

    /*
        Schedule
    */

    scheduleEventsInit() {
        //File Changed
        this.schedulePlayer.on(this.schedulePlayer.eventTypes.fileChanged, () => {
            this.emitToAllClients(types.schedules.namespace, types.schedules.events.songChanged, {
                fileName: this.schedulePlayer.currentSong.FileName,
                originalName: this.schedulePlayer.currentSong.OriginalName
            });
        });

        // Schedule: Position Channge
        this.schedulePlayer.on(this.schedulePlayer.eventTypes.positionChange, () => {
            this.emitToAllClients(types.schedules.namespace, types.schedules.events.positionChanged, {
                position: this.schedulePlayer.currentSong.Position,
                duration: this.schedulePlayer.currentSong.Duration,
                filePosition: this.schedulePlayer.currentSong.FilePosition,
                totalFiles: this.schedulePlayer.currentSong.TotalFiles
            });
        });

        // Schedule: Vumeter
        this.schedulePlayer.on(this.schedulePlayer.eventTypes.vumeter, () => {
            this.emitToAllClients(types.schedules.namespace, types.schedules.events.vumeterChanged, {
                left: this.schedulePlayer.currentSong.vumeterLeft,
                right: this.schedulePlayer.currentSong.vumeterRight
            });
        });

        // Schedule: State Changed
        this.schedulePlayer.on(this.schedulePlayer.eventTypes.stateChanged, (data) => {
            this.emitToAllClients(types.schedules.namespace, types.schedules.events.stateChange, data);
        });

        // Schedule: Playlist Finished
        this.schedulePlayer.on(this.schedulePlayer.eventTypes.playlistFinished, (data) => {
            this.emitToAllClients(types.schedules.namespace, types.schedules.events.playListFinished, {
                data: data
            });
        });
    }

    /*
        Annnounce
    */

    announceEventsInit() {

        // Announce: File Changed
        this.announcePlayer.on(this.announcePlayer.eventTypes.fileChanged, () => {
            this.emitToAllClients(types.announces.namespace, types.announces.events.songChanged, {
                fileName: this.announcePlayer.nowPlaying.FileName,
                originalName: this.announcePlayer.nowPlaying.OriginalName,
                totalFiles: this.announcePlayer.nowPlaying.TotalFiles,
                filePosition: this.announcePlayer.nowPlaying.FilePosition,
            });
        });

        // Announce: Position Changed
        this.announcePlayer.on(this.announcePlayer.eventTypes.positionChange, (activeFile, pos, dur, position, duration) => {
            this.emitToAllClients(types.announces.namespace, types.announces.events.positionChanged, {
                position: this.announcePlayer.nowPlaying.Position,
                duration: this.announcePlayer.nowPlaying.Duration,
            });
        });

        // Annnounce: Vumeter
        this.announcePlayer.on(this.announcePlayer.eventTypes.vumeter, (left, right) => {
            this.emitToAllClients(types.announces.namespace, types.announces.events.vumeterChanged, {
                left: left,
                right: right
            });
        });

        // Announce: State Changed
        this.announcePlayer.on(this.announcePlayer.eventTypes.announcesStarted, () => {
            this.emitToAllClients(types.announces.namespace, types.announces.events.announceStarted, true);
        });

        // Announce: Annnnounce Finished
        this.announcePlayer.on(this.announcePlayer.eventTypes.announcesFinished, () => {
            this.emitToAllClients(types.announces.namespace, types.announces.events.announceFinished, true);
        });

        // Announce: On Next Announce Time
        // this.announcePlayer.on(this.announcePlayer.eventTypes.onNextAnnounceTime, (remainingSeconds) => {
        //     this.emitToAllClients(types.announces.namespace, types.announces.events.remainingSeconds, {
        //         remainingSeconds: remainingSeconds
        //     })
        // });
    }

    /*
        DJ
    */

    djPlayerEventsInit() {
        // DJ: State Change
        this.djPlayer.on(this.djPlayer.eventTypes.stateChanged, (state) => {
            this.emitToAllClients(types.djPlayer.namespace, types.djPlayer.events.stateChange, {
                state: state
            });
        });

        // DJ: Playlist Finished
        this.djPlayer.on(this.djPlayer.eventTypes.playlistFinished, () => {
            this.emitToAllClients(types.djPlayer.namespace, types.djPlayer.events.playListFinished, true);
        });

        // DJ: File Changed
        this.djPlayer.on(this.djPlayer.eventTypes.fileChanged, () => {
            this.emitToAllClients(types.djPlayer.namespace, types.djPlayer.events.songChanged, {
                fileName: this.djPlayer.nowPlaying.FileName,
                originalName: this.djPlayer.nowPlaying.OriginalName,
                currentSongIndex: this.djPlayer.nowPlaying.FilePosition,
                songCount: this.djPlayer.nowPlaying.TotalFiles
            });
        });

        // DJ: Position Channged
        this.djPlayer.on(this.djPlayer.eventTypes.positionChange, (activeFile, pos, dur, position, duration) => {
            this.emitToAllClients(types.djPlayer.namespace, types.djPlayer.events.positionChange, {
                position: position,
                duration: duration
            });
        });

        // DJ: Vumeter
        this.djPlayer.on(this.djPlayer.eventTypes.vumeter, (left, right) => {
            this.emitToAllClients(types.djPlayer.namespace, types.djPlayer.events.vumeterChanged, {
                left: left,
                right: right
            })
        });

        // DJ: Start
        this.djPlayer.on(this.djPlayer.eventTypes.djPlayerStarted, (left, right) => {
            this.emitToAllClients(types.djPlayer.namespace, types.djPlayer.events.started, {
                playing: true
            })
        });

        // DJ: Stop
        this.djPlayer.on(this.djPlayer.eventTypes.djPlayerStopped, (left, right) => {
            this.emitToAllClients(types.djPlayer.namespace, types.djPlayer.events.stopped, {
                playing: false
            })
        });
    }

    /*
        Schedule Downloader
    */

    scheduleDownloaderEventsInit() {
        // Schedule Downloader: Progress
        this.schedulesDownloader.on(this.schedulesDownloader.eventTypes.onProgress, (fileName, percentage, currentMb, totalMb, speed, currentBytes, totalBytes, totalDownloadedFiles, totalFiles, filesSizeDownloaded, filesSize) => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.schedulesProgress, {
                fileName: fileName,
                totalMb: totalMb,
                currentMb: currentMb,
                percentage: percentage,
                speed: speed,
                currentBytes: currentBytes,
                totalBytes: totalBytes,
                currentFileIndex: totalDownloadedFiles,
                totalFiles: this.schedulesDownloader.TotalFiles,
                totalDownloadedFiles: totalDownloadedFiles,
                totalFiles: totalFiles,
                filesSizeDownloaded,
                filesSize: filesSize
            });
        });

        // Schedule Downloader: Download completed
        this.schedulesDownloader.on(this.schedulesDownloader.eventTypes.onDownloadCompleted, (pageStatus, pageMessage, fileName) => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.schedulesCompleted, {
                pageStatus: pageStatus,
                pageMessage: pageMessage,
                fileName: fileName
            });
        });

        // Schedule Downloader: Error
        this.schedulesDownloader.on(this.schedulesDownloader.eventTypes.onError, (message, fileName) => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.schedulesError, {
                message: message,
                fileName: fileName
            });
        });

        // Schedule Downloader: List download completed
        this.schedulesDownloader.on(this.schedulesDownloader.eventTypes.onListCompleted, () => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.schedulesListCompleted, true);
        });

    }

    /*
        Announce Downloader
    */

    announceDownloaderEventsInit() {
        // Announce Downloader: Progress
        this.announcesDownloader.on(this.announcesDownloader.eventTypes.onProgress, (fileName, percentage, currentMb, totalMb, speed, currentBytes, totalBytes, totalDownloadedFiles, totalFiles, filesSizeDownloaded, filesSize) => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.announcesProgress, {
                fileName: fileName,
                totalMb: totalMb,
                currentMb: currentMb,
                percentage: percentage,
                speed: speed,
                currentBytes: currentBytes,
                totalBytes: totalBytes,
                currentFileIndex: totalDownloadedFiles,
                totalFiles: this.schedulesDownloader.TotalFiles,
                totalDownloadedFiles: totalDownloadedFiles,
                totalFiles: totalFiles,
                filesSizeDownloaded,
                filesSize: filesSize
            });
        });

        // Announce Downloader: Download completed
        this.announcesDownloader.on(this.announcesDownloader.eventTypes.onDownloadCompleted, (pageStatus, pageMessage, fileName) => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.announcesCompleted, {
                pageStatus: pageStatus,
                pageMessage: pageMessage,
                fileName: fileName
            });
        });

        // Announce Dwonloader: Error (TODO)
        this.announcesDownloader.on(this.announcesDownloader.eventTypes.onError, (message, fileName) => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.announcesError, {
                message: message,
                fileName: fileName
            });
        });

        // Announce Downloader: List download completed
        this.announcesDownloader.on(this.announcesDownloader.eventTypes.onListCompleted, () => {
            this.emitToAllClients(types.downloads.namespace, types.downloads.events.announcesListCompleted, true);
        });
    }

    /*
        Stream Player
    */

    streamPlayerEventsInit() {
        // Stream Player: Vumeter
        this.streamPlayer.on(this.streamPlayer.streamEvents.vumeter, (left, right) => {
            this.emitToAllClients(types.streaming.namespace, types.streaming.events.vumeter, {
                left: left,
                right: right
            });
        });

        // Stream Player: File changed -- TODO
        this.streamPlayer.on(this.streamPlayer.streamEvents.fileChanged, (streamUrl) => {
            this.emitToAllClients(types.streaming.namespace, types.streaming.events.fileChanged, {
                streamUrl: streamUrl
            });
        });

        // Stream Player: Position change
        this.streamPlayer.on(this.streamPlayer.streamEvents.positionChange, (position) => {
            this.emitToAllClients(types.streaming.namespace, types.streaming.events.positionChange, {
                position: position
            });
        });

        // Stream Player: Started
        this.streamPlayer.on(this.streamPlayer.streamEvents.streamPlayerStarted, () => {
            this.emitToAllClients(types.streaming.namespace, types.streaming.events.started, {
                isPlaying: this.streamPlayer.isPlaying,
                streamUrl: this.streamPlayer.streamUrl
            });
        });

        // Stream Player: Finished
        this.streamPlayer.on(this.streamPlayer.streamEvents.streamPlayerStopped, () => {
            this.emitToAllClients(types.streaming.namespace, types.streaming.events.finished, false);
        });

        // Stream Player: Url changed
        this.streamPlayer.on(this.streamPlayer.streamEvents.urlChanged, (streamUrl) => {
            this.emitToAllClients(types.streaming.namespace, types.streaming.events.urlChange, {
                streamUrl: streamUrl
            });
        });
    }

    /*
        Bluetooth
    */

    bluetoothEventsInit() {
        // Bluetooth: Auto connnect control
        if (this.config.Bluetooth.isAutoConnectEnabled === "1") {
            try {
                console.log(chalk.bgBlue.white.bold(`Bluetooth auto connecting to: ${this.config.Bluetooth.macID}`))
                this.bluetooth.connect(this.config.Bluetooth.macID);
            }
            catch (error) {
                console.log(`Bluetooth auto connect failed: ${error}`);
            }
        }

        // Bluetooth: Controller info
        this.bluetooth.on(this.bluetooth.bluetoothEvents.Controller, (controllers) => {
            this.emitToAllClients(`${types.bluetooth.namespace}/${types.bluetooth.events.controllers}`, controllers);
        });

        // Bluetooth: Device found
        this.bluetooth.on(this.bluetooth.bluetoothEvents.Device, (devices) => {
            this.emitToAllClients(types.bluetooth.namespace, types.bluetooth.events.devices, devices);
        });
    }

    prayerEventsInit() {
        if(this.config.PrayerTime.Enabled === '1') {
            this.prayer.on(this.prayer.eventTypes.prayerBefore, () => {
               this.emitToAllClients(null, types.prayer, true);
            });

            this.prayer.on(this.prayer.eventTypes.prayerAfter, () => {
                this.emitToAllClients(null, types.prayer, false);
            })
        }
    }
}

module.exports = socketServer;
