/**
* jQuery CustomDropDown plugin
*
* It first reads all the <option> elements and selected <option> element as well.
* Next, it creates DL and DT with selected item inside it. After DL is being created,
* the code iterates through <option> collection and create UL with list items inside it. 
*/
(function ($) {
    $.fn.customDropDown = function ($selectOptions) {

        var defaults = { dropdownClass: "" };
        var settings = $.extend({}, defaults, $selectOptions);
        var dropdownClass = "dropdown";

        this.each(function () {
            var $select = $(this);
            var $selectOptions = $("option", $select);
            var $selected = $select.find("option:selected");
            var dropdownId = $select.attr("id") + "_cdd";

            //Hide the original dropdown
            $select.hide();

            //Create the container and add the selected option
            $select.after('<dl id="' + dropdownId + '" class="' + dropdownClass + " " + settings.dropdownClass + '"></dl>');
            $("#" + dropdownId).append('<dt><a href="#" value="' + $selected.val() + '">' + $selected.text() + '</a></dt>');
            $("#" + dropdownId).append('<dd><ul></ul></dd>');

            //Create the list with all the options and add a class to the selected item
            $selectOptions.each(function () {
                if ($(this).val() == $selected.val()) {
                    $("#" + dropdownId + " dd ul").append('<li><a href="#" tabindex="-1" class="selected" value="' + $(this).val() + '">' + $(this).text() + '</a></li>');
                }
                else {
                    $("#" + dropdownId + " dd ul").append('<li><a href="#" tabindex="-1" value="' + $(this).val() + '">' + $(this).text() + '</a></li>');
                }
            });

            var $dropdown = $("#" + dropdownId);
            var $dropdownSelected = $dropdown.find("dt");
            var $dropdownSelectedLink = $dropdown.find("dt a");
            var $dropdownList = $dropdown.find("dd");
            var $dropdownListLinks = $dropdown.find("dd ul li a");
            var $dropdownListSelectedLink = $dropdown.find("dd ul li a.selected");

            var selectedListIndex = 0;
            var maxListIndex = $selectOptions.length - 1;

            //When the selected option is clicked
            $dropdownSelected.click(function (e) {
                ToggleVisibility();
                $dropdownSelectedLink.trigger('focus');
                e.preventDefault();
            });

            //When a new option is selected in the list
            $dropdownListLinks.click(function (e) {
                $select.val($(this).attr("value")); //Set the value of the original dropdown
                $select.trigger('change'); //Trigger a change to update the dropdown
                $dropdownSelectedLink.trigger('focus');
                e.preventDefault();
            });

            //When a link in the list is hovered 
            $dropdownListLinks.hover(function (e) {
                $dropdownListSelectedLink.removeClass("selected");
            });

            //When the dropdown gets focus
            $dropdownSelectedLink.focus(function (e) {
                $dropdown.addClass("focus");
            });

            //When the dropdown loses focus
            $dropdownSelectedLink.blur(function (e) {
                $dropdown.removeClass("focus");
            });

            //When a key is pressed down while dropdown has focus
            $dropdownSelectedLink.keydown(function (e) {
                var isOpen = $dropdownList.is(":visible");

                //13 = enter
                if (e.keyCode == 13) {
                    if (isOpen) { SetSelectedIndex(selectedListIndex); } //If dropdown is open, change the selected index
                    else { ToggleVisibility(); } //If dropdown is not open, open it
                    e.preventDefault();
                }
                //27 = esc
                else if (e.keyCode == 27) {
                    if (isOpen) { ToggleVisibility(); } //If the custom dropdown is open, close it
                    e.preventDefault();
                }
                else if (e.keyCode == 38 || e.keyCode == 40) {
                    //38 = keyup
                    if (e.keyCode == 38) {
                        if (selectedListIndex > 0) { selectedListIndex--; }
                    }
                    //40 = keydown
                    else if (e.keyCode == 40) {
                        if (selectedListIndex < maxListIndex) { selectedListIndex++; }
                    }

                    //If dropdown is open, show the new index as selected but don't select it
                    if (isOpen) {
                        $dropdownListLinks.removeClass("selected");
                        $dropdownListLinks.eq(selectedListIndex).addClass("selected");
                    }
                    //If dropdown is not open, change the selected index
                    else {
                        SetSelectedIndex(selectedListIndex);
                    }

                    e.preventDefault();
                }
            });

            //When the original dropdown value changes
            $($select).change(function (e) {
                SetSelectedItem(true, true, true);
            });

            //Show or hide dropdown
            function ToggleVisibility() {
                //Hide all other open dropdowns
                $(".dropdown dd").not($dropdownList).hide();

                $dropdownSelected.toggleClass("expanded");
                $dropdownList.toggle();

                if ($dropdownList.is(":visible")) {
                    //Reset the selected item
                    selectedListIndex = $select.attr("selectedIndex");
                    SetSelectedItem(false, true, false);
                }
            }

            //Set the selected item in the dropdown
            function SetSelectedItem(setSelectedLink, setSelectedListLink, hideList) {
                $dropdownListSelectedLink = $dropdownListLinks.filter(function () { return $(this).attr("value") == $select.val(); });

                if (setSelectedLink) {
                    $dropdownSelectedLink.html($dropdownListSelectedLink.html());
                    $dropdownSelectedLink.attr("value", $dropdownListSelectedLink.attr("value"));
                }
                if (setSelectedListLink) {
                    $dropdownListLinks.removeClass("selected");
                    $dropdownListSelectedLink.addClass("selected");
                }
                if (hideList) {
                    $dropdownSelected.removeClass("expanded");
                    $dropdownList.hide();
                }
            }

            //Set the selected index in the original dropdown
            function SetSelectedIndex(index) {
                $selectOptions.eq(index).attr('selected', 'selected');
                $select.trigger('change');
            }

            //Cause the dropdown to close when user clicks outside the dropdown
            $(document).click(function (e) {
                if (!$(e.target).parents().hasClass(dropdownClass)) {
                    $dropdownSelected.removeClass("expanded");
                    $dropdownList.hide();
                }
            });
        });

        //Returns the jQuery object to allow for chainability
        return this;
    }
})(jQuery);
