/**
* Functions related to faders (slider controls for volume).
* These functions are intimately tied to the markup defined in
* the templates in _faders.html.erb
*/
(function(g, $) {

    "use strict";

    g.JK = g.JK || {};

    var $draggingFaderHandle = null;
    var $draggingFader = null;

    var subscribers = {};
    var logger = g.JK.logger;
    var MAX_VISUAL_FADER = 95;

    function faderClick(evt) {
        evt.stopPropagation();
        if (g.JK.$draggingFaderHandle) {
            return;
        }
        var $fader = $(evt.currentTarget);
        var faderId = $fader.closest('[fader-id]').attr("fader-id");
        var $handle = $fader.find('div[control="fader-handle"]');

        var faderPct = faderValue($fader, evt);

        // Notify subscribers of value change
        g._.each(subscribers, function(changeFunc, index, list) {
            if (faderId === index) {
                changeFunc(faderId, faderPct, false);
            }
        });

        setHandlePosition($fader, faderPct);
        return false;
    }

    function setHandlePosition($fader, value) {
        if (value > MAX_VISUAL_FADER) { value = MAX_VISUAL_FADER; } // Visual limit
        var $handle = $fader.find('div[control="fader-handle"]');
        var handleCssAttribute = getHandleCssAttribute($fader);
        $handle.css(handleCssAttribute, value + '%');
    }


    function faderHandleDown(evt) {
        evt.stopPropagation();
        $draggingFaderHandle = $(evt.currentTarget);
        $draggingFader = $draggingFaderHandle.closest('div[control="fader"]');
        return false;
    }

    function faderMouseUp(evt) {
        evt.stopPropagation();
        if ($draggingFaderHandle) {
            var $fader = $draggingFaderHandle.closest('div[control="fader"]');
            var faderId = $fader.closest('[fader-id]').attr("fader-id");
            var faderPct = faderValue($fader, evt);
            // Notify subscribers of value change
            g._.each(subscribers, function(changeFunc, index, list) {
                if (faderId === index) {
                    changeFunc(faderId, faderPct, false);
                }
            });
            $draggingFaderHandle = null;
            $draggingFader = null;
        }
        return false;
    }

    function faderValue($fader, evt) {
        var orientation = $fader.attr('orientation');
        var getPercentFunction = getVerticalFaderPercent;
        var absolutePosition = evt.clientY;
        if (orientation && orientation == 'horizontal') {
            getPercentFunction = getHorizontalFaderPercent;
            absolutePosition = evt.clientX;
        }
        return getPercentFunction(absolutePosition, $fader);
    }

    function getHandleCssAttribute($fader) {
        var orientation = $fader.attr('orientation');
        return (orientation === 'horizontal') ? 'left' : 'bottom';
    }

    function faderMouseMove(evt) {
        // bail out early if there's no in-process drag
        if (!($draggingFaderHandle)) {
            return false;
        }
        var $fader = $draggingFader;
        var faderId = $fader.closest('[fader-id]').attr("fader-id"); var $handle = $draggingFaderHandle;
        evt.stopPropagation();
        var faderPct = faderValue($fader, evt);

        // Notify subscribers of value change
        g._.each(subscribers, function(changeFunc, index, list) {
            if (faderId === index) {
                changeFunc(faderId, faderPct, true);
            }
        });

        if (faderPct > MAX_VISUAL_FADER) { faderPct = MAX_VISUAL_FADER; } // Visual limit
        var handleCssAttribute = getHandleCssAttribute($fader);
        $handle.css(handleCssAttribute, faderPct + '%');
        return false;
    }

    function getVerticalFaderPercent(eventY, $fader) {
        return getFaderPercent(eventY, $fader, 'vertical');
    }

    function getHorizontalFaderPercent(eventX, $fader) {
        return getFaderPercent(eventX, $fader, 'horizontal');
    }

    /**
    * Returns the current value of the fader as int percent 0-100
    */
    function getFaderPercent(value, $fader, orientation) {
        var faderPosition = $fader.offset();
        var faderMin = faderPosition.top;
        var faderSize = $fader.height();
        var handleValue = (faderSize - (value-faderMin));
        if (orientation === "horizontal") {
            faderMin = faderPosition.left;
            faderSize = $fader.width();
            handleValue = (value - faderMin);
        }
        var faderPct = Math.round(handleValue/faderSize * 100);
        if (faderPct < 0) {
            faderPct = 0;
        }
        if (faderPct > 100) {
            faderPct = 100;
        }
        return faderPct;
    }

    g.JK.FaderHelpers = {

        /**
        * Subscribe to fader change events. Provide a subscriber id
        * and a function in the form: change(faderId, newValue) which
        * will be called anytime a fader changes value.
        */
        subscribe: function(subscriberId, changeFunction) {
            subscribers[subscriberId] = changeFunction;
        },

        /**
        * Render a fader into the element identifed by the provided
        * selector, with the provided options.
        */
        renderFader: function(selector, userOptions) {
            if (userOptions === undefined) {
                throw ("renderFader: userOptions is required");
            }
            if (!(userOptions.hasOwnProperty("faderId"))) {
                throw ("renderFader: userOptions.faderId is required");
            }
            var renderDefaults = {
                faderType: "vertical",
                height: 83,  // only used for vertical
                width: 83    // only used for horizontal
            };
            var options = $.extend({}, renderDefaults, userOptions);
            var templateSelector = (options.faderType === 'horizontal') ?
                "#template-fader-h" : '#template-fader-v';
            var templateSource = $(templateSelector).html();

            $(selector).html(g._.template(templateSource, options));
            // Embed any custom styles, applied to the .fader below selector
            if ("style" in options) {
                for (var key in options.style) {
                    $(selector + ' .fader').css(key, options.style[key]);
                }
            }
        },

        convertLinearToDb: function(input) {
             var temp;
             temp = 0.0;
             // coefficients
             var a = -8.0013990435159329E+01;
             var b = 4.1755639785242042E+00;
             var c = -1.4036729740086906E-01;
             var d = 3.1788545454166156E-03;
             var f = -3.5148685730880861E-05;
             var g = 1.4221429222004657E-07;
             temp += a +
                b * input +
                c * Math.pow(input, 2.0) +
                d * Math.pow(input, 3.0) +
                f * Math.pow(input, 4.0) +
                g * Math.pow(input, 5.0);

             return temp;
        },

        setFaderValue: function(faderId, faderValue) {
            var $fader = $('[fader-id="' + faderId + '"]');
            this.setHandlePosition($fader, faderValue);
        },

        setHandlePosition: function($fader, faderValue) {
            setHandlePosition($fader, faderValue);
        },

        initialize: function() {
            $('body').on('click', 'div[control="fader"]', faderClick);
            $('body').on('mousedown', 'div[control="fader-handle"]', faderHandleDown);
            $('body').on('mousemove', 'div[layout-id="session"], [layout-wizard="ftue"]', faderMouseMove);
            $('body').on('mouseup', 'div[layout-id="session"], [layout-wizard="ftue"]', faderMouseUp);
            //$('body').on('mousemove', faderMouseMove);
            //$('body').on('mouseup', faderMouseUp);
        }

    };


})(window, jQuery);