/* jSelect (using jQuery library).
*--------------------------------------------*
*  @author : ukhome ( ukhome@gmail.com | ntkhoa_friends@yahoo.com )
*--------------------------------------------*
*  @released : 24-Mar-2009 : version 1.0
*--------------------------------------------*
*  @revision history : ( latest version : 1.0 )
*--------------------------------------------*
*      + 24-Mar-2009 : version 1.0
*          - released
*      + 03-Sep-2009 : version 1.1
*          - positioning issues fixed (esp. FF3), remove globalWrapper
*--------------------------------------------*
*/

/* package Main
*/
function escapeHTML(str) {
    var div = document.createElement('div');
    var text = document.createTextNode(str);
    div.appendChild(text);
    return div.innerHTML;
};
jQuery.fn.extend({
    addSelectUI: function() {
        //droplist Manager
        $droplist_Manager = function() {
            var o = this;
            o.els = new Array(); // element type = jquery object
            o.activeName = null; // index of active droplist
        }

        //droplist class
        $droplist_UI = function(jEl, options) { //jEl = jquery element
            var o = this; //self reference

            /* methods */

            this.setupDropListUI = function() {
                /*Create UL reflect <select>*/
                var offset = 0;
                o.select.find("> *").each(function(index) {
                    var el = jQuery(this);
                    var count = index;

                    if (this.tagName.toLowerCase() == "optgroup") {
                        //detected <optgroup>
                        el.each(function() {
                            var optgroup = jQuery(this);

                            var optName = optgroup.attr("label");
                            var optgroup_el = jQuery("<li></li>");
                            optgroup_el.prepend("<span class=\"OptgroupLabel\">" + optName + "</span>");
                            var optgroup_elsubUL = jQuery("<ul></ul>");
                            o.elUL.append(optgroup_el);
                            optgroup_el.append(optgroup_elsubUL);

                            optgroup.find("option").each(function(index) {
                                var self = jQuery(this);
                                if (self.attr("value") == "") {
                                    optgroup_elsubUL.append("<li class=\"SelectUITitle\" value=\"" + parseInt(count + index + offset + 1) + "\"><a href=\"#\" title=\"" + self.text() + "\" rel=\"" + self.attr("label") + "\">" + self.text() + "</a></li>");
                                }
                                else if (self.attr("selected")) {
                                    optgroup_elsubUL.append("<li class=\"Active\" value=\"" + parseInt(count + index + offset + 1) + "\"><a href=\"#\" title=\"" + self.text() + "\" rel=\"" + self.attr("label") + "\">" + self.text() + "</a></li>");
                                }
                                else {
                                    optgroup_elsubUL.append("<li value=\"" + parseInt(count + index + offset + 1) + "\"><a href=\"#\" title=\"" + self.text() + "\" rel=\"" + self.attr("label") + "\">" + self.text() + "</a></li>");
                                }
                            });
                            offset += optgroup.find("option").length - 1;
                        });
                    }
                    else {
                        //detected <option>
                        if (el.attr("value") == "") {
                            o.elUL.append("<li class=\"SelectUITitle\" value=\"" + parseInt(index + offset + 1) + "\"><a href=\"#\" title=\"" + el.text() + "\" rel=\"" + el.attr("label") + "\">" + el.text() + "</a></li>");
                        }
                        else if (el.attr("selected")) {
                            o.elUL.append("<li class=\"Active\" value=\"" + parseInt(index + offset + 1) + "\"><a href=\"#\" title=\"" + el.text() + "\" rel=\"" + el.attr("label") + "\">" + el.text() + "</a></li>");
                        }
                        else {
                            o.elUL.append("<li value=\"" + parseInt(index + offset + 1) + "\"><a href=\"#\" title=\"" + el.text() + "\" rel=\"" + el.attr("label") + "\">" + el.text() + "</a></li>");
                        }
                    }
                });

                //append to DOM
                o.el = jQuery("<div class=\"DropListUIContainer\"></div>");

                o.elUL.before(o.el);
                o.el.html(o.elUL);
                /*end. Create UL reflect <select>*/

                /*Wrapper*/
                o.elWrapper = jQuery("<div class=\"DropListUI\"></div>");
                o.el.before(o.elWrapper);

                var elClasses = o.elUL.attr("class").split(" ");
                var addDefaultTheme = true;
                for (var i = 0; i < elClasses.length; i++) {
                    if (elClasses[i].match(/^Theme/)) {
                        o.elWrapper.addClass(elClasses[i]);
                        addDefaultTheme = false;
                    }
                }

                if (addDefaultTheme) {
                    o.elWrapper.addClass("Theme_Default");
                    o.elUL.addClass("Theme_Default");
                }
                o.elWrapper.html(o.el);
                /*end. Wrapper*/

                if (!o.select.attr("multiple")) {
                    //max droplist height
                    o.maxDropListHeight = options != undefined && options.maxDropListHeight != undefined ? parseInt(options.maxDropListHeight) : 300;
                    o.config = {
                        maxDropListHeight: o.maxDropListHeight
                    }

                    /*Title*/
                    var title = "";
                    var hasValue = false;
                    o.select.find("option").each(function() {
                        var option = jQuery(this);

                        if (option.attr("selected")) {
                            title = option.text();
                            hasValue = true;
                        }
                    });

                    if (!hasValue) {
                        title = o.select.attr("title") != "" ? o.select.attr("title") : o.select.find("option:first-child").text();
                    }
                    /*end. Title*/

                    /*Disabled option*/
                    if (!o.select.attr("disabled")) {
                        o.droplistTITLE = jQuery("<p title=\"" + title + "\">" + "<span>" + title + "</span>" + "</p>");
                    }
                    else {

                        o.droplistTITLE = jQuery("<p title=\"" + title + "\">" + "<span>" + title + "</span>" + "</p>");
                        o.elWrapper.addClass("Disabled");
                    }
                    o.el.before(o.droplistTITLE);
                    /*end. Disabled option*/

                    o.el.css({
                        position: "absolute",
                        left: 0,
                        display: "none",
                        overflow: "hidden",
                        width: o.elUL.width()
                    });

                    /*Binding events*/
                    o.el.find("ul > li").each(function(index) {
                        var self = jQuery(this);

                        self.bind("click", function() {
                            if (self.find("span.OptgroupLabel:first-child").length > 0) {
                                //o.el.hideList();
                                return false;
                            }
                            else {
                                if (!o.select.attr("disabled")) {
                                    //o.droplistTITLE.text( self.text() );
                                    o.el.find("ul > li").removeClass("Active");
                                    self.addClass("Active");
                                    var textValue = self.text();
                                    textValue = escapeHTML(textValue);

                                    o.droplistTITLE.html("<span>" + textValue + "</span>");
                                    o.droplistTITLE.attr("title", self.text());
                                    o.hideList();
                                    o.select.val(o.select.find("option").eq(self.attr("value") - 1).val());
                                    /*call Externall Function*/
                                    callExternalFunction(o, droplistManager.els, self.find("a:first").attr("rel"));
                                    self.removeClass("Hover");
                                    return false;
                                }
                            }
                        });
                    });

                    o.droplistTITLE.bind("click", function(evt) {
                        o.eventFire = true;

                        if (!o.select.attr("disabled")) {
                            if (o.el.hasClass("DropListUIShow")) {
                                o.hideList();
                            }
                            else { //showlist
                                if (droplistManager.activeName != null) {
                                    droplistManager.els[droplistManager.activeName].hideList();
                                }
                                o.showList();
                                droplistManager.activeName = o.select.attr("id");
                            }
                        }
                        return false; //prevent default action and stop bubble
                    });

                    jQuery(document).bind("click", function(evt) {
                        if (droplistManager.activeName != null) {
                            droplistManager.els[droplistManager.activeName].hideList();
                        }
                        evt.stopPropagation();
                        //return false;
                    });
                    jQuery(document).bind("mouseover", function(evt) {
                        if (droplistManager.activeName != null) {
                            droplistManager.els[droplistManager.activeName].hideList();
                        }
                    });
                    o.elWrapper.bind("mouseover", function(evt) {
                        evt.stopPropagation();
                    });
                    o.el.bind("click", function(evt) {
                        return false; //prevent default action and stop bubble
                    });

                    /*end. Binding events*/
                }
                else { //multi choices enabled
                    var size = o.select.attr("size");
                    o.elUL.css({
                        height: o.elUL.find("li").eq(0).outerHeight(true) * size,
                        overflow: "hidden"
                    });

                    if (!o.elUL.parent().hasClass("jScrollPaneContainer")) {
                        o.elUL.jScrollPane({
                            scrollbarWidth: o.options.scrollbarWidth,
                            scrollbarOnLeft: o.options.scrollbarSide == "left" ? true : false
                        });
                    }

                    /*Binding events*/
                    var keyChar = null;
                    var beginVal_INDEX = null;
                    var endVal_INDEX = null;

                    /*shortcut function*/
                    function clearValues() {
                        o.select.find("option").removeAttr("selected");
                        o.elUL.find("li").removeClass("Active");
                    }
                    /*END. shortcut function*/

                    o.el.find("ul > li").each(function(index) {
                        var self = jQuery(this);

                        self.bind("click", function(e) {
                            if (self.find("span.OptgroupLabel:first-child").length > 0) {
                                //o.el.hideList();
                                return false;
                            }
                            else {
                                if (!o.select.attr("disabled")) {
                                    if (e.ctrlKey && !e.shiftKey) { //only CTRL
                                        /*pre-proccess for SHIFT key case*/
                                        beginVal_INDEX = index;
                                        /*END. pre-proccess for SHIFT key case*/
                                        o.select.find("option").eq(index).attr("selected", "selected");
                                    }
                                    else if ((!e.ctrlKey && e.shiftKey) || (e.ctrlKey && e.shiftKey)) { //only SHIFT or CTRL+SHIFT: SHIFT take the higher priority
                                        if (!e.ctrlKey) { //if NOT hold CTRL --> clear values
                                            clearValues();
                                        }
                                        if (beginVal_INDEX == null) {
                                            beginVal_INDEX = index;
                                        }
                                        else {
                                            endVal_INDEX = index;
                                            if (beginVal_INDEX != null && endVal_INDEX != null) {
                                                o.el.find("ul > li").each(function(index) {
                                                    var self = jQuery(this);
                                                    if ((beginVal_INDEX <= endVal_INDEX && index >= beginVal_INDEX && index <= endVal_INDEX) || (beginVal_INDEX >= endVal_INDEX && index <= beginVal_INDEX && index >= endVal_INDEX)) {
                                                        o.select.find("option").eq(index).attr("selected", "selected");
                                                        self.addClass("Active");
                                                    }
                                                });
                                                endVal_INDEX = null;
                                            }
                                        }
                                    }
                                    else { //no key pressed
                                        clearValues();
                                        o.select.find("option").eq(index).attr("selected", "selected");
                                        /*pre-proccess for SHIFT key case*/
                                        beginVal_INDEX = index;
                                        /*END. pre-proccess for SHIFT key case*/
                                    }
                                    self.addClass("Active");
                                    //o.select.val(o.select.find("option").eq(self.attr("value")-1).val());
                                    /*call Externall Function*/
                                    //callExternalFunction(o, droplistManager.els, self.find("a:first").attr("rel"));
                                    self.removeClass("Hover");
                                    return false;
                                }
                            }
                        });
                    });
                }

                /* Little trick for IE6 Hover Problem */
                o.el.find("ul > li").each(function(index) {
                    var self = jQuery(this);

                    self.bind("mouseover", function() {
                        self.addClass("Hover");
                        return false;
                    });

                    self.bind("mouseout", function() {
                        self.removeClass("Hover");
                        return false;
                    });
                });
                /* end. Little trick for IE6 Hover Problem */
            }

            this.reset = function() {
                //refresh
                o.elUL.empty();
                o.elUL.removeAttr("class");
                //re-create
                o.elUL.attr("title", o.select.attr("title"));
                o.elUL.addClass(o.select.attr("class"));

                this.setupDropListUI();

                /*Re-Create UL reflect <select>*/
            }

            this.showList = function() {
                o.elWrapper.addClass("TopLevel");
                o.el.addClass("DropListUIShow");

                o.reservedHolder = o.elWrapper.clone(true).empty();
                o.reservedHolder.css({
                    visibility: "hidden",
                    height: o.elWrapper.outerHeight()
                });
                o.elWrapper.hide();
                o.elWrapper.before(o.reservedHolder);

                var borderLeftWidth = 0;
                var borderTopWidth = 0;
                var offset = {
                    left: 0,
                    top: 0
                };

                o.elWrapper.appendTo("body"); //must append to body before calculate position

                //var isFF3 = (/Firefox\/3.*/).test(window.navigator.userAgent);
                //!!! if FF3, substract the border-left/top width of all parent wrapper: bugs in offset()

                /*if (isFF3) {
                var parentWrapper = o.reservedHolder.parent();
                borderLeftWidth = 0;
                borderTopWidth = 0;
                while (parentWrapper.attr("tagName").toLowerCase() != "body") { //find all borders of parents
                if ( (/relative|absolute|fixed/).test( parentWrapper.css("position") ) ) {
                borderLeftWidth += parseInt(parentWrapper.css("borderLeftWidth"));
                borderTopWidth += parseInt(parentWrapper.css("borderTopWidth"));
                }
                parentWrapper = parentWrapper.parent();
                }
					
					var el = o.reservedHolder.get(0);
                do {
                offset.top += el.offsetTop;
                offset.left += el.offsetLeft;
                }
                while ( el = el.offsetParent ) ; //trick
                }
                else {*/
                offset.top = o.reservedHolder.offset().top;
                offset.left = o.reservedHolder.offset().left;
                //}

                o.elWrapper.css({
                    position: "absolute",
                    top: offset.top + borderTopWidth,
                    left: offset.left + borderLeftWidth,
                    margin: 0
                });
                o.elWrapper.show();
                o.el.show();
                //o.setDirection();

                //apply jScrollPane for scrolling
                if (o.el.height() > o.maxDropListHeight) {
                    o.elUL.height(o.maxDropListHeight);

                    if (!o.elUL.parent().hasClass("jScrollPaneContainer")) {
                        o.elUL.jScrollPane({
                            scrollbarWidth: o.options.scrollbarWidth,
                            scrollbarOnLeft: o.options.scrollbarSide == "left" ? true : false
                        });
                    }
                }

                o.eventFire = false;
            }

            this.hideList = function() {
                //remove jScrollPane
                o.el.prepend(o.elUL);
                o.elUL.removeAttr("style");
                o.elUL.next().remove();
                //end. remove jScrollPane

                o.elWrapper.removeClass("TopLevel");
                o.el.removeClass("DropListUIShow");
                o.select.after(o.elWrapper.removeAttr("style"));
                o.el.hide();
                o.reservedHolder.remove();
            }

            this.setDirection = function() {
                var windowHeight = jQuery(window).height();
                var elPostion_Top = o.elWrapper.offset().top - jQuery(window).scrollTop();
                var elPostion_Bottom = o.elWrapper.offset().top + o.elWrapper.height() - jQuery(window).scrollTop();
                var elULHeight = o.elUL.outerHeight();
                var direction = "";

                /*  
                * When o.maxDropListHeight change in case 
                * it's height is greater than top space and bottom space,
                * it need to be reset to its config value for new calculation
                */
                if (o.config.maxDropListHeight > o.maxDropListHeight) {
                    o.maxDropListHeight = o.config.maxDropListHeight;
                }
                if (elULHeight <= windowHeight - elPostion_Bottom) { //no need scroll
                    //decide to go down
                    direction = "down";
                }
                else if (windowHeight - elPostion_Bottom > o.maxDropListHeight) { //need scroll
                    //go down take higher priority if available
                    direction = "down";
                }
                else if (elULHeight < elPostion_Top) { //no need scroll
                    //decide to go up
                    direction = "up";
                }
                else if (elPostion_Top > o.maxDropListHeight) { //need scroll
                    //go up take priority when down is unavailable (< maxDropListHeight)
                    direction = "up";
                }
                else if (windowHeight - elPostion_Bottom >= elPostion_Top) { //need scroll
                    //no case available but go down better than go up
                    direction = "down";
                    o.maxDropListHeight = windowHeight - elPostion_Bottom;
                }
                else { //need scroll
                    //no case available but go up better than go down
                    direction = "up";
                    o.maxDropListHeight = elPostion_Top;
                }
                var borderTop = (/[0-9]+/).test(o.el.css("borderTopWidth"))
                                        ? parseInt(o.el.css("borderTopWidth"))
                                        : 0;
                var borderBottom = (/[0-9]+/).test(o.el.css("borderBottomWidth"))
                                        ? parseInt(o.el.css("borderBottomWidth"))
                                        : 0;

                o.maxDropListHeight -= (borderTop + borderBottom);
                /* Act on direction decision */
                if (direction == "up") { //go up
                    o.el.css({
                        bottom: o.elWrapper.height() + "px",
                        top: "auto"
                    });
                }
                else { // go down, direction == "down"
                    o.el.css({
                        top: "100%",
                        bottom: "auto"
                    });
                }
            }

            /* end. methods */

            /* constructor */

            o.options = {
                scrollbarWidth: options != undefined && options.scrollbarWidth != undefined ? parseInt(options.scrollbarWidth) : 10,
                scrollbarSide: options != undefined && options.scrollbarSide != undefined ? options.scrollbarSide : "right"
            }

            /*<select>*/
            o.select = jEl;
            o.select.addClass("HasSelectUI");
            o.select.css({
                opacity: 0,
                position: "absolute",
                left: "-1000em",
                top: "-1000em"
            });
            o.reservedHolder = null;
            o.elUL = jQuery("<ul title=\"" + o.select.attr("title") + "\"></ul>");
            o.elUL.addClass(o.select.attr("class"));
            o.select.after(o.elUL);

            this.setupDropListUI();
            /*end. <select>*/

            /* END. constructor */
        }

        //setup
        if (window.droplistManager == undefined) {
            window.droplistManager = new $droplist_Manager();
        }

        if (window.droplistManager != undefined) {
            jQuery(window).bind("resize", function(evt) {
                if (droplistManager.activeName != null && window.droplistManager.els[droplistManager.activeName] != undefined && !droplistManager.els[droplistManager.activeName].eventFire) {
                    window.droplistManager.els[droplistManager.activeName].hideList();
                }
            });
            jQuery(window).bind("scroll", function(evt) {
                if (droplistManager.activeName != null && window.droplistManager.els[droplistManager.activeName] != undefined && !droplistManager.els[droplistManager.activeName].eventFire) {
                    window.droplistManager.els[droplistManager.activeName].hideList();
                    evt.stopPropagation();
                }
            });
        }

        var options = arguments[0];
        this.each(function() {
            if (!jQuery(this).hasClass("HasSelectUI")) {
                jQuery(this).addClass("HasSelectUI")
                droplistManager.els[jQuery(this).attr("id")] = new $droplist_UI(jQuery(this), options);
            }
        });

    }
});