/* 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
*--------------------------------------------*
*/

/* package Main
*/

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;
            //init
            o.options = {
                scrollbarWidth: options != undefined && options.scrollbarWidth != undefined ? parseInt(options.scrollbarWidth) : 10,
                scrollbarSide: options != undefined && options.scrollbarSide != undefined ? options.scrollbarSide : "right"
            }
            //max droplist height
            o.maxDropListHeight = options != undefined && options.maxDropListHeight != undefined ? parseInt(options.maxDropListHeight) : 300;
            o.config = {
                maxDropListHeight: o.maxDropListHeight
            }

            /*prepare a global wrapper*/
            if ( jQuery("div#selectUIGlobalWrapper").length == 0 ) {
                o.globalWrapper = jQuery("<div id=\"selectUIGlobalWrapper\"></div>");
                try {
                    o.globalWrapper.css({
                        width: jQuery("#mainOuter").outerWidth(),
                        height: jQuery("#mainOuter").outerHeight(),
                        position: "absolute",
                        top: jQuery("#mainOuter").offset().top,
                        left: jQuery("#mainOuter").offset().left,
                        zIndex: -1
                    });
                }
                catch (err) {
                }

                jQuery("body").append(o.globalWrapper);
            }
            else {
                o.globalWrapper = jQuery("div#selectUIGlobalWrapper");
            }


            /*<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);
            /*end. <select>*/

            /*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 {
                                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 select
                    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 {
                        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*/

            /*Title*/
            /*
            var title = o.elUL.children("li:first-child").text();

            o.select.find("option").each(function () {
                var option = jQuery(this);

                if ( option.attr("value") == o.select.val() ) {
                    title = option.text();
                }
            });
            */
            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 + "</p>");
           }
            else {
                o.droplistTITLE = jQuery("<p></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");
                            o.droplistTITLE.text( 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;
                        }
                    }
                });
                
                /* Little trick for IE6 Hover Problem */
                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 */
            });

            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;
            });

            o.el.bind("click", function (evt) {
                return false; //prevent default action and stop bubble
            });

            /*end. Binding events*/

            /* methods */
            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"));

                /*Re-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 {
                                    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 select
                        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 {
                            o.elUL.append("<li value=\"" + parseInt(index + offset+1) + "\"><a href=\"#\" title=\"" + el.text() + "\" rel=\"" + el.attr("label") + "\">" + el.text() +"</a></li>");
                        }
                    }
                });
                /*end. Create UL reflect <select>*/

                /*Title*/
                /*
                var title = o.elUL.children("li:first-child").text();

                o.select.find("option").each(function () {
                    var option = jQuery(this);

                    if ( option.attr("value") == o.select.val() ) {
                        title = option.text();
                    }
                });
                */
                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") != undefined ? o.select.attr("title") : o.select.find("option:first-child").text();
                }
                /*end. Title*/

                /*Disabled option*/
                if ( !o.select.attr("disabled") ) {
                    o.droplistTITLE.text(title);
                }
                else {
                    o.droplistTITLE.text("");
                    o.elWrapper.addClass("Disabled");
                }
                o.el.before(o.droplistTITLE);
                /*end. Disabled option*/

                /*Re-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.hideList();
                            return false;
                        }
                        else {
                            if ( !o.select.attr("disabled") ) {
                                //o.droplistTITLE.text( self.text() );
                                o.el.find("ul > li").removeClass("Active");
                                self.addClass("Active");
                                o.droplistTITLE.text( 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;
                            }
                        }
                    });

                    self.bind("mouseover", function () {
                        self.addClass("Hover");
                        return false;
                    });

                    self.bind("mouseout", function () {
                        self.removeClass("Hover");
                        return false;
                    });
                });
                /*end. Re-Binding events*/
            }

            this.showList = function () {
                o.elWrapper.addClass("TopLevel");
                o.globalWrapper.addClass("TopLevel");
                o.el.addClass("DropListUIShow");

                var reservedTop = parseInt(o.elWrapper.offset().top);
                var reservedLeft = parseInt(o.elWrapper.offset().left) - o.globalWrapper.offset().left;

                o.reservedHolder = o.elWrapper.clone(true).empty();
                o.reservedHolder.css({
                    visibility: "hidden"
                });

                o.elWrapper.before(o.reservedHolder);

                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();
                    var borderLeftWidth = 0;
                    var borderTopWidth = 0;
                    while ( parentWrapper.attr("tagName").toLowerCase() != "body" ) {
                        borderLeftWidth += parseInt(parentWrapper.css("borderLeftWidth"));
                        borderTopWidth += parseInt(parentWrapper.css("borderTopWidth"));
                        parentWrapper = parentWrapper.parent();
                    }

                    reservedTop -= borderTopWidth;
                    reservedLeft -= borderLeftWidth;
                }

                o.elWrapper.appendTo(o.globalWrapper);
                o.elWrapper.css({
                    position: "absolute",
                    top: reservedTop,
                    left: reservedLeft,
                    margin: 0
                });
                o.el.show();
                o.setDirection();

                //apply jScrollPane for scrolling
                if (o.el.height() > o.maxDropListHeight) {
                   o.elUL.height(o.maxDropListHeight);

                   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.globalWrapper.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() + jQuery(document).scrollTop();
                var elPostion_Top = o.elWrapper.offset().top;
                var elPostion_Bottom = o.elWrapper.offset().top + o.elWrapper.height();
                var elULHeight = o.elUL.outerHeight();
                var direction = "";

                /*  
                * When o.maxDropListHeight change due to case 
                * it 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 - jQuery(document).scrollTop() ) { //no need scroll
                    //decide to go down
                    direction = "down";
                }
                else if ( elULHeight < elPostion_Top - jQuery(document).scrollTop() ) {
                    //decide to go up
                    direction = "up";
                }
                else if ( windowHeight - elPostion_Bottom > o.maxDropListHeight ) {//need scroll
                    //go down take higher priority if available
                    direction = "down";
                }
                else if ( elPostion_Top - jQuery(document).scrollTop() > o.maxDropListHeight ) {
                    //go up take priority when down is unavailable (< maxDropListHeight)
                    direction = "up";
                }
                else if ( windowHeight - elPostion_Bottom >= elPostion_Top - jQuery(document).scrollTop() ) { //need scroll
                    //no case available but go down better than go up
                    direction = "down";
                    o.maxDropListHeight = windowHeight - elPostion_Bottom;
                }
                else {
                    //no case available but go up better than go down
                    direction = "up";
                    o.maxDropListHeight = elPostion_Top - jQuery(document).scrollTop();
                }
                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 */
        }

        //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) ;
            }
        });
        
    }
});
