
;(function ($) {
    var popup, idIndex = 0, zIndex = 9999, agent = navigator.userAgent.toLowerCase();
    
    popup = {
        isIphone: agent.indexOf('iphone') != -1,
        isIE6: (/msie 6/i.test(agent)) && typeof window['XMLHttpRequest'] != 'object', // browser sniffing is bad!
        
        doc: $('document'),
        win: $('window'),
        body: $('body'),
        
        countPosition : function ($selector, o, onscroll) {
            var hideAfter = false;
            if ($selector.css('display') == 'none') {
                if (onscroll) {
                    return null;
                }
                $selector.css({
                    'position': 'absolute',
                    'top': '-5000px',
                    'left' : '-5000px',
                    'display': ''
                });
                hideAfter = true;
            }
            if (onscroll && (($selector.outerHeight() + 40) >= popup.win.height())) {
                popup.win.unbind('scroll.popup-' + o.uid, o.onScroll);
            }
            var x, y;
            x = Math.round((popup.win.width() - $selector.outerWidth(true)) / 2) + popup.win.scrollLeft();
            if (x < 20) {
                x = 20;
            }
            y = Math.round((popup.win.height() - $selector.outerHeight(true)) / 2);
            if (y < 20) {
                y = 20;
            }
            y += popup.win.scrollTop();
            if (hideAfter) {
                $selector.css('display', 'none');
            }
            return [x, y];
        },
        
        setPosition : function ($selector, o) {
            p = popup.countPosition($selector, o, false);
            return $selector.css({ 
                'left': p[0], 
                'position': 'absolute', 
                'top': p[1], 
                'z-index': o.popupZ 
            });
        },
        
        handleScroll : function ($selector, o) {
            try {
            p = popup.countPosition($selector, o, true);
            if (p !== null) {
                $selector.animate({
                    'left': p[0],
                    'top': p[1]
                }, 'fast');
            }
            } catch (e) {
                window.console.error(e);
            }
        },
        
        distanceToLeft : function () {
            var ww, bw;
            ww = popup.win.width();
            bw = popup.body.width();
            return (ww < bw) ? 0 : Math.round((bw - ww) / 2);
        },
        
        setModalStyles : function ($modal, o) {
            var dd, css = {
                'background-color': '#000', 
                'opacity' : 0.3,
                'top': 0, 
                'left' : 0,
                'z-index': o.modalZ
            };
            if (popup.isIE6 || popup.isIphone) {
                $.extend(css, { 
                    'height': popup.doc.height(), 
                    'left': popup.distanceToLefT(), 
                    'position': 'absolute', 
                    'width': popup.doc.width()
                });
            } else {
                $.extend(css, { 
                    'height': '100%', 
                    'position': 'fixed', 
                    'width': '100%'
                });
            }
            return $modal.css(css);
        },
        
        create : function ($selector, o) {
            $.isFunction(o.onOpen) && o.onOpen.call($selector);
            popup.setModalStyles(o.modal, o);
            popup.body.append(o.modal);
            o.modal.show();
            $selector.css('display', 'none').appendTo(popup.body);
            popup.setPosition($selector, o);
            $selector.fadeIn('slow', function() {
                if (o.modalClose) {
                    o.modal.click(o.modalCloseFn);
                }
                if (o.escClose) {
                    popup.doc.bind('keydown.popup-' + o.uid, o.escCloseFn);
                }
                popup.win.bind('scroll.popup-' + o.uid, o.onScroll);
                popup.handleScroll($selector, o);
                $.isFunction(o.onOpened) && o.onOpened.call($selector);
            });
        },
        
        close : function ($selector, o) {
            $.isFunction(o.onBeforeClose) && o.onBeforeClose.call($selector);
            $selector.fadeOut(o.fadeSpeed, function () {
                o.modal.unbind('click', o.modalCloseFn);
                popup.doc.unbind('keydown.popup-' + o.uid, o.escCloseFn);
                popup.win.unbind('scroll.popup-' + o.uid, o.onScroll);
                o.modal.remove();
                $.isFunction(o.onClose) && o.onClose.call($selector);
            });
        }
    };
    
    $.fn.popup = function (options) {
        var $selector = $(this), old, o = {
            onOpen : function () {},
            onOpened : function () {},
            onClose : function () {},
            modalClose : true,
            escClose : false,
            fadeSpeed : 300
        };
        $.extend(o, options);
        
        old = $selector.data('popup');
        if (old && old.modal) {
            o.uid = old.uid;
            o.modal = old.modal;
            o.modalCloseFn = old.modalCloseFn;
            o.escCloseFn = old.escCloseFn;
            o.onScroll = old.onScroll;
        } else {
            o.uid    = ++idIndex;
            o.modal  = $('<div></div>');
            o.modalCloseFn = function () {
                $selector.popupClose();
            };
            o.onScroll = function (e) {
                popup.handleScroll($selector, o);
            };
            o.escCloseFn = function (e) {
                if (e.which == 27) {
                    e.stopPropagation();
                    e.preventDefault();
                    $selector.popupClose();
                }
            };
        }
        o.modalZ = zIndex++;
        o.popupZ = zIndex++;
        $selector.data('popup', o);
        popup.create($selector, o);
    };
    $.fn.popupUpdate = function () {
        var $selector, o;
        $selector = $(this);
        o = $selector.data('popup');
        if (o) {
            popup.setPosition($selector, o);
        }
    };
    $.fn.popupClose = function () {
        var $selector, o;
        $selector = $(this);
        o = $selector.data('popup');
        if (o) {
            popup.close($selector, o);
        }
    };
    $(document).ready(function () {
        $.extend(popup, {
            doc: $(document),
            win: $(window),
            body: $('body')
        });
    });
}(jQuery));

