function jbox(opts) {
    var _this = this;
	
    // set up our jbox
    this.init = function() {
        this.options = null;
        var defaults = {
            overlayColor: 'black',
            overlayOpacity: .7,
            overlayFade: 300,
            contentfadeIn: 200,
            contentfadeOut: 400,
            overlayContentTop: '150px',
            closeButtonPath: '/themes/che/images/close.png',
            closeButtonPathIE: false,
            closeElementClass: 'closebox'
        };
		
        this.options = jQuery.extend(defaults, opts);
		
        this.overlay = null;
        this.overlayLiner = null;
        this.overlayContentHolder = null;
		
        this.currentContent = false;
		
        this.visible = false;
        this.mouseIn = false;
        this.nextPrevButtons = false;
		
        this.fadeSpeed = 300;
        this.jboxGroups = Array();
		
        if (jQuery('a[rel^=jbox]').length) {
            this.buildOverlay();
            this.addJboxHandler();
            this.addWindowHandler();
        }
    }
	
	
	
    // build overlay
    this.buildOverlay = function() {
        jQuery('body').append(
            jQuery('<div></div>').attr({
                'id': 'Overlay'
            }).css({
                display: 'none',
                position: 'absolute',
                top: '0',
                left: '0',
                'z-index': '24',
                opacity: this.options.overlayOpacity,
                "background-color": this.options.overlayColor,
                padding: '0',
                margin: '0'
            }),
            jQuery('<div></div>').attr({
                'id': 'OverlayLiner'
            }).css({
                display: 'none',
                position: 'absolute',
                top: '0',
                left: '0',
                'z-index': '25',
                width: this.overlayWidth,
                height: this.overlayHeight,
                padding: '0',
                margin: '0'
            }).append(
                jQuery('<div></div>').attr({
                    'id': 'OverlayContentHolder'
                }).css({
                    position: 'relative',
                    'z-index': '50'
                })
                )
            );
        this.overlay = jQuery('#Overlay');
        this.overlayLiner = jQuery('#OverlayLiner');
        this.overlayContentHolder = jQuery('#OverlayContentHolder');
    }
	
	
	
    // display the overlay
    this.showOverlay = function() {
        this.resizeOverlay();
        this.updateModalLocation();
        var that = this;
        if (!this.visible) {
            this.overlay.fadeIn(this.options.overlayFade);
            this.overlayLiner.fadeIn(this.options.overlayFade, function() {
                that.resizeOverlay(); // resize again just incase the gallery popup was bigger than the window size and created scroll bars (overlay would be cut off below the fold)
            });
            this.visible = true;
        }
    }
	
	
	
    // hide the overlay
    this.hideOverlay = function() {
        if (this.visible) {
            this.overlay.fadeOut(this.options.overlayFade);
            this.overlayLiner.fadeOut(this.options.overlayFade);
            this.visible = false;
        }
    }
	
	
	
    // load content into the overlay (ajax request if doesn't exist, just display if already loaded)
    this.loadContent = function(href, group) {
        httpRegExp = /^(http:)/;
        jpgRegExp = /(.jpg)$/;
        gifRegExp  = /(.gif)$/;
        pngRegExp = /(.png)$/;

        // weird ie 6 bug where the whole address comes from the href so we need to substr it away
        if (httpRegExp.test(href)) {
            href = this.fixIE6(href);
        }

        // generate the id to attach to the div that this content will be loaded into
        var loadID = this.generateLoadID(href);

        if (jpgRegExp.test(href) || gifRegExp.test(href) || pngRegExp.test(href)) {
            // load image
            this.loadImage(loadID, href);
        } else {
            // load html
            this.loadHTML(loadID, href);
        }
		
        // check to see if this content is part of a group
        this.checkForGroup(group);
    }
	
	
	
    this.fixIE6 = function(href) {
        pos = href.indexOf("/");
        var count = 0;
        while (count < 3 && pos != -1) {
            count++;
            href = href.substr(pos + 1);
            pos = href.indexOf("/");
        }
        return href;
    }
	
	
	
    this.generateLoadID = function(href) {
        var loadID = href;
		
        pos = loadID.indexOf("/");
		
        while (pos != -1) {
            loadID = loadID.substr(0, pos) + loadID.substr(pos + 1);
            pos = loadID.indexOf("/");
        }
		
        pos = loadID.indexOf('.');
        if (pos != -1) {
            loadID = loadID.substr(0, pos) + loadID.substr(pos + 1);
        }
		
        // handle get variables in the href
        var quesPos = loadID.indexOf("?");
        var eqPos   = -1;
        if (quesPos != -1) {
            loadID = loadID.substr(0, quesPos) + loadID.substr(quesPos + 1);
            eqPos  = loadID.indexOf("=");
            loadID = loadID.substr(0, eqPos) + loadID.substr(eqPos + 1);
            var ampPos = loadID.indexOf("&");
            while (ampPos != -1) {
                loadID = loadID.substr(0, ampPos) + loadID.substr(ampPos + 1);
                eqPos  = loadID.indexOf("=");
                loadID = loadID.substr(0, eqPos) + loadID.substr(eqPos + 1);
                ampPos = loadID.indexOf("&");
            }
        }
		
        return loadID;
    }
	
	
	
    // load an image into overlay
    this.loadImage = function(loadID, href) {
        if (jQuery('#' + loadID).length) {
            if (this.currentContent != loadID) {
                jQuery('#' + this.currentContent).fadeOut(this.options.contentFadeOut);
                this.currentContent = loadID;
                jQuery('#' + this.currentContent).fadeIn(this.options.contentFadeIn);
            }
        } else {
            var img = jQuery('<img/>').load(function() {
                jQuery('#OverlayContentHolder').prepend(
                    // create div with loadID to hold new content
                    jQuery('<div></div>').attr({
                        'id': loadID,
                        className: 'overlayContent imageContent'
                    }).css({
                        display: 'none',
                        position: 'absolute',
                        top: _this.options.overlayContentTop
                    }).append(
                        this,
                        _this.addCloseButton()
                        )
                    );
                if (_this.currentContent) {
                    jQuery('#' + _this.currentContent).fadeOut(_this.options.contentFadeOut);
                }
                _this.currentContent = loadID;
                jQuery('<img/>').load(function() {
                    jQuery('#' + _this.currentContent).fadeIn(_this.options.contentFadeIn);
                }).attr('src', href);
                _this.centreContent();
                _this.addCloseHandler();
            }).attr('src', href);
            if (img[0].complete && jQuery.browser.msie) {
                img.trigger('load');
            }
        }
    }
	
	
	
    this.loadHTML = function(loadID, href) {
        // check to see if content has already been loaded
        if (jQuery('#' + loadID).length) {
            // check to see if this content is already the current content
            if (this.currentContent != loadID) {
                // show loading animation
                jQuery('#loader').css({
                    display: 'block'
                });
                // hide current content
                jQuery('#' + this.currentContent).fadeOut(this.options.contentFadeOut);
                // show new content
                jQuery('#' + loadID).fadeIn(this.options.contentFadeIn);
                // hide loading animation
                jQuery('#loader').css({
                    display: 'none'
                });
                // store new current content id
                this.currentContent = loadID;
            }
            this.centreContent();
            jQuery('#' + loadID).css({
                display: 'block'
            });
        } else {
            // load content using ajax
            jQuery.get(href, function(data) {
                jQuery('#loader').css({
                    display: 'none'
                });
                jQuery('#OverlayContentHolder').prepend(
                    // create div with loadID to hold new content
                    jQuery('<div></div>').attr({
                        'id': loadID,
                        className: 'overlayContent htmlContent'
                    }).css({
                        display: 'none',
                        position: 'absolute',
                        top: _this.options.overlayContentTop
                    }).append(data).fadeIn(_this.options.contentFadeIn)
                    );
                if (_this.currentContent) {
                    jQuery('#' + _this.currentContent).fadeOut(_this.options.contentFadeOut);
                }
                _this.currentContent = loadID;
                _this.centreContent();
                _this.addJboxHandler();
                _this.addCloseHandler();
            });
        }
    }
	
	
	
    this.centreContent = function() {
        var contentWidth = jQuery('#' + this.currentContent).outerWidth();
        var offset = (this.overlayWidth / 2) - (contentWidth / 2);
        jQuery('#' + this.currentContent).css({
            'left': offset
        });
    }
	
	
	
    // check to see if this content is part of a group
    this.checkForGroup = function(group) {
        if (group && _this.jboxGroups[group.group].length > 1) {
            // create buttons when needed
            if (!this.nextPrevButtons) {
            //this.addNextPrevButtons();
            }
			
            // display next/prev buttons and add new click events
            jQuery('#next').css({
                display: 'block'
            });
            jQuery('#prev').css({
                display: 'block'
            });
            // unbind any current click events
            jQuery('#next').unbind('click');
            jQuery('#prev').unbind('click');
            // bind new click events
            jQuery('#next').bind('click', function() {
                var next = group.current+1;
                if (next > _this.jboxGroups[group.group].length-1) {
                    next = 0;
                }
                _this.loadContent(_this.jboxGroups[group.group][next], {
                    group: group.group,
                    current: next
                });
            });
            jQuery('#prev').bind('click', function() {
                var prev = group.current-1;
                if (prev < 0) {
                    prev = _this.jboxGroups[group.group].length-1;
                }
                _this.loadContent(_this.jboxGroups[group.group][prev], {
                    group: group.group,
                    current: prev
                });
            });
        } else {
            // make sure buttons are hidden if they have been created
            if (this.nextPrevButtons) {
                jQuery('#next').css({
                    'display': 'none'
                });
                jQuery('#prev').css({
                    'display': 'none'
                });
            }
        }
    }
	
	
    this.addNextPrevButtons = function() {
        this.nextPrevButtons = true;
        this.overlayContentHolder.append(
            jQuery('<div></div>').attr('id', 'next'),
            jQuery('<div></div>').attr('id', 'prev')
            );
    }
	
	
	
    this.addCloseButton = function() {
        var closeButton = null;
        if (this.options.closeButtonPathIE && jQuery.browser.msie && jQuery.browser.version == "6.0") {
            closeButton = "<img src='" + this.options.closeButtonPathIE + "' />";
        } else {
            closeButton = "<img src='" + this.options.closeButtonPath + "' />";
        }
        return jQuery('<div></div>').addClass(this.options.closeElementClass).css({
            position: 'absolute',
            top: '14px',
            right: '18px',
            cursor: 'pointer',
            'z-index': '100'
        }).append(
            closeButton
            );
    }
	
	
	
    // add click events to all anchor tags with rel = 'jbox'
    this.addJboxHandler = function() {
        jQuery("a[rel^='jbox']").each(function(i) {
            var rel = jQuery(this).attr('rel');
            var href = jQuery(this).attr('href');
            var position = href.indexOf("/");
	
            // check for groups (if length of rel is > 4 it means we have 'jbox[...]' which means it is in a group
            if (rel.length > 4) {
                // get the group name (the string between the [ ])
                rel = rel.substr(5, (rel.length-6));
                // create a new entry in the group array if it isn't already there
                if (!_this.jboxGroups[rel]) {
                    _this.jboxGroups[rel] = Array();
                }
                if (jQuery.inArray(href, _this.jboxGroups[rel]) == -1) {
                    // add this link to the group
                    _this.jboxGroups[rel].push(href);
                }
                // store group and current info for loadContent() call
                rel = {
                    group: rel,
                    current: jQuery.inArray(href, _this.jboxGroups[rel])
                };
                                
            } else {
                // not part of a group so set rel to false
                rel = false;
            }
            // add click event
            jQuery(this).unbind("click");
            jQuery(this).bind("click", function(event) {
                event.preventDefault();
                event.stopPropagation();
                _this.showOverlay();
                _this.loadContent(href, rel);
            });

            /*jQuery(this).unbind("mouseup");
            jQuery(this).bind("mouseup", function(event) {
                event.preventDefault();
            });

            jQuery(this).unbind("click");
            jQuery(this).bind("click", function(event) {
                event.preventDefault();
            });*/
        });
    }
	
	
	
    // add events to handle closing the overlay
    this.addCloseHandler = function() {
        this.overlayContentHolder.unbind('mouseenter');
        this.overlayContentHolder.unbind('mouseleave');
        this.overlayContentHolder.bind('mouseenter', function() {
            _this.mouseIn = true;
        }).bind('mouseleave', function() {
            _this.mouseIn = false;
        });
        jQuery('.' + this.options.closeElementClass).unbind('click');
        jQuery('.' + this.options.closeElementClass).bind('click', function(event) {
            event.preventDefault();
            _this.hideOverlay();
        });
        this.overlayLiner.unbind('click');
        this.overlayLiner.bind('click', function() {
            if (!_this.mouseIn) {
                _this.hideOverlay();
            }
        });
    }
	
	
	
    // add a resize event to the window so the overlay stays the right size
    this.addWindowHandler = function() {
        jQuery(window).unbind('resize');
        jQuery(window).bind('resize', function() {
            _this.resizeOverlay(true);
        });
    }
	
	
	
    // keep the modal window in the viewport
    this.updateModalLocation = function() {
        this.overlayContentHolder.css({
            top: jQuery(window).scrollTop() + 'px'
        });
    }
	
	
	
    // get the current width and height of the window/document and apply this to the overlay and liner
    this.resizeOverlay = function(windowChange) {
        var newWidth = this.getViewWidth(windowChange);
        var newHeight = this.getViewHeight();
	
        // check that the new height and width is different to the current
        if (this.overlayWidth != newWidth || this.overlayHeight != newHeight) {
            // set the new heights and widths
			
            // take into account the scrollbar in IE 6
            if (jQuery.browser.msie && jQuery.browser.version == "6.0") {
                newWidth = newWidth - 21;
            }
			
            this.overlay.css({
                width: newWidth,
                height: newHeight
            });
            this.overlayLiner.css({
                width: newWidth,
                height: newHeight
            });
			
            // store the new height and widths
            this.overlayWidth = newWidth;
            this.overlayHeight = newHeight;
			
            this.centreContent();
        }
    }
	
	
	
    // get width of the view
    this.getViewWidth = function(windowChange) {
        if (windowChange) {
            return jQuery(window).width();
        }
        return jQuery(document).width();
    }
	
	
	
    // get height of the view
    this.getViewHeight = function() {
        return jQuery(document).height();
    }
	
	
	
    this.init();
}

var box = null;

jQuery(document).ready(function() {
    box = new jbox();
});