require('linqjs');
const Player = require('./clsPlayer').clsPlayer;
const _ = require('lodash');
const rootPath = process.cwd();
const path = require('path');
const moment = require('moment');
//let uid = require('gen-uid');
//let chalk = require('chalk');
const PlaylistManager = class PlaylistManager {
    constructor({
        moment, utils, config,
        isLooping = true,
        shuffle = true,
        autoStart = true,
        minFileCountToPlay = 3,
        fadeInEnabled = true,
        musicVolume = 100, decodeOnly = true,
        logger
    } = {}) {
        this.moment = moment;
        this.utils = utils;
        this.config = config;
        this.shuffle = shuffle;
        this.isLooping = isLooping;
        this.autoStart = autoStart;
        this.minFileCountToPlay = minFileCountToPlay;
        this.fadeInEnabled = fadeInEnabled;
        this.musicVolume = musicVolume;
        this.mixerVolume = musicVolume;
        this.decodeOnly = decodeOnly;
        this.logger = logger;
        this.totalDownloaded = 0;
        this.index = -1;
        this.totalFiles = 0;
        this.activeFile = null;
        this.activeAnnounce = null;
        this.activeChannel = 0;
        this.fadePeriod = 4000;
        this.lastSongIndex = 0;
        this.path = path.join(rootPath, 'files');
        this.oldPlayer = null;
        this.player = null;
        this.activeScheduleChannels = [];
        this.chanToControl = 0;
        this.chanPos = 0;
        this.chanDur = 0;
        this.isDJ = false;
        // this.bassErrCount = 0;

        this.shuffled = [];
        this.isTimeManagementEnabled = true;
        this.isAnnouncePlaying = false;
        this.playerEvents = {
            stateChanged: 'stateChanged',
            positionChange: 'positionChange',
            fileChanged: 'fileChanged',
            playlistFinished: 'playlistFinished',
            fadeInStarted: 'fadeInStarted',
            fadeOutStarted: 'fadeOutStarted',
            vumeter: 'vumeter',
            notAGoodTime: 'notAGoodTime',
            Error: 'error',
            announcesFinished: 'announcesFinished',
            playbackFinished: 'playbackFinished'
        };
        this.startTime = null;
        this.endTime = null;

        this.lastPlayedSongOnDB = '';

        let mixerPlayer = new Player();
        this._mixerPlayer = mixerPlayer;

        mixerPlayer.on(mixerPlayer.playerEvents.stateChanged, (state) => {
            this.emit(this.playerEvents.stateChanged, state);
        });
        mixerPlayer.on(mixerPlayer.playerEvents.vumeter, (left, right) => {
            this.emit(this.playerEvents.vumeter, left, right);
        });
        this.announcesArray = [];

        mixerPlayer.initSoundCard(this.config.Settings.soundCard, mixerPlayer.basslib.BASS_DEVICE_SPEAKERS);

        //get multi output settings from config

        //default settings
        let mixerFlags = mixerPlayer.bassAttributes.BASS_SAMPLE_FLOAT;
        let speaker = mixerPlayer.bassAttributes.BASS_SAMPLE_DEFAULT;
        let channelCount = 2;
        this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
        //check config  mono out and which channel
        if (this.config.MultiOutput.isEnabled) {
            switch (parseInt(this.config.MultiOutput.Channel)) {
                case 1:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_FRONT;
                    break;
                case 2:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_REAR;
                    break;
                case 3:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_CENLFE;
                    channelCount = 1;
                    break;
                case 4:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_REAR2;
                    break;
                case 5:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_LEFT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 6:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_RIGHT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 7:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_FRONTLEFT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 8:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_FRONTRIGHT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 9:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_REARLEFT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 10:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_REARRIGHT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 11:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_CENTER;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 12:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_LFE;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 13:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_REAR2LEFT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                case 14:
                    speaker = mixerPlayer.speakerAttributes.BASS_SPEAKER_REAR2RIGHT;
                    channelCount = 1;
                    this.addChannelFlags = mixerPlayer.mixerAttributes.BASS_MIXER_DOWNMIX | mixerPlayer.mixerAttributes.BASS_MIXER_BUFFER;
                    break;
                default:
                    channelCount = 2;
                    break;
            }
        }

        if (this.decodeOnly) {
            speaker = mixerPlayer.bassAttributes.BASS_STREAM_DECODE;

        }
        this.addChannelFlags = this.addChannelFlags | mixerPlayer.bassAttributes.BASS_SAMPLE_FLOAT;
        //create the mixer
        let mixer = mixerPlayer.createMixer(channelCount, speaker);
        this.mixer = mixer;
        mixerPlayer.setVolume(mixer, this.mixerVolume);
        let err = mixerPlayer.getError();
        this.files = [];

        if (this.autoStart && !this.decodeOnly) {
            //start Mixer
            mixerPlayer.PlayMixer();
        }
    }

    setMixerVolume(newVolume) {
        this.mixerVolume = newVolume;
        this._mixerPlayer.setVolume(mixer, this.mixerVolume);
    }

    setMusicVolume(newVolume) {

        this.musicVolume = newVolume;
        if (this.oldPlayer == null) return;
        let m = this.oldPlayer;
        this.oldPlayer.setVolume(this.oldPlayer.channel, this.musicVolume);

    }

    addFiles(newFiles, lastSong) {
        /*
        this.files.push(newFiles);
        this.files = _.flattenDeep(this.files);
         */
        for (let i = 0; i < newFiles.length; i++) {
            this.files.push(newFiles[i]);
        }

        // knit shuffle method try
        /*
        serkan
        let total = this.files.length;
        let groupes = this.files.groupBy(c => c.scheduleID);
        let schedules = [];
        for(let i = 0; i < groupes.length; i++) {
            schedules[i] = _.shuffle(this.files.where(c => c.scheduleID == groupes[i][0].scheduleID));
        }
        let newArray = [];
        for(let i = 0; i < total; i++) {
            for(let j = 0; j < groupes.length; j++) {
                if(schedules[j].length > 0) {
                    newArray.push(schedules[j].shift());
                }
            }
        }
        this.files = newArray;
        this.shuffled = null;
        newArray = null;
         */
        /*
        can
        let grouped = this.files.groupBy(c => c.scheduleID);
        grouped.sort((x, y) => y.length - x.length);
        if(grouped.length > 2) {
            let q = _.shuffle(grouped[0]);
            let qq = _.shuffle(grouped[1]);
            let qqq = _.shuffle(grouped[2]);
            q.forEach((c) => {
                this.shuffled.push(c);
                let y = qq.shift();
                let yy = qqq.shift();
                if(y != undefined){
                    if(y.FileName != c.FileName) this.shuffled.push(y);
                }
                if(yy != undefined) {
                    if(yy.FileName != y.FileName && yy.FileName != c.FileName ) this.shuffled.push(yy);
                }
            });
        } else if(grouped.length > 1) {
            let q = _.shuffle(grouped[0]);
            let qq = _.shuffle(grouped[1]);
            q.forEach((c) => {
                this.shuffled.push(c);
                let y = qq.shift();
                if(y != undefined) {
                    if(y.FileName != c.FileName) this.shuffled.push(y);
                }
            });
        }
        grouped = null;
        this.files = this.shuffled;
        this.shuffled = [];
         */


        // knit shuffle method try


        this.lastPlayedSongOnDB = lastSong ? lastSong.FileName : '';
        this.setLastSong(lastSong);
        // if is already playing, then stop and streamfree it.
        /*  if (this.oldPlayer!=null) {
              if (this.oldPlayer.isPlaying) {
                  this.oldPlayer.FadeAndStop(1000);
              }
          }*/

        if (this.autoStart) {
            if (this.oldPlayer != null) {
                if (!this.oldPlayer.isPlaying) {
                    this.Play();
                } else {
                    this.logger.PlayerEventsSchedules('already playing , just added new files');
                }
            } else {
                this.Play();
            }
        }
    }

    addFile(newFile) {
        this.files.push(newFile);
    }

    clearFiles() {
        this.files = [];
    }

    setLastSong(song) {
        if (!song) {
            this.lastSongIndex = -1;
            return;
        }
        let index = _.findIndex(this.files, (o) => {
            return o.FileName == song.FileName;
        });
        if (index >= 0) {
            this.lastSongIndex = index;
        } else {
            this.logger.AudioEvents('this playlist is never played before');
        }
    }

    setFileStatus(filename, status) {
        //get the first index
        let index = _.findIndex(this.files, (o) => {
            return o.FileName == filename;
        });
        while (index > -1) {
            this.files[index].isDownloaded = status;
            //find the index in the files with same name
            index = _.findIndex(this.files, (o) => {
                return o.FileName == filename;
            }, ++index);
        }
    }

    PlayAnnounces() {
        if (this.isAnnouncePlaying) {
            setTimeout(() => {
                this.logger.PlayerEventsAnnounces('announce already playing');
                this.PlayAnnounces()
            }, 500);
            return;
        }

        this.isAnnouncePlaying = true;
        // if (this.announcesArray.length == 0) {
        //     this.emit(this.eventTypes.announcesFinished);
        //     this.isAnnouncePlaying = false;
        //     return;
        // }
        // we push array into announcesArray from announcePlayer, so we flatten it.
        this.announcesArray = _.flattenDeep(this.announcesArray);
        this.announcesArray = this.announcesArray.where(c => {
            return c.isDownloaded == true;
        });
        //this.announcesArray = [];

        //if there are no files to shift, shift returns undefined, emit announce finished and return.
        this.activeAnnounce = this.announcesArray.shift();
        if (this.activeAnnounce == undefined) {
            this.isAnnouncePlaying = false;
            this.emit(this.playerEvents.announcesFinished);
            return;
        }
        let p = new Player();
        let deviceInfo = p.getDevice(this.config.Settings.soundCard);
        if (!deviceInfo.IsInitialized) {
            this.logger.System(`${this.config.Settings.soundCard} wasnt initialized, trying initializing`);
            let init = p.init();
            if (!init) {
                this.logger.System(`Couldn't initialize ${this.config.Settings.soundCard}, err: ${p.getError()}. Restarting in 5 seconds.`);
                setTimeout(() => {
                    process.exit(4);
                }, 5000);
            }
        }

        p.on(p.playerEvents.positionChange, (position, duration, chan) => {
            let pos = moment({ hour: 0, minute: 0, second: 0 }).second(position).format('mm:ss');
            let dur = moment({ hour: 0, minute: 0, second: 0 }).second(duration).format('mm:ss');
            this.emit(this.playerEvents.positionChange, this.activeAnnounce, pos, dur, position, duration);
            let isPlaying = p.getIsPlaying(chan);
            if(!isPlaying){
                if(this.config.DebugMode.Debug == 1) {
                    this.logger.Debug(`channel playing: ${isPlaying}, chan: ${chan}`);
                    this.logger.Debug(`not playing, err: ${p.getError()}, position: ${pos}, duration: ${dur}, file: ${this.activeAnnounce}`);
                }
                process.exit();
            }
            pos = null;
            dur = null;
        });

        p.on(p.playerEvents.playbackFinished, (chan) => {
            this.isAnnouncePlaying = false;
            this.emit(this.playerEvents.playbackFinished, chan);
            this.activeAnnounce = null;
            setTimeout(() => {
                this.PlayAnnounces();
            }, 500);
            return;
        });
        let chan = p.openFile(path.join(this.path, this.activeAnnounce.FileName), p.bassAttributes.BASS_STREAM_DECODE | p.bassAttributes.BASS_SAMPLE_FLOAT);
        let err = p.getError();
        if(chan != 0 && err != 0) {
            this.isAnnouncePlaying = false;
            this.logger.PlayerEventsAnnounces(`Error! Channel created but there's a problem with the file. Err: ${err}, file: ${this.activeFile.FileName}, chan: ${chan}`);
            if(this.config.DebugMode.Debug == 1){
                this.logger.Debug('Bass error occured, starting logging cpu and memory info every 15 sec');
                let os = require('os');
                this.logger.Debug(`cpu: ${os.cpus()}`);
                this.logger.Debug(`devices: ${p.getDevices()}`);
                setInterval(() => {
                    this.logger.Debug(`Mem info: free: ${os.freemem()/1024} / total: ${os.totalmem()/1024} -- Avg cpu load:  1 - 5 - 15 min averages ${os.loadavg()} -- BASS cpu usage ${p.getCpu(chan)}`);

                }, 15000)
            }
        }
        if (chan == 0 || parseInt(err) != 0) {
            if (this.announcesArray.length == 0) {
                this.isAnnouncePlaying = false;
                this.emit(this.playerEvents.announcesFinished);
                this.logger.PlayerEventsAnnounces(`Error creating channel: ${err}, filename: ${this.activeAnnounce.FileName}`);
                this.emit(this.playerEvents.Error, this.activeAnnounce.FileName, err);
                return;
            }
            this.logger.PlayerEventsAnnounces(`Error creating channel: ${err}, filename: ${this.activeAnnounce.FileName}`);
            this.emit(this.playerEvents.Error, this.activeAnnounce.FileName, err);
            this.isAnnouncePlaying = false;
            setTimeout(() => {
                this.PlayAnnounces();
            }, 500);
            return;
        }
        p.Play();
        let result = this._mixerPlayer.addChannelToMixer(chan, this.addChannelFlags);
        let duration = p.Duration;
        this.emit(this.playerEvents.fileChanged, chan, this.activeAnnounce.FileName, this.activeAnnounce, duration);
    }

    setTimes() {
        // on db exception changes, schedulePlayer sets playlistManager's start and end times,
        // this method just changes the day without modifying hour.
        let now = new moment().utc(true);
        let nowDate = now.toJSON().substr(0, 11);
        if (this.startTime == null || this.endTime == null) {
            setTimeout(() => {
                this.setTimes();
            }, 500);
            return false;
        }
        this.startTime = new moment(nowDate + this.startTime.toJSON().substr(11, 8)).utc(true);
        this.endTime = new moment(nowDate + this.endTime.toJSON().substr(11, 8)).utc(true);
        return true;
    }

    Play() {
        let now = moment().utc(true);
        if (this.isTimeManagementEnabled) {
            this.setTimes();
            let isNowOkToPlay = now.isBetween(this.startTime, this.endTime, null, '[]');
            if (!isNowOkToPlay) {

                this.emit(this.playerEvents.notAGoodTime, this.startTime, this.endTime);
                return;
            }
        }

        let files = this.files.where(c => {
            return c.isDownloaded == true;
        });
        this.totalDownloaded = files.length;

        // if its coming from dj player, dont check for minimum number of files
        if (files.length < this.minFileCountToPlay && !this.isDJ) {

            //wait till enough files to play
            this.logger.PlayerEventsSchedules(`waiting for ${this.minFileCountToPlay} , now we have ${files.length}`);
            setTimeout(() => {
                this.Play();
            }, 2000);
            return;
        }

        ++this.lastSongIndex;
        this.lastSongIndex = (this.lastSongIndex % this.files.length);
        let index = _.findIndex(this.files, (o) => {
            return o.isDownloaded && !o.isPlayed;
        }, this.lastSongIndex);


        try {
            if (this.files && this.files[index]) {

                if (this.lastPlayedSongOnDB == this.files[index].FileName) {
                    this.files[index].isPlayed = true;
                    //this means the last played file on db is same with the selected index.
                    ++this.lastSongIndex;
                    //clear it.. we dont use it anymore
                    this.lastPlayedSongOnDB = '';
                    setTimeout(() => {
                        this.Play();
                    }, 500);
                    return;
                }
            }
        }
        catch (e) {

        }


        // if index=-1 then all files are played,
        //  now reset all of them.
        if (index == -1) {
            this.lastSongIndex = 0;
            this.logger.PlayerEventsSchedules('played all files');
            this.emit(this.playerEvents.playlistFinished);

            if (this.isLooping) {
                this.files.forEach(c => c.isPlayed = false);
                // check if shuffle
                if (this.shuffle) {
                    this.logger.PlayerEventsSchedules('shuffling playlist');
                    // another fast shuffling
                    // this.files=this.files.orderBy(c=>uid.token(true))
                    this.files = _.shuffle(this.files);
                    this.logger.PlayerEventsSchedules('shuffle completed');
                }
                setTimeout(() => {
                    this.Play();
                }, 500);
            }
            return;
        }


        this.files[index].isPlayed = true;

        this.activeFile = this.files[index];
        //false metadata files
        //this.activeFile.FileName = 'b5d9d93c-8642-4285-a4d9-9fdd8590084b.mp3';
        //this.activeFile.FileName = 'b1a34d64-cc4f-4339-9456-e4802bfed648.mp3'; // ugur 5 sn eksik sarki

        let p = new Player();
        let deviceInfo = p.getDevice(this.config.Settings.soundCard);
        if (!deviceInfo.IsInitialized) {
            this.logger.System(`${this.config.Settings.soundCard} wasnt initialized, trying initializing`);
            let init = p.init();
            if (!init) {
                this.logger.System(`Couldn't initialize ${this.config.Settings.soundCard}, err: ${p.getError()}. Restarting in 5 seconds.`);
                setTimeout(() => {
                    process.exit(4);
                }, 5000);
            }
        }
        this.player = p;
        p.on(p.playerEvents.positionChange, (position, duration, chan) => {
            let pos = moment({ hour: 0, minute: 0, second: 0 }).second(position).format('mm:ss');
            let dur = moment({ hour: 0, minute: 0, second: 0 }).second(duration).format('mm:ss');
            this.emit(this.playerEvents.positionChange, this.activeFile, pos, dur, position, duration);
            let isPlaying = p.getIsPlaying(chan);
            if(!isPlaying){
                if(this.config.DebugMode.Debug == 1) {
                    this.logger.Debug(`channel playing: ${isPlaying}, chan: ${chan}`);
                    this.logger.Debug(`not playing, err: ${p.getError()}, position: ${pos}, duration: ${dur}, file: ${this.activeAnnounce}`);
                }
                process.exit();
            }
            // this.chanDur = duration;
            // this.chanPos = position;
            pos = null;
            dur = null;
        });

        p.on(p.playerEvents.fadeOutStarted, (chan) => {
            this.emit(this.playerEvents.fadeOutStarted, chan);
            p.clearPositionEvent();
            this.Play();
        });

        p.on(p.playerEvents.fadeInStarted, (chan) => {
            //this.chanToControl = chan;
            this.emit(this.playerEvents.fadeInStarted, chan);
        });

        p.on(p.playerEvents.playbackFinished, (chan) => {
            //this is a necessary control for false metadata files. if metadata is wrong, bass gives a false duration. if fade in is enabled,
            // we play the next song 3 seconds before the duration BUT false metadata may lead the song not reach to last 3 seconds of false duration,
            //therefor we set position, duration and chan to a variable on every position change, and check these variables on playbackfinished event.
            //if playback is finished and position and duration difference is bigger than 3 secs we play next song.
            // if (chan == this.chanToControl && (this.chanDur - this.chanPos) > 3) {
            //     this.logger.PlayingSchedules(chalk.red(`Player stopped unexpectedly, probably this files metadata is wrong, playing next song. Position: ${this.chanPos}, Duration: ${this.chanDur}, file: ${this.activeFile.FileName}`));
            //     p.StopChannel(this.chanToControl);
            //     this.Play();
            // }
            this.activeScheduleChannels.remove(chan);
            this.logger.PlayerEventsSchedules(`Removed channel: ${chan} from active schedule channels`);
            this.emit(this.playerEvents.playbackFinished, chan);
            if (!this.fadeInEnabled) {
                setTimeout(() => {
                    this.Play();
                }, 500);
                return;
            }
        });
        p.on(p.playerEvents.stateChanged, (state) => {
            this.emit(this.playerEvents.stateChanged, state);
        });


        let chan = p.openFile(path.join(this.path, this.activeFile.FileName), p.bassAttributes.BASS_STREAM_DECODE | p.bassAttributes.BASS_SAMPLE_FLOAT | p.bassAttributes.BASS_STREAM_PRESCAN);
        if (chan && chan != 0) {
            if(this.activeScheduleChannels.length < 2) {
                this.activeChannel = chan;
                this.activeScheduleChannels.push(this.activeChannel);
            } else {
                this.logger.PlayerEventsSchedules(`There are already 2 active schedule channels, not creating new one`);
                return;
            }
        }
        /*
        on playlist change, 2 channels are created and 2 songs are played at the same time,
        to fix this, we set the active channel to created channel.
        we'll look for if this channel is playing on playbackFinished event and if its playing,
        return before new channel is created.
         */
        let err = parseInt(p.getError());
        if(chan != 0 && err != 0) {
            this.logger.PlayerEventsSchedules(`Error! Channel created but there's a problem with the file. Err: ${err}, file: ${this.activeFile.FileName}, chan: ${chan}`);
            if(this.config.DebugMode.Debug == 1){
                this.logger.Debug('Bass error occured, starting logging cpu and memory info every 15 sec');
                let os = require('os');
                this.logger.Debug(`cpu: ${os.cpus()}`);
                this.logger.Debug(`devices: ${p.getDevices()}`);
                setInterval(() => {
                    this.logger.Debug(`Mem info: free: ${os.freemem()/1024} / total: ${os.totalmem()/1024} -- Avg cpu load:  1 - 5 - 15 min averages ${os.loadavg()} -- BASS cpu usage ${p.getCpu(chan)}`);

                }, 15000)
            }
        }
        if (chan == 0 || err != 0) {
            if(chan == this.activeChannel) {
                this.activeScheduleChannels.remove(this.activeChannel);
            }
            // ++this.bassErrCount;
            this.logger.PlayerEventsSchedules(`Error creating channel, err: ${err}, file: ${this.activeFile.FileName}, chan: ${chan}`);
            this.emit(this.playerEvents.Error, this.activeFile.FileName, err);
            if(this.config.DebugMode.Debug == 1){
                this.logger.Debug('Bass error occured, starting logging cpu and memory info every 15 sec');
                let os = require('os');
                this.logger.Debug(`cpu: ${os.cpus()}`);
                this.logger.Debug(`devices: ${p.getDevices()}`);
                setInterval(() => {
                    this.logger.Debug(`Mem info: free: ${os.freemem()/1024} / total: ${os.totalmem()/1024} -- Avg cpu load:  1 - 5 - 15 min averages ${os.loadavg()}`);

                }, 15000)
            }
            // if(this.bassErrCount == 10) {
            //     process.exit(5);
            // }
            setTimeout(() => {
                this.Play();
            }, 1000);
            return;
        }
        //this.emit(this.eventTypes.fileChanged,chan,this.activeFile.FileName,this.activeFile);
        // this.bassErrCount = 0;
        this.oldPlayer = p;
        //check if fadein/fadeout enabled
        if (this.fadeInEnabled) {
            p.setVolume(chan, 0);
            p.setFadeIn(chan, this.musicVolume, this.fadePeriod);
            //p.setFadeIn(chan, 10,this.fadePeriod)
            p.setFadeOut(chan, this.fadePeriod);
        } else {
            p.setVolume(chan, this.musicVolume);
            p.Play();
        }

        let result = this._mixerPlayer.addChannelToMixer(chan, this.addChannelFlags);
        if (result != 1) {
            let err = parseInt(p.getError());
            this.logger.PlayerEventsSchedules(`Error adding channel to mixer, err: ${err}`);
            this.emit(this.playerEvents.Error, this.mixer, err);
        }
        let duration = p.Duration;
        this.emit(this.playerEvents.fileChanged, chan, this.activeFile.FileName, this.activeFile, duration, index);


        // jump to last 8 seconds of the song
        // if(!this.utils.isCompiled) {
        //
        //     setTimeout(() => {
        //         console.log(chalk.bgGreen('Dev mode: jump to last 8 secs'));
        //         p.setPosition(chan, duration - 5)
        //     }, 8000)
        // }
    }
};

const util = require('util');
const EventEmitter = require('events').EventEmitter;
util.inherits(PlaylistManager, EventEmitter);
module.exports = PlaylistManager;