jQuery.fn.halvrEditor || (function(){

    jQuery.fn.halvrEditor = function(options) {
        var opts = jQuery.extend({}, jQuery.fn.halvrEditor.defaults, options);
        return this.each(function(index, editor){
            var $editor = jQuery(editor);

            var $iframe = jQuery('<iframe border="0" frameborder="0" ></iframe>',editor.document);
            var id = editor.id;
            if (id) {
                $iframe.attr('id', id + "IFrame");
            }

            $iframe.width($editor.width());
            $iframe.height($editor.height());

            $iframe.bind('halvrChange', null, function(){
                syncTextArea($iframe, $editor);
            });
            
            $editor.hide();
            $editor.before($iframe);

            enableDesignMode($iframe, $editor);
            attachButtonHandlers(opts.toolbar, opts.dialogs, $iframe, $editor);
        });

        function attachExbandHandler($iframe) {
            $iframe.contents().click( function(e) {
                if($iframe.get(0).contentWindow.getSelection) {
                    if (e.target.tagName.toLowerCase() === 'widget') {
                        var sel = $iframe.get(0).contentWindow.getSelection();
                        var range = jQuery.halvr.getSelectionRange($iframe.get(0).contentWindow);
                        range.selectNode(e.target);
                        sel.addRange(range);
                    }
                } 
            });
        }

        function attachDoubleClickHandler($iframe) {
            jQuery($iframe.get(0).contentDocument).dblclick( function(e) {
                switch (e.target.tagName.toLowerCase()) {
                    case 'widget':
                        var widget = jQuery(e.target);
                        var halvrType = widget.attr('_halvrtype');
                        
                        var dialog = jQuery('#' + halvrType + 'Dialog');
                        dialog.data('element',e.target);
                        
                        var inputElements = jQuery('#' + halvrType + 'Dialog :input:not([type=submit]):not([type=reset])');

                        inputElements.each(function(index,item) {
                            var value = widget.attr(item.name);
                            item.value = value;
                        });

                        jQuery('#' + halvrType + 'Button').mousedown();
                        break;
                    case 'img':
                        halvrType = 'image';
                        if($iframe.get(0).document && $iframe.get(0).document.selection) {
                        	var range = $iframe.get(0).document.selection.createRange();
                        	range.moveToElementText(e.target);
                        	range.select();
                        }
                        jQuery('#' + halvrType + 'Button').mousedown();
                        break;
                    case 'a':
                        halvrType = 'link';
                        var dialog = jQuery('#' + halvrType + 'Dialog');
                        dialog.data('element',e.target);
                        
                        jQuery('#' + halvrType + 'Button').mousedown();
                        break;
                    default:
                }
            });
        }

        function attachButtonHandlers(toolbarId, dialogId, $iframe, $editor) {
            var toolbarButtons;
            if (toolbarId){
                toolbarButtons = jQuery('#'+toolbarId + '> .toolbarButton, #'+toolbarId + '> .toolbarButtonText');
            } else {
                toolbarButtons = jQuery('.toolbarButton, .toolbarButtonText');
            }

            // WORKAROUND: IE - Wanted to use click event, but for some reason IE doesn't trigger click handlers on DIVs
            toolbarButtons.mousedown(function(e) {
                $iframe.get(0).focus();
                var originalRange = jQuery.halvr.getSelectionRange($iframe.get(0).contentWindow);
                var thisButton = jQuery(this);

                var command = thisButton.attr("data-command");
                if (command.indexOf('halvrCmd_') !== 0 && command.indexOf('jQueryUIDialog_') !== 0) {
                    var value = thisButton.attr("data-type");
                    if (command === 'heading' && !jQuery.browser.mozilla ) {
                        command = 'formatblock';
                    }  
                    if (command === 'formatblock' && jQuery.browser.msie) {
                        value = '<' + value + '>';
                    }
                    
                    jQuery.halvr.editorCommand($iframe.get(0), command, value);
                    syncTextArea($iframe, $editor);
                } else if (command.indexOf('jQueryUIDialog_') === 0) {
                	var dialogId = command.substr(15);
                	var dialog = jQuery('#' + dialogId + 'Dialog');
                	
                	var dialogSelection = {
                        	range : originalRange,
                        	iframe : $iframe.get(0)
                    };
                        
                    dialog.data('editorSelection',dialogSelection);
                	
                    dialog.dialog('open');
                }

                e.stopPropagation();
                e.preventDefault();
                return false;
            });
        }
        
        function enableDesignMode(iframe, editor) {
            var iframeWindow = iframe.get(0).contentWindow;

            // WORKAROUND: FF - Due to a bug in FF we must do this processing delayed, because iframes take awhile to initialize in FF
            var timeout = 1;
            if (jQuery.browser.mozilla){
                timeout = 20;
            }
            setTimeout(
                function() {
                    var content = editor.val();
                    if (content.indexOf('[BASE64]') === 0) {
                        content = content.substr(8);
                        content = jQuery.halvr.base64Decode(content);
                    }
                    content = jQuery.trim(content);
                    if (content === '') {
                        content = '<br>';
                    }

                    /* WORKAROUND: IE - IE doesn't create a body property until something has been written into the
                     * document and WebKit removes the default body property if you write something into the document 
                     * that doesn't contain a body element */
                    if (!iframeWindow.document.body) {
                        iframeWindow.document.write('Loading...');
                    }

                    iframe.contents().find('head').html('<style>a {color:blue;text-decoration:underline;}' +
                    		' table {border-bottom:1px dotted #000000;border-right:1px dotted #000000;border-collapse:collapse;border-spacing:0px;}' +
                    		' td,th {border-left:1px dotted #000000;border-top:1px dotted #000000;min-width:100px;}' +
                    		' td:hover,th:hover {background-color:#dbdbdb;}' +
                    		'</style><base href="' + window.location + '">');
                    
                    var contentBody = iframe.contents().find('body');

                    contentBody.html(content);
                    contentBody.attr('contentEditable','true');
                    try {
                    	contentBody.execCommand('styleWithCSS',false);
                    } catch (e) {}
                    
                    iframe.contents().keyup(function() {
                        syncTextArea(iframe,editor);
                    });
                    attachExbandHandler(iframe);
                    attachDoubleClickHandler(iframe);
                    
                    syncTextArea(iframe,editor,true);
                }, timeout);
            
            function focusEditor(e) {
                var contentBody = iframe.contents().find('body');
                editor.siblings('#toolbar').fadeIn();
                contentBody.blur(blurEditor);
                contentBody.unbind('focus', focusEditor);
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
            function blurEditor(e) {
                var contentBody = iframe.contents().find('body');
                contentBody.focus(focusEditor);
                contentBody.unbind('blur', blurEditor);
                editor.siblings('#toolbar').fadeOut();
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
        }
        
    };

    function syncTextArea(iframe, editor, disableElementRemoval) {
    	var body = iframe.contents().find('body');
        var html = body.html();
        if (disableElementRemoval) {
        	html = html.replace(new RegExp('<\?.*\/>'),'');
        }
        editor.val(html);
        editor.trigger('change.halvr.editor');
    }

    jQuery.fn.halvrEditor.defaults = {
        toolbar: undefined, // the id of the element containing all toolbar buttons, if not defined we search whole doc
        dialogs: undefined //the id of the element containing all the dialogs, if not defined we search whole doc
    };
})();
