/*!
**|   CyTube Audio Notifications System
**|   Copyright 2013-2016 Xaekai
**|   Version 2016.09.28.1700
**|
**@requires playlist
**@optional settings
**@optional audiolib
**@optional whispers
**@preserve
*/

'use strict';

// -- Channel Namespace --
if(!window[CHANNEL.name]){
    window[CHANNEL.name] = {};
}

// -- Begin Module
(function (CyTube_Notifications) {
    return CyTube_Notifications(window, document, window.jQuery);
}

// Locally scoped parameters 
(function (window, document, $, undefined) {

    // Do we have our prerequisites?
    if(typeof(Storage) === 'undefined') {
        console.error('[XaeTube: Audio Notifier]', "localStorage not supported. Aborting load.");
        return;
    } else if (typeof(window.playlist) !== 'function'){
        console.error('[XaeTube: Audio Notifier]', "Playlist parser unavailable. Aborting load.");
        return;        return;
    } else {
        console.info('[XaeTube: Audio Notifier]', "Loading Module.");
    }

    // Do we have our optionals?
    if (typeof(window[CHANNEL.name].audioLibrary) === 'undefined'){
        console.warn('[XaeTube: Audio Notifier]', "WARNING: Audio library module not loaded.");
    }
    // TODO: Replace this
    if (!$("#customSettingsStaging").length){
        console.warn('[XaeTube: Audio Notifier]', "WARNING: Settings module not loaded.");
    }


    const AudioNotifier = function(){
        this.Squee = { timeSinceLast: 0, toggleState: true, volume: (0.60), id: 'squee'      };
        this.Poll  = { timeSinceLast: 0, toggleState: true, volume: (0.30), id: 'votingpoll' };
        this.Priv  = { timeSinceLast: 0, toggleState: true, volume: (0.35), id: 'uhoh'       };
        this.Video = { timeSinceLast: 0, toggleState: true, volume: (0.35), id: 'fairywand'  };

        this.typeNames = {
            Squee: "Username",
            Poll:  "Poll",
            Priv:  "Private Message",
            Video: "Queued Video",
        };

        this.choices = Object.assign({}, { 
                squee:      "https://resources.pink.horse/sounds/squee.ogg" ,
                votingpoll: "https://resources.pink.horse/sounds/votingpoll.ogg",
                uhoh:       "https://resources.pink.horse/sounds/uhoh.ogg",
                fairywand:  "https://resources.pink.horse/sounds/fairy_wand.ogg",
            },
            window[CHANNEL.name].audioLibrary ? window[CHANNEL.name].audioLibrary.squees : undefined
        )

        this.handler = {
            // chatMsg
            Squee: function(data) {
                var squee;

                // -- Off state
                if(!this.Squee.toggleState){return;}
                // -- Squees aren't parsed when throttle is off
                if(!CHANNEL.opts.chat_antiflood){ 
                    console.info('[XaeTube: Audio Notifier]', "User ping ignored: Chat throttle off.")
                    return;
                }
                // -- Cooldown
                if(Date.now() - this.Squee.timeSinceLast < 7000) return;

                // -- Do we have squees?
                squee = $('.nick-highlight:not( .parsed )');
                // -- No squees
                if (!squee.length) return;

                squee.addClass('parsed');

            // START HALLOWEEN FUN
                var start   = Date.parse('2015-10-31T04:00:00Z'), 
                    end     = Date.parse('2015-11-01T04:00:00Z'), 
                    current = Date.now();

                current > start && end > current ? function(){ toot = new Audio('/skulltrumpet.wav'); toot.volume = 0.33; toot.play() }() : 
            // END HALLOWEEN FUN

                this.Squee.audio[0].play();
                this.Squee.timeSinceLast = Date.now()

            }.bind(this),
            // newPoll
            Poll: function(data) {
                // -- Off state
                if(!this.Poll.toggleState) return;
                // -- If you can't vote, polls don't mean much
                if(CLIENT.rank < CHANNEL.perms.pollvote) return;
                // -- Cooldown
                if(Date.now() - this.Poll.timeSinceLast < 360000) return;

                this.Poll.audio[0].play();
                this.Poll.timeSinceLast = Date.now()
            }.bind(this),
            // pm
            Priv: function(data) {
                // -- Off state
                if(!this.Priv.toggleState) return;
                // -- Your own messages
                if(data.username == CLIENT.name) return;
                // -- When you already have an PM input in focus
                if($(document.activeElement).hasClass("pm-input")) return;
                // -- Cooldown
                if(Date.now() - this.Priv.timeSinceLast < 180000) return;

                this.Priv.audio[0].play();
                this.Priv.timeSinceLast = Date.now()
                $("div.chat-msg-\\\\\\$server\\\\\\$:contains(Private Message Notification)").remove();
                $('#messagebuffer').trigger('whisper', "Private Message Notification");
            }.bind(this),
            // changeMedia
            Video: function(data) {
                var addedby;
                // -- Off state
                if(!this.Video.toggleState) return;

                // -- We don't work if you can't see the playlist
                if(CLIENT.rank < CHANNEL.perms.seeplaylist) return;
                // -- Not really needed when we have consecutive videos
                addedby = (playlist(true).addedby == CLIENT.name);
                if(addedby && this.Video.last) {
                    this.Video.timeSinceLast = Date.now()
                    return;
                }
                // -- Not consecutive anymore
                this.Video.last = false;
                // -- Not our video
                if(!addedby) return;
                // -- Cooldown
                if(Date.now() - this.Video.timeSinceLast < 600000) return;

                this.Video.audio[0].play();
                this.Video.timeSinceLast = Date.now();
                this.Video.last = true;
                $("div.chat-msg-\\\\\\$server\\\\\\$:contains(Video Notification)").remove();
                $('#messagebuffer').trigger('whisper', "Video Notification: Your video is now playing!");
            }.bind(this),
        };

        return this;
    }

    Object.assign(AudioNotifier.prototype, {
        pushNoticeChange : function(change){
            var type, id, silent;
            type   = change.type;
            id     = change.id;
            silent = change.silent;

            this[type].id = id;
            this[type].file = this.choices[id]

            localStorage.setItem((`${CHANNEL.name}_AudioNotice${type}ID`), id);

            $('#AudioNotice' + (this.typeNames[type].split(" ")[0]) ).remove();
            this[type].audio = $("<audio>")
                .prop("id",('AudioNotice'+(this.typeNames[type].split(" ")[0])))
                .appendTo('body')
                .attr("preload","auto")
                .prop("volume", this[type].volume)
                .append($("<source>")
                        .attr("src",this[type].file)
                        .attr("type","audio/ogg")
                    )
            if(!silent){
                this[type].audio[0].play();
                $("div.chat-msg-\\\\\\$server\\\\\\$:contains(" + this.typeNames[type] + " Notification)").remove();
                $('#messagebuffer').trigger('whisper', this.typeNames[type] + " Notification Changed to: " + id);
            }
        },

        pushVolume : function(change){
            var type, volume;
            type   = change.type;
            volume = change.volume;

            if(volume == "up"){
                volume = (((this[type].volume * 100) + 5) / 100)
            } else if(volume == "down"){
                volume = (((this[type].volume * 100) - 5) / 100)
            } else {
                return console.error('[XaeTube: Audio Notifier]', "Unrecognized volume direction.");
            }
            volume = Math.min(Math.max(volume,0.05), 1.00) || (0.6);

            this[type].volume = volume;

            localStorage.setItem(`${CHANNEL.name}_AudioNotice${type}Volume`, Math.floor(volume * 100));
            this[type].audio.prop("volume", volume)[0].play();

            if(this[type].indicator){
                this[type].indicator.html(Math.floor(volume * 100));
            }
        },

        toggle : function (type) {
            this[type].toggleState = !this[type].toggleState;
            localStorage.setItem(`${CHANNEL.name}_AudioNotice${type}Toggle`, +this[type].toggleState);

            if(this[type].toggleButton){
                this[type].toggleButton.toggleClass('label-default label-info');
            }

            this[type].panel.toggleClass('btn-danger btn-success');
        },

        createToggles : function(){
            this.Squee.toggleButton = $("<span/>")
                .html('Sq<span class="toggle-label">uee</span>')
                .prop('id', 'AudioNoticeSqueeToggle')
                .attr('title', 'Toggle Username Audio Notices')
                .addClass("pointer label label-info pull-right")
                .on('click', ()=>{ this.toggle("Squee") })
                .appendTo($("#chatheader"))
                ;

            // Correct button appearace if toggle state is off
            if(!this.Squee.toggleState) {
                this.Squee.toggleButton
                    .removeClass("label-info").addClass("label-default");
            } 
        },

        createControls : function(types){
            var self = this;

            this.controls = $('<div>')
                .addClass('customSettings')
                .attr('id','AudioNoticeControls')
                .attr('data-title', "Audio Notifications Settings")
                .prependTo('#customSettingsStaging')
                .data('column-class','col-sm-6')
                ;

            while(types.length){
                var type = types.shift();

                var form = $('<form>')
                    .prop("action", "javascript:void(0)")
                    .addClass("form-horizontal")
                    ;
                var wrapper = $('<div>')
                    .addClass("form-group")
                    .prop("id", "AudioNoticeControls" + type)
                    .appendTo(form)
                    ;
                var label = $('<span>')
                    .addClass("label label-info col-sm-3")
                    .text(this.typeNames[type] + " Notice")
                    .appendTo(wrapper)
                    ;
                var buttongroup = $('<div>')
                    .addClass("btn-group col-sm-8")
                    .attr("data-control", type)
                    .appendTo(wrapper)
                    ;
                var toggle = this[type].panel = $("<button/>")
                    .prop("id", "AudioNoticeControls" + type + "Toggle")
                    .addClass("btn btn-sm btn-success")
                    .attr("title", "Toggle " + this.typeNames[type] + " Notices")
                    .html('<span class="glyphicon glyphicon-bell"></span>')
                    .on('click', function(){
                        self.toggle($(this).parent().data().control)
                    })
                    .prependTo(buttongroup)
                    ;
                var sounds = $("<div/>")
                    .addClass("btn-group")
                    .prop("id", "AudioNoticeControls" + type + "Sounds")
                    .appendTo(buttongroup)
                    ;
                var volumeDown = $("<button/>")
                    .prop("id", "AudioNoticeControls" + type + "VolumeDown")
                    .addClass("btn btn-sm btn-default")
                    .attr("title", this.typeNames[type] + " Volume Down")
                    .on('click', function(){
                        self.pushVolume({
                            type   : $(this).parent().data().control,
                            volume : "down"
                        });
                    })
                    .html('<span class="glyphicon glyphicon-volume-down"></span>')
                    .appendTo(buttongroup)
                    ;
                var indicator = this[type].indicator = $("<button/>")
                    .prop("id", "AudioNoticeControls"+type+"Indicator")
                    .addClass("btn btn-sm btn-default")
                    .attr("title", this.typeNames[type] + " Volume")
                    .html( this[type].volume * 100 )
                    .appendTo(buttongroup)
                    ;
                var volumeUp = $("<button/>")
                    .prop("id", "AudioNoticeControls"+type+"VolumeUp")
                    .addClass("btn btn-sm btn-default")
                    .attr("title", this.typeNames[type] + " Volume Up")
                    .on('click', function(){
                        self.pushVolume({
                            type   : $(this).parent().data().control,
                            volume : "up"
                        });
                    })
                    .html('<span class="glyphicon glyphicon-volume-up"></span>')
                    .appendTo(buttongroup)
                    ;
                var play = $("<button/>")
                    .prop("id", "AudioNoticeControls"+type+"Play")
                    .addClass("btn btn-sm btn-default")
                    .attr("title", "Play Notification")
                    .on('click', function(){
                        self[$(this).parent().data().control].audio[0].play();
                    })
                    .html('<span class="glyphicon glyphicon-play"></span>')
                    .appendTo(buttongroup)
                    ;
                var dropdown = $("<button/>")
                    .addClass("btn btn-default btn-sm dropdown-toggle")
                    .attr("type", "button")
                    .attr("href", "javascript:void(0)")
                    .attr("data-toggle", "dropdown")
                    .html("<span class='glyphicon glyphicon-music'></span> Sound <span class='caret'></span>")
                    .appendTo(sounds)
                    ;
                var sound_content = $("<ul/>")
                    .addClass("dropdown-menu")
                    .addClass("columns")
                    .attr("role", "menu")
                    .appendTo(sounds)
                    ;

                var keys = Object.keys(this.choices)
                while(keys.length){
                    var populate_list = $("<li/>").appendTo(sound_content);
                    void (function(key) {
                        $("<a/>")
                            .text(key)
                            .attr("href", "javascript:void(0)")
                            .attr("data-notice", key)
                            .attr("data-type", type)
                            .on('click', function(){
                                console.log($(this).data().type, $(this).data().notice)
                                self.pushNoticeChange({
                                    type: $(this).data().type,
                                    id: $(this).data().notice,
                                    silent: false
                                })
                            })
                            .appendTo(populate_list);
                    })(keys.shift());
                }

                // -- Correct toggle appearance from persistence
                if(!this[type].toggleState){
                    toggle.toggleClass("btn-success btn-danger");
                }

                this.controls.append(form);
            }
        },

        initialize : function(){
            this.initialized = true;

            // -- Listeners
            socket.on("chatMsg",     (data)=>{ this.handler["Squee"](data); });
            socket.on("newPoll",     (data)=>{ this.handler["Poll"](data);  });
            socket.on("pm",          (data)=>{ this.handler["Priv"](data);  });
            socket.on("changeMedia", (data)=>{ this.handler["Video"](data); });

            // -- Module Options
            if(window[CHANNEL.name].modulesOptions && window[CHANNEL.name].modulesOptions.audioNotice){
                this.choices = Object.assign(this.choices, window[CHANNEL.name].modulesOptions.audioNotice.choices)

                // This lets you override the default soundID used by a notice
                var notices = Object.keys(window[CHANNEL.name].modulesOptions.audioNotice.notices)
                for (var i = notices.length - 1; i >= 0; i--) {
                    this[notices[i]]["id"] = window[CHANNEL.name].modulesOptions.audioNotice.notices[notices[i]]
                };

            }

            // -- Persistent state support --
            var types = Object.keys(this.typeNames);
            while(types.length){
                var type = types.shift();

                var toggle = localStorage.getItem(`${CHANNEL.name}_AudioNotice${type}Toggle`);
                var id     = localStorage.getItem(`${CHANNEL.name}_AudioNotice${type}ID`);
                var volume = localStorage.getItem(`${CHANNEL.name}_AudioNotice${type}Volume`);

                if (toggle) { this[type].toggleState = parseInt(toggle) }
                if (id)     { this[type].id = id }
                if (volume) { this[type].volume = (parseInt(volume)/100) || (0.6) }

                this.pushNoticeChange({
                    type   : type, 
                    id     : this[type].id,
                    silent : true
                }); 
            }

            this.createToggles();
            this.createControls(Object.keys(this.typeNames));

            console.info('[XaeTube: Audio Notifier]', "System Initialized.");
            return this;
        }

    })

    window[CHANNEL.name].audioNotice = new AudioNotifier().initialize();
/*
** END OF IIFE
*/
}));
// END OF FILE