/**
* Functions related to VU meters.
* These functions are intimately tied to the markup defined in the
* VU templates in _vu_meters.html.erb
*/
(function(context, $) {

    "use strict";

    context.JK = context.JK || {};

    // As these are helper functions, just have a single
    // static object with functions. Each function should
    // take all necessary arguments to complete its work.
    context.JK.VuHelpers = {

        registeredMixers: [],

        /**
        * Render a VU meter into the provided selector.
        * vuType can be either "horizontal" or "vertical"
        */
        renderVU: function(selector, userOptions) {
            selector = $(selector);


            /**
            * The default options for rendering a VU
            */
            var renderVUDefaults = {
                vuType: "vertical",
                lightCount: 12,
                lightWidth: 3,
                lightHeight: 17
            };

            var options = $.extend({}, renderVUDefaults, userOptions);
            var templateSelector = "#template-vu-v";
            if (options.vuType === "horizontal") {
                templateSelector = "#template-vu-h";
            }
            var templateSource = $(templateSelector).html();

            selector.each(function() {
                var $track = $(this);
                $track.empty();
                $track.html(context._.template(templateSource, options, {variable: 'data'}));
            })

        },

        /**
        * Given a selector representing a container for a VU meter and
        * a value between 0.0 and 1.0, light the appropriate lights.
        */
        updateVU: function ($selector, value) {
            // There are 13 VU lights. Figure out how many to
            // light based on the incoming value.
            $selector.each(function() {
                var $track = $(this)
                var countSelector = 'tr';
                var horizontal = ($track.find('table.horizontal').length);
                if (horizontal) {
                    countSelector = 'td';
                }

                var lightCount = $track.find(countSelector).length;
                var i = 0;
                var state = 'on';
                var lights = Math.round(value * lightCount);
                var redSwitch = Math.round(lightCount * 0.6666667);

                var $light = null;
                var colorClass = 'vu-green-';
                var lightSelectorPrefix = $track.find('td.vu');
                var thisLightSelector = null;

                // Remove all light classes from all lights
                var allLightsSelector = $track.find('td.vulight');
                $(allLightsSelector).removeClass('vu-green-off vu-green-on vu-red-off vu-red-on');

                // Set the lights
                for (i = 0; i < lightCount; i++) {
                    colorClass = 'vu-green-';
                    state = 'on';
                    if (i >= redSwitch) {
                        colorClass = 'vu-red-';
                    }
                    if (i >= lights) {
                        state = 'off';
                    }

                    var lightIndex = horizontal ? i : lightCount - i - 1;
                    allLightsSelector.eq(lightIndex).addClass(colorClass + state);
                }
            })

        },

        createQualifiedId: function(mixer) {
          return (mixer.mode ? 'M' : 'P') + mixer.id
        },

        // type can be 'single' or 'double', meaning how the VU is represented (one set of lights, two)
        // mixerId is the ID of the mixer
        // and someFunction is used to make the registration (equality check).
        registerVU: function(type, mixer, someFunction, horizontal, lightCount, lights) {

            var fqId = this.createQualifiedId(mixer)
            var registrations = this.registeredMixers[fqId]
            if (!registrations) {
                registrations = []
                this.registeredMixers[fqId] = registrations
            }

            if(type == 'best') {
                registrations.push({type:type, ptr: someFunction, ptrCount: 1, horizontal: horizontal, lightCount: lightCount, lights:lights})
            }
            else {
                // find the right registration and add left lights or right lights to it
                var found = null
                context._.each(registrations, function(registration) {
                    if(registration.ptr == someFunction) {
                        found = registration;
                        return false;
                    }
                })

                if(!found) {
                    found = {type:type, ptr: someFunction, ptrCount: 1, horizontal: horizontal, lightCount: lightCount}
                    registrations.push(found);
                }
                else {
                    found.ptrCount++;
                }

                if(type == 'left') {
                    //logger.debug("adding left lights")
                    found.leftLights = lights;
                }
                else {
                    //logger.debug("adding right lights");
                    found.rightLights = lights;
                }

            }
        },

        unregisterVU: function(mixer, someFunction) {
            var fqId = this.createQualifiedId(mixer)
            var registrations = this.registeredMixers[fqId]
            if (!registrations || registrations.length == 0) {
                logger.debug("no registration found for:" + fqId, registrations, this.registeredMixers)
                return
            }
            else {
                //logger.debug("unregistering " + fqId + ", " + registrations.length)
            }

            var origLength = registrations.length;
            registrations = registrations.filter(function(element) {
                var isMatch = element.ptr == someFunction;

                if(isMatch) {
                    // found a registration that matches
                    //logger.debug("removing matching ptr", element.ptr)
                    element.ptrCount--;

                    // keep the registration if any ptr's still left
                    var keepRegistration = element.ptrCount > 0;
                    if(!keepRegistration) {
                        //logger.debug("getting rid of the registration; no more ptrs");
                    }
                    return keepRegistration;
                }
                else {
                    // keep the registration if this does not match the ptr
                    return true;
                }
            })

            this.registeredMixers[fqId] = registrations
        },

        updateSingleVU: function(horizontal, lightCount, $lights, value, isClipping) {

            var i = 0;
            var state = 'on';
            var lights = Math.round(value * lightCount);
            var redSwitch = Math.round(lightCount * 0.6666667);

            var $light = null;
            var colorClass = 'vu-green-';
            var thisLightSelector = null;

            // Remove all light classes from all lights
            $lights.removeClass('vu-green-off vu-green-on vu-red-off vu-red-on');

            // Set the lights
            for (i = 0; i < lightCount; i++) {
                colorClass = 'vu-green-';
                state = 'on';
                if (i >= redSwitch) {
                    colorClass = 'vu-red-';
                }
                if (i >= lights) {
                    state = 'off';
                }

                var lightIndex = horizontal ? i : lightCount - i - 1;
                $lights.eq(lightIndex).addClass(colorClass + state);
            }
        },

        // sentMixerId  ends with vul or vur
        updateVU3: function(mixer, leftValue, leftClipping, rightValue, rightClipping) {

            var fqId = this.createQualifiedId(mixer)

            var registrations = this.registeredMixers[fqId]
            if (registrations) {
                var j;
                for(j = 0; j < registrations.length; j++) {
                    var registration = registrations[j]
                    var horizontal = registration.horizontal;
                    var lightCount = registration.lightCount;

                    if(registration.type == 'best') {
                        // TODO: find 'active' VU ... is it left value, or right value?
                        var $lights = registration.lights;
                        this.updateSingleVU(horizontal, lightCount, $lights, leftValue, leftClipping)
                    }
                    else {
                        if(mixer.stereo) {
                            this.updateSingleVU(horizontal, lightCount, registration.leftLights, leftValue, leftClipping)
                            this.updateSingleVU(horizontal, lightCount, registration.rightLights, rightValue, rightClipping)
                        }
                        else {
                            this.updateSingleVU(horizontal, lightCount, registration.leftLights, leftValue, leftClipping)
                            this.updateSingleVU(horizontal, lightCount, registration.rightLights, leftValue, leftClipping)
                        }
                    }
                }
            }
        },

    };

})(window, jQuery);