(function($){
    function CopyLink(options) {
        this.id = options.id || 'copyLink';
        this.minLength = options.minLength || 20;
        this.$container = options.container || $('body');
        this.handler = options.handler || function() {
            return '<br/>' + options.text + ': ' + location.href;
        };
    }
    
    CopyLink.prototype = {
        init: function() {
            var self = this;
            
            $(this.$container).bind('copy', function(){
                self.copy();
            });
        },
        copy: function() {
            this.el = $(
                '<span id="' + this.id +
                '" style="position:absolute; left:-9999px">' +
                this.handler() + '</span>'
                ).get(0);
            
            if (document.selection) {
                this.doIe();
            } else if (window.getSelection) {
                this.selection = getSelection();
                
                if(this.selection.toString().length >= this.minLength) {
                    this.originalRange = this.selection.getRangeAt(0);
                    this.range = document.createRange();

                    if ($.browser.mozilla) {
                        this.doMozilla();
                    } else {
                        this.doWebKit();
                    }

                    this.remove();
                }
            }
        },
        doIe: function() {
            var self = this;
            
            range = document.selection.createRange();
            
            if (range.text.length < this.minLength) {
                return;
            }
            
            newRange = range.duplicate();
            newRange.setEndPoint('StartToEnd', range);
            newRange.pasteHTML(this.el.outerHTML);
            range.setEndPoint('EndToEnd', newRange);
            range.select();
			
            setTimeout(function() {
                $('#' + self.id).remove();
            }, 0);
        },
        doMozilla: function() {
            $('body').append(this.el);
            this.range.selectNode(this.el);
            this.selection.addRange(this.range);
        },
        doWebKit: function() {
            anchorNode = this.selection.anchorNode;
            focusNode = this.selection.focusNode;
            anchorOffset = this.selection.anchorOffset;
            focusOffset = this.selection.focusOffset;
            startNode = 1 == anchorNode.nodeType ?
            anchorNode.childNodes[anchorOffset] : anchorNode
            ;
            endNode = 1 == focusNode.nodeType ?
            focusNode.childNodes[focusOffset] : focusNode
            ;

            if (
                anchorNode == focusNode &&
                anchorOffset > focusOffset ||
                2 == startNode.compareDocumentPosition(endNode)
                ) {
                anchorNode = focusNode;
                focusNode = this.selection.anchorNode;
                anchorOffset = focusOffset;
                focusOffset = this.selection.anchorOffset;
            }
            
            this.range.setStart(focusNode, focusOffset);
            this.range.insertNode(this.el);
            this.range.setStart(anchorNode, anchorOffset);
            this.range.setEndAfter(this.el);
            this.selection.removeAllRanges();
            this.selection.addRange(this.range);
        },
        remove: function() {
            var self = this;

            setTimeout(function() {
                $(self.el).remove();

                if ($.browser.mozilla) {
                    self.selection.removeRange(self.range);
                } else {
                    self.selection.removeAllRanges();
                    self.selection.addRange(self.originalRange);
                }
            }, 0);
        }
    };

    $.copyLink = function(options) {
        var link = new CopyLink(options);

        link.init();
    };
})(jQuery);
