var TOGGLE_SUFFIX = 'Img';

function makeFixed(element, leftOffsetBase) {
    var scrollOffsetField = $('scrollOffset');

    element = $(element);
    var base = element.cumulativeOffset()[1];

    element.absolutize();

    var updateTimer = 0;

    var adjust = function() {
        if (updateTimer) {
            clearTimeout(updateTimer);
        }

        var windowOffsetTop = document.viewport.getScrollOffsets()[1];
        scrollOffsetField.value = windowOffsetTop;

        // 476 is the difference in pixels between the top of the simBottomY paragraph and the top of the simulatorLeft ad
        // If the ad creeps below this point, stop it right there.
        var simBottomY = $('simBottomY');
        var furthestY = simBottomY.cumulativeOffset()[1] - 594;

        if (windowOffsetTop < base) {
            windowOffsetTop = base;
        }
        else if (windowOffsetTop > furthestY) {
            windowOffsetTop = furthestY;
        }

        updateTimer = setTimeout(function() { new Effect.Move(element, { x: element.cumulativeOffset()[0], y: windowOffsetTop, mode: 'absolute' }) }, 300);
    };

    var resize = function() {
        element.style.left = ($(leftOffsetBase).cumulativeOffset()[0] + 593) + "px";
    }

    Event.observe(window, 'scroll', adjust);
    Event.observe(window, 'resize', resize);
}

function scrollToLastPosition() {
    var scrollPos = $('scrollOffset').value;

    if (scrollPos > 0) {
        window.scroll(0, scrollPos);
    }
}

var registeredModifiers = new Array();
var registeredModifierAdvice = {};

function registerModifier(modifierId, defaultExpanded) {
    registeredModifiers.push(modifierId);
    $(modifierId + TOGGLE_SUFFIX).onclick = function() { changeModifierState(modifierId, !defaultExpanded); return false; };
}

function changeModifierState(modifierId, expanding) {
    var expandedDiv = $(modifierId + "Expanded");
    var collapsedDiv = $(modifierId + "Collapsed");

    if (expanding) {
        swapVisibleModifier(expandedDiv, collapsedDiv);
        //var toggleSign = 'layout/simulator/minus.png';
        var toggleSign =  MEDIA_URL + '/res/img/layout/simulator/minus.png';

        if (SimulatorSlider.sliders[modifierId]) {
            var slider = SimulatorSlider.sliders[modifierId];
            slider.dispose();
            slider.activate();
        }
    }
    else {
        swapVisibleModifier(collapsedDiv, expandedDiv);
       //var toggleSign = 'layout/simulator/plus.png';
        var toggleSign =  MEDIA_URL + '/res/img/layout/simulator/plus.png';
    }

    var toggle = $(modifierId + TOGGLE_SUFFIX);
    toggle.onclick = function() { changeModifierState(modifierId, !expanding); return false; };
    toggle.src = toggleSign;
}

function swapVisibleModifier(makeVisible, makeInvisible) {
    makeVisible.removeClassName('hidden');
    makeInvisible.addClassName('hidden');
}

function toggleAllModifiers(expanding) {
    registeredModifiers.each(function(modifierId) {
        changeModifierState(modifierId, expanding);
    });
}

function resetAllModifiers() {
    var resetConfirmImg = $('resetConfirmImg');
    resetConfirmImg.style.display = 'inline';
    new Effect.Fade(resetConfirmImg);

    var radioAndCheckboxFn = function(inputElement) { inputElement.checked = false; };
    var textFn = function(inputElement) { inputElement.value = ''; };
    var extraAction = function(inputElement, modifierId) {
        toggleAdvice(modifierId, registeredModifierAdvice[modifierId], inputElement, true, true);
    };

    actOnAllInputFields(radioAndCheckboxFn, textFn, extraAction);

    resetAllSliders();

    Effect.ScrollTo('subNav');
}

function resetAllSliders() {
    for (modifierId in SimulatorSlider.sliders) {
        var slider = SimulatorSlider.sliders[modifierId];

        slider.hiddenInput.value = slider.resetValue;
        slider.dispose();
        slider.activate();

        toggleAdvice(modifierId, "neutral", slider.hiddenInput, true, true);
    }
}

function realignSliders() {
    for (modifierId in SimulatorSlider.sliders) {
        var slider = SimulatorSlider.sliders[modifierId];
        slider.dispose();
        slider.activate();
    }
}

// Performs radioAndCheckboxFn on all radios and checkboxes; textFn on all text fields. Only for registered modifier fields.
function actOnAllInputFields(radioAndCheckboxFn, textFn, extraAction) {

    registeredModifiers.each(
        function(modifierId) {
            var expanded = $(modifierId + "Expanded");

            expanded.select('input').each(
                function(inputElement) {
                    var type = inputElement.getAttribute("type");

                    if (type == "radio" || type == "checkbox") {
                        radioAndCheckboxFn(inputElement, modifierId);
                    }
                    else if (type == "text") {
                        textFn(inputElement, modifierId);
                    }

                    if (extraAction) {
                        extraAction(inputElement, modifierId);
                    }
                }
            );
        }
    );
}

// Generates an onchange event handler, to be used to trigger advice.
function getAdviceTrigger(eventToBind, checkDeselectedFn) {
    return function(inputElement, modifierId) {
        Event.observe(inputElement, eventToBind, function(e) {
            toggleAdvice(modifierId, registeredModifierAdvice[modifierId], this, checkDeselectedFn(this));
        });
    };
}

// Binds all of the onchange event handlers to all of the modifier input fields. They only activate if the field is "on"
function setupAdviceTriggers() {
    var radioAndCheckboxFn = getAdviceTrigger('click', function(inputElement) { return (inputElement.checked != true); });
    var textFn = getAdviceTrigger('keyup', function(inputElement) { return (inputElement.value.length < 1); })
    actOnAllInputFields(radioAndCheckboxFn, textFn);
}

/** This function makes advice appear/disappear when the user enters in a value or toggles an option.
 * This shows good, bad, and neutral advice.
 * 
 * @param modifierId string prefix used everywhere for this modifier
 * @param toggledItem
 * @param deactivate
 * @param forceDeactivate
 * @param firstOrSecond
 * @return
 */
function toggleAdvice(modifierId, goodBadOrNeutral, toggledItem, deactivate, forceDeactivate, firstOrSecond) {
    if (deactivate && (toggledItem.getAttribute("type") == "radio") && !forceDeactivate) {
        return;
    }

    var expanded = $(modifierId + 'Expanded');

    // If this is a set of checkboxes, then don't deactivate the advice for the whole set if there are other checkboxes still checked
    if (deactivate && (toggledItem.getAttribute("type") == "checkbox") && !forceDeactivate) {
        if (expanded.select('input[type=checkbox]').pluck('checked').any()) {
            return;
        }
    }

    if (deactivate) {
        var display = 'none';
    }
    else {
        var display = 'block';
    }

    var impact = $(modifierId + 'Impact');
    impact.style.display = display;
    
    var paraSelector = 'p.simDesc2';

    // For sliders; kills all paragraphs before we redisplay them
    if (firstOrSecond) {
        changeDisplays(expanded, paraSelector, 'none');
        paraSelector += firstOrSecond;
    }

    changeDisplays(expanded, paraSelector, display);
}

function changeDisplays(baseElement, selector, display) {
    baseElement.select(selector).each(
        function(inputElement) {
            inputElement.style.display = display;
        }
    );
}

function SimulatorSlider(modifierId, displayValues, resetValue, firstAdvice, secondAdvice, spanTwo) {
    this.modifierId = modifierId;
    this.valueElement = $(modifierId + 'Value');
    this.hiddenInput = $(modifierId);
    this.displayValues = displayValues;
    this.spanTwo = spanTwo;
    this.firstHandle = this.modifierId + 'Handle';
    this.firstAdvice = firstAdvice;
    this.secondAdvice = secondAdvice;
    this.resetValue = resetValue;

    var thisObj = this;
    SimulatorSlider.sliders[modifierId] = this;

    this.options = {
        values: SimulatorSlider.values,
        onSlide: function(selectedVals) { thisObj.updateValues(selectedVals); },
        startSpan: modifierId + 'Span'
    };

    if (typeof(IE6) != 'undefined') {
        if (!spanTwo) {
            this.options.alignX = -3;
        }
        else {
            this.options.alignX = -11;
        }
    }

    this.activate();
}
// Update the hidden input field for this slider and the displayed value as well.
// updateValue is this slider's position, generated by Scriptaculous.
SimulatorSlider.prototype.updateValues = function(updateValue) {
	
	// Translate the Scriptaculous value, like "0.11", to an index, like "1"
    var value = SimulatorSlider.values.indexOf(updateValue);
    
    // Grab the display value for the index and display it
    this.valueElement.update(this.displayValues[value]);

    if (this.spanTwo && value == 0) {
        value = 9;
    }

    // This is what is submitted to Credit Karma's backend via AJAX
    this.hiddenInput.value = value;

    // Check that this value is the value that will make the advice disappear ("resetValue")
    if (value == this.resetValue) {
        toggleAdvice(this.modifierId, "neutral", this.hiddenInput, true, true);
    }
    // If not, update the advice accordingly
    else {
        var adviceSelector = '.sliderAdvice';
        if (this.secondAdvice && value >= this.secondAdvice[1]) {
            adviceSelector += 'Second';
            toggleAdvice(this.modifierId, this.secondAdvice[0], this.hiddenInput, false, false, adviceSelector);
        }
        else if (value >= this.firstAdvice[1]) {
            adviceSelector += 'First';
            toggleAdvice(this.modifierId, this.firstAdvice[0], this.hiddenInput, false, false, adviceSelector);
        }
    }
};
// Kill a slider that's been hidden
SimulatorSlider.prototype.dispose = function() {
    this.slider.dispose();
};
// Reactivate a slider after it's been hidden or on initialization
SimulatorSlider.prototype.activate = function() {
    var sliderIndex = this.hiddenInput.value;

    if (sliderIndex == 9) {
        sliderIndex = 0;
    }

    this.valueElement.update(this.displayValues[sliderIndex]);
    this.options.sliderValue = SimulatorSlider.values[sliderIndex];

    this.slider = new Control.Slider(this.firstHandle, this.modifierId + 'Track', this.options);
}
SimulatorSlider.values = [0, 0.11, 0.24, 0.37, 0.497, 0.625, 0.758, 0.888, 1];
SimulatorSlider.sliders = {};